mielk-api 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/http/httpResponseStatus/HttpResponseStatus.d.ts +3 -0
- package/dist/http/httpResponseStatus/HttpResponseStatus.js +3 -0
- package/dist/internal/messaging/messageTags.d.ts +3 -0
- package/dist/internal/messaging/messageTags.js +3 -0
- package/dist/middlewares/index.d.ts +6 -0
- package/dist/middlewares/index.js +4 -0
- package/dist/middlewares/redisLocks/redisLocker.d.ts +7 -0
- package/dist/middlewares/redisLocks/redisLocker.js +46 -0
- package/dist/middlewares/redisLocks/redisLockerConfigFactory.d.ts +4 -0
- package/dist/middlewares/redisLocks/redisLockerConfigFactory.js +17 -0
- package/dist/middlewares/redisLocks/types.d.ts +14 -0
- package/dist/middlewares/redisLocks/types.js +1 -0
- package/dist/rateLimit/checkRateLimit.js +8 -1
- package/dist/rateLimit/createRateLimiter.d.ts +2 -2
- package/dist/rateLimit/createRateLimiter.js +13 -3
- package/dist/rateLimit/index.d.ts +2 -1
- package/dist/rateLimit/rateLimitConfigFactory.d.ts +5 -5
- package/dist/rateLimit/rateLimitConfigFactory.js +13 -12
- package/dist/rateLimit/redisKeysFactory.d.ts +1 -0
- package/dist/rateLimit/redisKeysFactory.js +4 -3
- package/dist/rateLimit/types.d.ts +16 -1
- package/dist/routing/express.d.ts +2 -2
- package/dist/routing/express.js +2 -0
- package/package.json +1 -1
|
@@ -2,11 +2,14 @@ import { HttpStatus } from "../types/HttpStatus.js";
|
|
|
2
2
|
export declare const HttpResponseStatus: {
|
|
3
3
|
OK: HttpStatus;
|
|
4
4
|
CREATED: HttpStatus;
|
|
5
|
+
ACCEPTED: HttpStatus;
|
|
6
|
+
NO_CONTENT: HttpStatus;
|
|
5
7
|
BAD_REQUEST: HttpStatus;
|
|
6
8
|
UNAUTHORIZED: HttpStatus;
|
|
7
9
|
FORBIDDEN: HttpStatus;
|
|
8
10
|
NOT_FOUND: HttpStatus;
|
|
9
11
|
CONFLICT: HttpStatus;
|
|
12
|
+
LOCKED: HttpStatus;
|
|
10
13
|
TOO_MANY_REQUESTS: HttpStatus;
|
|
11
14
|
SERVER_ERROR: HttpStatus;
|
|
12
15
|
};
|
|
@@ -4,11 +4,14 @@ const msg = Msg.apiStatus;
|
|
|
4
4
|
export const HttpResponseStatus = {
|
|
5
5
|
OK: createApiStatus(true, 200, msg.ok),
|
|
6
6
|
CREATED: createApiStatus(true, 201, msg.created),
|
|
7
|
+
ACCEPTED: createApiStatus(true, 202, msg.created),
|
|
8
|
+
NO_CONTENT: createApiStatus(true, 204, msg.noContent),
|
|
7
9
|
BAD_REQUEST: createApiStatus(false, 400, msg.badRequest),
|
|
8
10
|
UNAUTHORIZED: createApiStatus(false, 401, msg.unauthorized),
|
|
9
11
|
FORBIDDEN: createApiStatus(false, 403, msg.forbidden),
|
|
10
12
|
NOT_FOUND: createApiStatus(false, 404, msg.notFound),
|
|
11
13
|
CONFLICT: createApiStatus(false, 409, msg.conflict),
|
|
14
|
+
LOCKED: createApiStatus(false, 423, msg.locked),
|
|
12
15
|
TOO_MANY_REQUESTS: createApiStatus(false, 429, msg.tooManyRequests),
|
|
13
16
|
SERVER_ERROR: createApiStatus(false, 500, msg.serverError),
|
|
14
17
|
};
|
|
@@ -2,11 +2,14 @@ export declare const Msg: {
|
|
|
2
2
|
apiStatus: {
|
|
3
3
|
ok: string;
|
|
4
4
|
created: string;
|
|
5
|
+
accepted: string;
|
|
6
|
+
noContent: string;
|
|
5
7
|
badRequest: string;
|
|
6
8
|
unauthorized: string;
|
|
7
9
|
forbidden: string;
|
|
8
10
|
notFound: string;
|
|
9
11
|
conflict: string;
|
|
12
|
+
locked: string;
|
|
10
13
|
tooManyRequests: string;
|
|
11
14
|
serverError: string;
|
|
12
15
|
};
|
|
@@ -5,11 +5,14 @@ export const Msg = {
|
|
|
5
5
|
apiStatus: {
|
|
6
6
|
ok: `${___HTTP_STATUS___}:ok`,
|
|
7
7
|
created: `${___HTTP_STATUS___}:created`,
|
|
8
|
+
accepted: `${___HTTP_STATUS___}:accepted`,
|
|
9
|
+
noContent: `${___HTTP_STATUS___}:noContent`,
|
|
8
10
|
badRequest: `${___HTTP_STATUS___}:badRequest`,
|
|
9
11
|
unauthorized: `${___HTTP_STATUS___}:unauthorized`,
|
|
10
12
|
forbidden: `${___HTTP_STATUS___}:forbidden`,
|
|
11
13
|
notFound: `${___HTTP_STATUS___}:notFound`,
|
|
12
14
|
conflict: `${___HTTP_STATUS___}:conflict`,
|
|
15
|
+
locked: `${___HTTP_STATUS___}:locked`, // Account is temporarily locked. Try again later or reset your password. OR Your account has been temporarily locked due to multiple failed login attempts. Please reset your password to regain access.
|
|
13
16
|
tooManyRequests: `${___HTTP_STATUS___}:tooManyRequests`,
|
|
14
17
|
serverError: `${___HTTP_STATUS___}:serverError`,
|
|
15
18
|
},
|
|
@@ -3,6 +3,12 @@ import { privateCors } from './cors/privateCors.js';
|
|
|
3
3
|
import { publicCors } from './cors/publicCors.js';
|
|
4
4
|
import { apiKeyAuthorization } from './requestAuth/auth.middleware.js';
|
|
5
5
|
import { validateQueryParams, validateBodyJson } from './zod/validate.js';
|
|
6
|
+
import { createRedisLocker, setRedisLock, removeRedisLock, checkIfLockedInRedis } from './redisLocks/redisLocker.js';
|
|
7
|
+
import { RedisLockerConfigFactory } from './redisLocks/redisLockerConfigFactory.js';
|
|
8
|
+
import { RedisLocker, RedisLockerConfig, RedisLockerConfigParams } from './redisLocks/types.js';
|
|
6
9
|
export { CorsConfig, initCors, privateCors, publicCors };
|
|
7
10
|
export { apiKeyAuthorization };
|
|
8
11
|
export { validateQueryParams, validateBodyJson };
|
|
12
|
+
export { createRedisLocker, setRedisLock, removeRedisLock as removeLock, checkIfLockedInRedis as isLocked };
|
|
13
|
+
export { RedisLockerConfigFactory };
|
|
14
|
+
export { RedisLocker, RedisLockerConfig, RedisLockerConfigParams };
|
|
@@ -3,6 +3,10 @@ import { privateCors } from './cors/privateCors.js';
|
|
|
3
3
|
import { publicCors } from './cors/publicCors.js';
|
|
4
4
|
import { apiKeyAuthorization } from './requestAuth/auth.middleware.js';
|
|
5
5
|
import { validateQueryParams, validateBodyJson } from './zod/validate.js';
|
|
6
|
+
import { createRedisLocker, setRedisLock, removeRedisLock, checkIfLockedInRedis } from './redisLocks/redisLocker.js';
|
|
7
|
+
import { RedisLockerConfigFactory } from './redisLocks/redisLockerConfigFactory.js';
|
|
6
8
|
export { initCors, privateCors, publicCors };
|
|
7
9
|
export { apiKeyAuthorization };
|
|
8
10
|
export { validateQueryParams, validateBodyJson };
|
|
11
|
+
export { createRedisLocker, setRedisLock, removeRedisLock as removeLock, checkIfLockedInRedis as isLocked };
|
|
12
|
+
export { RedisLockerConfigFactory };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { RedisLocker, RedisLockerConfig } from "./types.js";
|
|
2
|
+
import { Request } from "express";
|
|
3
|
+
export declare const createRedisLocker: (config: RedisLockerConfig) => RedisLocker;
|
|
4
|
+
export declare const generateRedisLockKey: (config: RedisLockerConfig, req: Request) => string;
|
|
5
|
+
export declare const setRedisLock: (key: string, ttlSeconds: number) => Promise<void>;
|
|
6
|
+
export declare const removeRedisLock: (key: string) => Promise<void>;
|
|
7
|
+
export declare const checkIfLockedInRedis: (key: string) => Promise<boolean>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { getRedisClient } from "mielk-fn/redis";
|
|
11
|
+
import { failure, HttpResponseStatus } from "../../http/index.js";
|
|
12
|
+
import { Msg } from "../../internal/messaging/messageTags.js";
|
|
13
|
+
export const createRedisLocker = (config) => {
|
|
14
|
+
return (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
|
|
15
|
+
const { message } = config;
|
|
16
|
+
const key = generateRedisLockKey(config, req);
|
|
17
|
+
const isLocked = yield checkIfLockedInRedis(key);
|
|
18
|
+
if (isLocked) {
|
|
19
|
+
return failure(res, HttpResponseStatus.LOCKED, message || Msg.apiStatus.locked);
|
|
20
|
+
}
|
|
21
|
+
return next();
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
export const generateRedisLockKey = (config, req) => {
|
|
25
|
+
const { keyPrefix, keySuffixes } = config;
|
|
26
|
+
return `${keyPrefix}:${keySuffixes(req).join(':')}`;
|
|
27
|
+
};
|
|
28
|
+
export const setRedisLock = (key, ttlSeconds) => __awaiter(void 0, void 0, void 0, function* () {
|
|
29
|
+
const redisClient = yield getRedisClient();
|
|
30
|
+
yield redisClient.set(key, JSON.stringify({ locked: true }), {
|
|
31
|
+
expiration: {
|
|
32
|
+
type: 'EX',
|
|
33
|
+
value: ttlSeconds
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
console.log('RL key:', key, ttlSeconds);
|
|
37
|
+
});
|
|
38
|
+
export const removeRedisLock = (key) => __awaiter(void 0, void 0, void 0, function* () {
|
|
39
|
+
const redisClient = yield getRedisClient();
|
|
40
|
+
yield redisClient.del(key);
|
|
41
|
+
});
|
|
42
|
+
export const checkIfLockedInRedis = (key) => __awaiter(void 0, void 0, void 0, function* () {
|
|
43
|
+
const redisClient = yield getRedisClient();
|
|
44
|
+
const value = yield redisClient.get(key);
|
|
45
|
+
return value !== null;
|
|
46
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { RedisKeyFactory } from "../../rateLimit/redisKeysFactory.js";
|
|
2
|
+
import { Msg } from "../../internal/messaging/messageTags.js";
|
|
3
|
+
const defaultRedisLockerConfig = {
|
|
4
|
+
keyPrefix: RedisKeyFactory.prefixes.lockEmail,
|
|
5
|
+
keySuffixes: RedisKeyFactory.suffixes.mail,
|
|
6
|
+
ttlSeconds: 3 * 60,
|
|
7
|
+
message: Msg.apiStatus.locked,
|
|
8
|
+
};
|
|
9
|
+
const createRedisLockerConfig = (params) => {
|
|
10
|
+
return Object.assign(Object.assign({}, defaultRedisLockerConfig), params);
|
|
11
|
+
};
|
|
12
|
+
const mail = (params) => {
|
|
13
|
+
return createRedisLockerConfig(Object.assign({}, (params || {})));
|
|
14
|
+
};
|
|
15
|
+
export const RedisLockerConfigFactory = {
|
|
16
|
+
mail,
|
|
17
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { NextFunction, Request, Response } from "express";
|
|
2
|
+
export type RedisLocker = (req: Request, res: Response, next: NextFunction) => Promise<void | Response<Record<string, any>, Record<string, any>>>;
|
|
3
|
+
export interface RedisLockerConfigParams {
|
|
4
|
+
keyPrefix?: string;
|
|
5
|
+
keySuffixes?: (req: Request) => string[];
|
|
6
|
+
ttlSeconds?: number;
|
|
7
|
+
message?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface RedisLockerConfig {
|
|
10
|
+
keyPrefix: string;
|
|
11
|
+
keySuffixes: (req: Request) => string[];
|
|
12
|
+
ttlSeconds: number;
|
|
13
|
+
message: string;
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -8,8 +8,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { getRedisClient } from 'mielk-fn/redis';
|
|
11
|
+
import { setRedisLock } from '../middlewares/redisLocks/redisLocker.js';
|
|
11
12
|
export const checkRateLimit = (rateLimit) => __awaiter(void 0, void 0, void 0, function* () {
|
|
12
|
-
const { key, limit, windowSec } = rateLimit;
|
|
13
|
+
const { key, limit, windowSec, redisLock } = rateLimit;
|
|
13
14
|
const client = yield getRedisClient();
|
|
14
15
|
const currentCounter = yield client.incr(key);
|
|
15
16
|
if (currentCounter === 1) {
|
|
@@ -17,6 +18,12 @@ export const checkRateLimit = (rateLimit) => __awaiter(void 0, void 0, void 0, f
|
|
|
17
18
|
}
|
|
18
19
|
const ttl = yield client.ttl(key);
|
|
19
20
|
const allowed = currentCounter <= limit;
|
|
21
|
+
if (!allowed && redisLock) {
|
|
22
|
+
const { key, ttlSeconds } = redisLock;
|
|
23
|
+
console.log(`Setting Redis lock for ${key} | ${ttlSeconds} seconds`);
|
|
24
|
+
setRedisLock(key, ttlSeconds);
|
|
25
|
+
}
|
|
26
|
+
console.log('RL key:', key, 'current:', currentCounter, 'ttl:', ttl);
|
|
20
27
|
return {
|
|
21
28
|
currentCounter,
|
|
22
29
|
limit,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Request, Response, NextFunction } from 'express';
|
|
2
|
-
import { RateLimitConfig } from './types.js';
|
|
3
|
-
export declare const createGlobalRateLimiter: (config?:
|
|
2
|
+
import { RateLimitConfig, RateLimitConfigParams } from './types.js';
|
|
3
|
+
export declare const createGlobalRateLimiter: (config?: RateLimitConfigParams) => (req: Request, res: Response, next: NextFunction) => Promise<void | Response<Record<string, any>, Record<string, any>>>;
|
|
4
4
|
export declare const createRateLimiter: (config: RateLimitConfig) => (req: Request, res: Response, next: NextFunction) => Promise<void | Response<Record<string, any>, Record<string, any>>>;
|
|
@@ -11,8 +11,9 @@ import { checkRateLimit } from './checkRateLimit.js';
|
|
|
11
11
|
import { failure, HttpResponseStatus } from '../http/index.js';
|
|
12
12
|
import { Msg } from '../internal/messaging/messageTags.js';
|
|
13
13
|
import { RateLimitConfigFactory } from './rateLimitConfigFactory.js';
|
|
14
|
+
import { generateRedisLockKey } from '../middlewares/redisLocks/redisLocker.js';
|
|
14
15
|
export const createGlobalRateLimiter = (config) => {
|
|
15
|
-
return createRateLimiter(
|
|
16
|
+
return createRateLimiter(RateLimitConfigFactory.globalIp(config));
|
|
16
17
|
};
|
|
17
18
|
export const createRateLimiter = (config) => {
|
|
18
19
|
return (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -22,6 +23,8 @@ export const createRateLimiter = (config) => {
|
|
|
22
23
|
res.setHeader('X-RateLimit-Limit', limit);
|
|
23
24
|
res.setHeader('X-RateLimit-Remaining', Math.max(0, limit - currentCounter));
|
|
24
25
|
res.setHeader('X-RateLimit-Reset', ttl);
|
|
26
|
+
console.log('IP:', req.ip);
|
|
27
|
+
console.log('Forwarded:', req.headers['x-forwarded-for']);
|
|
25
28
|
if (!allowed) {
|
|
26
29
|
return failure(res, HttpResponseStatus.TOO_MANY_REQUESTS, message || Msg.apiStatus.tooManyRequests);
|
|
27
30
|
}
|
|
@@ -29,9 +32,16 @@ export const createRateLimiter = (config) => {
|
|
|
29
32
|
});
|
|
30
33
|
};
|
|
31
34
|
const createRateLimitFromConfig = (config, req) => {
|
|
32
|
-
const { limit, windowSec, message } = config;
|
|
35
|
+
const { limit, windowSec, message, redisLockerConfig } = config;
|
|
33
36
|
const key = generateKeyFromConfig(config, req);
|
|
34
|
-
|
|
37
|
+
const rateLimit = { key, limit, windowSec, message };
|
|
38
|
+
if (redisLockerConfig) {
|
|
39
|
+
const { ttlSeconds } = redisLockerConfig;
|
|
40
|
+
const key = generateRedisLockKey(redisLockerConfig, req);
|
|
41
|
+
const redisLock = { key, ttlSeconds };
|
|
42
|
+
rateLimit.redisLock = redisLock;
|
|
43
|
+
}
|
|
44
|
+
return rateLimit;
|
|
35
45
|
};
|
|
36
46
|
const generateKeyFromConfig = (config, req) => {
|
|
37
47
|
const { keyPrefix, keySuffixes } = config;
|
|
@@ -2,6 +2,7 @@ import { checkRateLimit } from './checkRateLimit.js';
|
|
|
2
2
|
import { createRateLimiter } from './createRateLimiter.js';
|
|
3
3
|
import { RateLimitConfigFactory } from './rateLimitConfigFactory.js';
|
|
4
4
|
import { RedisKeyFactory } from './redisKeysFactory.js';
|
|
5
|
-
import { RateLimitConfig, RateLimit, RateLimitCheck } from './types.js';
|
|
5
|
+
import { type RateLimiter, RateLimitConfig, RateLimit, RateLimitCheck } from './types.js';
|
|
6
6
|
export { checkRateLimit, createRateLimiter, RateLimitConfigFactory, RedisKeyFactory };
|
|
7
7
|
export { RateLimitConfig, RateLimit, RateLimitCheck };
|
|
8
|
+
export type { RateLimiter };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { RateLimitConfig } from "./types.js";
|
|
1
|
+
import { RateLimitConfig, RateLimitConfigParams } from "./types.js";
|
|
2
2
|
export declare const RateLimitConfigFactory: {
|
|
3
|
-
globalIp: RateLimitConfig;
|
|
4
|
-
loginIp: RateLimitConfig;
|
|
5
|
-
loginIpMail: RateLimitConfig;
|
|
6
|
-
loginMail: RateLimitConfig;
|
|
3
|
+
globalIp: (params?: RateLimitConfigParams) => RateLimitConfig;
|
|
4
|
+
loginIp: (params?: RateLimitConfigParams) => RateLimitConfig;
|
|
5
|
+
loginIpMail: (params?: RateLimitConfigParams) => RateLimitConfig;
|
|
6
|
+
loginMail: (params?: RateLimitConfigParams) => RateLimitConfig;
|
|
7
7
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { RedisKeyFactory } from "./redisKeysFactory.js";
|
|
2
2
|
import { Msg } from "../internal/messaging/messageTags.js";
|
|
3
|
+
import { RedisLockerConfigFactory } from "../middlewares/index.js";
|
|
3
4
|
const defaultRateLimitConfig = {
|
|
4
5
|
keyPrefix: RedisKeyFactory.prefixes.login,
|
|
5
6
|
keySuffixes: RedisKeyFactory.suffixes.ip,
|
|
@@ -10,18 +11,18 @@ const defaultRateLimitConfig = {
|
|
|
10
11
|
const createRateLimitConfig = (params) => {
|
|
11
12
|
return Object.assign(Object.assign({}, defaultRateLimitConfig), params);
|
|
12
13
|
};
|
|
13
|
-
const globalIp =
|
|
14
|
-
keyPrefix: RedisKeyFactory.prefixes.global,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
const loginIpMail =
|
|
20
|
-
keySuffixes: RedisKeyFactory.suffixes.ipMail,
|
|
21
|
-
}
|
|
22
|
-
const loginMail =
|
|
23
|
-
keySuffixes: RedisKeyFactory.suffixes.mail,
|
|
24
|
-
}
|
|
14
|
+
const globalIp = (params) => {
|
|
15
|
+
return createRateLimitConfig(Object.assign({ keyPrefix: RedisKeyFactory.prefixes.global, windowSec: 60, limit: 2 }, (params || {})));
|
|
16
|
+
};
|
|
17
|
+
const loginIp = (params) => {
|
|
18
|
+
return createRateLimitConfig(Object.assign({}, (params || {})));
|
|
19
|
+
};
|
|
20
|
+
const loginIpMail = (params) => {
|
|
21
|
+
return createRateLimitConfig(Object.assign({ keySuffixes: RedisKeyFactory.suffixes.ipMail }, (params || {})));
|
|
22
|
+
};
|
|
23
|
+
const loginMail = (params) => {
|
|
24
|
+
return createRateLimitConfig(Object.assign({ keySuffixes: RedisKeyFactory.suffixes.mail, redisLockerConfig: RedisLockerConfigFactory.mail() }, (params || {})));
|
|
25
|
+
};
|
|
25
26
|
export const RateLimitConfigFactory = {
|
|
26
27
|
globalIp,
|
|
27
28
|
loginIp,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
const prefixes = {
|
|
2
2
|
global: 'global',
|
|
3
3
|
login: 'login',
|
|
4
|
-
|
|
4
|
+
lockEmail: 'lock:email',
|
|
5
|
+
refresh: 'refresh',
|
|
5
6
|
};
|
|
6
7
|
const getIpSuffixCallback = (req) => {
|
|
7
8
|
const ip = req.ip || 'undefined';
|
|
@@ -9,12 +10,12 @@ const getIpSuffixCallback = (req) => {
|
|
|
9
10
|
};
|
|
10
11
|
const getEmailSuffixCallback = (req) => {
|
|
11
12
|
var _a;
|
|
12
|
-
const email = ((_a = req.body) === null || _a === void 0 ? void 0 : _a.email) || 'unknown';
|
|
13
|
+
const email = (((_a = req.body) === null || _a === void 0 ? void 0 : _a.email) || 'unknown').toLowerCase();
|
|
13
14
|
return [email];
|
|
14
15
|
};
|
|
15
16
|
const getIpEmailSuffixCallback = (req) => {
|
|
16
17
|
var _a;
|
|
17
|
-
const email = ((_a = req.body) === null || _a === void 0 ? void 0 : _a.email) || 'unknown';
|
|
18
|
+
const email = (((_a = req.body) === null || _a === void 0 ? void 0 : _a.email) || 'unknown').toLowerCase();
|
|
18
19
|
const ip = req.ip || 'unknown';
|
|
19
20
|
return [ip, email];
|
|
20
21
|
};
|
|
@@ -1,16 +1,31 @@
|
|
|
1
|
-
import { Request } from "express";
|
|
1
|
+
import { NextFunction, Request, Response } from "express";
|
|
2
|
+
import { RedisLockerConfig } from "../middlewares/index.js";
|
|
3
|
+
export type RateLimiter = (req: Request, res: Response, next: NextFunction) => Promise<void | Response<Record<string, any>, Record<string, any>>>;
|
|
4
|
+
export type RateLimitConfigParams = {
|
|
5
|
+
keyPrefix?: string;
|
|
6
|
+
keySuffixes?: (req: Request) => string[];
|
|
7
|
+
windowSec?: number;
|
|
8
|
+
limit?: number;
|
|
9
|
+
message?: string;
|
|
10
|
+
redisLockerConfig?: RedisLockerConfig | null;
|
|
11
|
+
};
|
|
2
12
|
export interface RateLimitConfig {
|
|
3
13
|
keyPrefix: string;
|
|
4
14
|
keySuffixes: (req: Request) => string[];
|
|
5
15
|
limit: number;
|
|
6
16
|
windowSec: number;
|
|
7
17
|
message?: string;
|
|
18
|
+
redisLockerConfig?: RedisLockerConfig | null;
|
|
8
19
|
}
|
|
9
20
|
export interface RateLimit {
|
|
10
21
|
key: string;
|
|
11
22
|
limit: number;
|
|
12
23
|
windowSec: number;
|
|
13
24
|
message?: string;
|
|
25
|
+
redisLock?: {
|
|
26
|
+
key: string;
|
|
27
|
+
ttlSeconds: number;
|
|
28
|
+
};
|
|
14
29
|
}
|
|
15
30
|
export interface RateLimitCheck {
|
|
16
31
|
currentCounter: number;
|
|
@@ -2,8 +2,8 @@ import { PostgreDbConfig } from '../db/pg/index.js';
|
|
|
2
2
|
import { MsSqlDbConfig } from '../db/mssql/index.js';
|
|
3
3
|
import { CorsConfig } from '../middlewares/index.js';
|
|
4
4
|
import { DbProvider } from './DbProvider.js';
|
|
5
|
-
import {
|
|
5
|
+
import { RateLimitConfigParams } from '../rateLimit/types.js';
|
|
6
6
|
export type DbConfig = PostgreDbConfig | MsSqlDbConfig;
|
|
7
|
-
export declare const createExpressApp: (isProd: boolean, dbConfig: DbConfig, corsConfig: CorsConfig, rateLimitConfig?:
|
|
7
|
+
export declare const createExpressApp: (isProd: boolean, dbConfig: DbConfig, corsConfig: CorsConfig, rateLimitConfig?: RateLimitConfigParams) => Promise<import("express-serve-static-core").Express>;
|
|
8
8
|
export declare const isProd: () => boolean;
|
|
9
9
|
export declare const getDbProvider: () => DbProvider;
|
package/dist/routing/express.js
CHANGED
|
@@ -31,6 +31,8 @@ export const createExpressApp = (isProd, dbConfig, corsConfig, rateLimitConfig)
|
|
|
31
31
|
initCors(corsConfig);
|
|
32
32
|
app.use(createGlobalRateLimiter(rateLimitConfig));
|
|
33
33
|
app.use(express.json());
|
|
34
|
+
if (isProd)
|
|
35
|
+
app.set('trust proxy', 1);
|
|
34
36
|
return app;
|
|
35
37
|
});
|
|
36
38
|
export const isProd = () => env.isProd;
|