|
1 |
| -import { NextFunction, Request, Response, Router } from 'express' |
| 1 | +import { Router } from 'express' |
| 2 | +import rateLimit from 'express-rate-limit' |
2 | 3 | import multer from 'multer'
|
| 4 | +import { parseResponseResult } from '../common/parseResponseResult' |
3 | 5 | import { MulterRequest, TokenController } from '../controllers/token'
|
4 | 6 | import middlewares from '../middlewares'
|
| 7 | +import { ITokenClaimPayload } from '../types' |
5 | 8 |
|
6 | 9 | const router = Router()
|
7 | 10 | const upload = multer({ dest: 'uploads/' })
|
8 | 11 |
|
| 12 | +// Custom store for rate limiting based on email |
| 13 | +class EmailStore { |
| 14 | + private store: any |
| 15 | + |
| 16 | + constructor() { |
| 17 | + this.store = new Map() |
| 18 | + } |
| 19 | + |
| 20 | + incr(key: string, cb: any): void { |
| 21 | + const now = Date.now() |
| 22 | + const record = this.store.get(key) || { count: 0, resetTime: now + 60000 } |
| 23 | + |
| 24 | + if (now > record.resetTime) { |
| 25 | + record.count = 1 |
| 26 | + record.resetTime = now + 60000 |
| 27 | + } else { |
| 28 | + record.count++ |
| 29 | + } |
| 30 | + |
| 31 | + this.store.set(key, record) |
| 32 | + cb(null, record.count) |
| 33 | + } |
| 34 | + |
| 35 | + decrement(key: string): void { |
| 36 | + const record = this.store.get(key) |
| 37 | + if (record) { |
| 38 | + record.count = Math.max(0, record.count - 1) |
| 39 | + } |
| 40 | + } |
| 41 | + |
| 42 | + resetKey(key: string): void { |
| 43 | + this.store.delete(key) |
| 44 | + } |
| 45 | + |
| 46 | + resetAll(): void { |
| 47 | + this.store.clear() |
| 48 | + } |
| 49 | +} |
| 50 | + |
| 51 | +const emailStore = new EmailStore() |
| 52 | + |
| 53 | +const claimLimiter = rateLimit({ |
| 54 | + windowMs: 1 * 60 * 1000, // 1 minute |
| 55 | + max: 10, // Limit each email to 20 requests per windowMs |
| 56 | + handler: (req: any, res: any) => { |
| 57 | + const email = req.body.email || 'Unknown' |
| 58 | + console.log(`[RATE-LIMIT] User ${email} hit the rate limit`) |
| 59 | + const result = parseResponseResult('error', 'Too many attempts, please try again later.', 429) |
| 60 | + res.status(result.statusCode).json(result) |
| 61 | + }, |
| 62 | + standardHeaders: true, |
| 63 | + legacyHeaders: false, |
| 64 | + keyGenerator: (req: any) => { |
| 65 | + const body = req.body as ITokenClaimPayload |
| 66 | + return body.email || req.ip // Fallback to IP if email is not provided |
| 67 | + }, |
| 68 | + store: emailStore as any |
| 69 | +}) |
| 70 | + |
9 | 71 | router.post(
|
10 | 72 | '/claim',
|
11 | 73 | middlewares.authentication,
|
| 74 | + claimLimiter, |
12 | 75 | async (request, response, next) => {
|
13 | 76 | try {
|
14 | 77 | const controller = new TokenController()
|
@@ -120,16 +183,30 @@ router.post(
|
120 | 183 | }
|
121 | 184 | )
|
122 | 185 |
|
| 186 | +// router.post( |
| 187 | +// '/partner', |
| 188 | +// [middlewares.setHasPartnerAuth, middlewares.authentication], |
| 189 | +// async (_request: Request, response: Response, next: NextFunction) => { |
| 190 | +// try { |
| 191 | +// const controller = new TokenController() |
| 192 | +// const requestResult = await controller.createByPartner() |
| 193 | +// return response |
| 194 | +// .status(requestResult.statusCode || 200) |
| 195 | +// .send(requestResult) |
| 196 | +// } catch (error) { |
| 197 | +// next(error) |
| 198 | +// } |
| 199 | +// } |
| 200 | +// ) |
| 201 | + |
123 | 202 | router.post(
|
124 |
| - '/partner', |
125 |
| - [middlewares.setHasPartnerAuth, middlewares.authentication], |
126 |
| - async (_request: Request, response: Response, next: NextFunction) => { |
| 203 | + '/revert-user-claims', |
| 204 | + middlewares.authentication, |
| 205 | + async (request, response, next) => { |
127 | 206 | try {
|
128 | 207 | const controller = new TokenController()
|
129 |
| - const requestResult = await controller.createByPartner() |
130 |
| - return response |
131 |
| - .status(requestResult.statusCode || 200) |
132 |
| - .send(requestResult) |
| 208 | + const result = await controller.revertUserClaims(request.body) |
| 209 | + return response.status(result.statusCode || 200).send(result) |
133 | 210 | } catch (error) {
|
134 | 211 | next(error)
|
135 | 212 | }
|
|
0 commit comments