mielk-api 1.4.0 → 1.5.1

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.
Files changed (34) hide show
  1. package/dist/http/httpResponseStatus/HttpResponseStatus.d.ts +3 -0
  2. package/dist/http/httpResponseStatus/HttpResponseStatus.js +3 -0
  3. package/dist/internal/messaging/messageTags.d.ts +3 -0
  4. package/dist/internal/messaging/messageTags.js +3 -0
  5. package/dist/middlewares/index.d.ts +12 -0
  6. package/dist/middlewares/index.js +12 -0
  7. package/dist/{rateLimit → middlewares/rateLimit}/checkRateLimit.js +6 -1
  8. package/dist/{rateLimit → middlewares/rateLimit}/createRateLimiter.d.ts +2 -2
  9. package/dist/{rateLimit → middlewares/rateLimit}/createRateLimiter.js +16 -5
  10. package/dist/{rateLimit → middlewares/rateLimit}/index.d.ts +3 -2
  11. package/dist/{rateLimit → middlewares/rateLimit}/index.js +1 -1
  12. package/dist/middlewares/rateLimit/rateLimitConfigFactory.d.ts +7 -0
  13. package/dist/middlewares/rateLimit/rateLimitConfigFactory.js +30 -0
  14. package/dist/middlewares/rateLimit/types.d.ts +35 -0
  15. package/dist/{rateLimit → middlewares/redis}/redisKeysFactory.d.ts +1 -0
  16. package/dist/{rateLimit → middlewares/redis}/redisKeysFactory.js +4 -3
  17. package/dist/middlewares/redis/redisLockChecker.d.ts +5 -0
  18. package/dist/middlewares/redis/redisLockChecker.js +31 -0
  19. package/dist/middlewares/redis/redisLockCheckerConfigFactory.d.ts +4 -0
  20. package/dist/middlewares/redis/redisLockCheckerConfigFactory.js +16 -0
  21. package/dist/middlewares/redis/redisLocker.d.ts +2 -0
  22. package/dist/middlewares/redis/redisLocker.js +23 -0
  23. package/dist/middlewares/redis/redisLockerConfigFactory.d.ts +4 -0
  24. package/dist/middlewares/redis/redisLockerConfigFactory.js +14 -0
  25. package/dist/middlewares/redis/types.d.ts +20 -0
  26. package/dist/middlewares/redis/types.js +1 -0
  27. package/dist/routing/express.d.ts +2 -2
  28. package/dist/routing/express.js +3 -1
  29. package/package.json +4 -4
  30. package/dist/rateLimit/rateLimitConfigFactory.d.ts +0 -7
  31. package/dist/rateLimit/rateLimitConfigFactory.js +0 -30
  32. package/dist/rateLimit/types.d.ts +0 -20
  33. /package/dist/{rateLimit → middlewares/rateLimit}/checkRateLimit.d.ts +0 -0
  34. /package/dist/{rateLimit → middlewares/rateLimit}/types.js +0 -0
@@ -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,18 @@ 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 { RedisLockerConfigFactory } from './redis/redisLockerConfigFactory.js';
7
+ import { RedisLockerConfig, RedisLockerConfigParams } from './redis/types.js';
8
+ import { setRedisLock, removeRedisLock } from './redis/redisLocker.js';
9
+ import { RedisLockCheckerConfigFactory } from './redis/redisLockCheckerConfigFactory.js';
10
+ import { RedisLockChecker, RedisLockCheckerConfig, RedisLockCheckerConfigParams } from './redis/types.js';
11
+ import { createRedisLockChecker, checkIfLockedInRedis } from './redis/redisLockChecker.js';
6
12
  export { CorsConfig, initCors, privateCors, publicCors };
7
13
  export { apiKeyAuthorization };
8
14
  export { validateQueryParams, validateBodyJson };
15
+ export { RedisLockerConfigFactory };
16
+ export { RedisLockerConfig, RedisLockerConfigParams };
17
+ export { setRedisLock, removeRedisLock };
18
+ export { createRedisLockChecker, checkIfLockedInRedis };
19
+ export { RedisLockCheckerConfigFactory };
20
+ export { RedisLockChecker, RedisLockCheckerConfig, RedisLockCheckerConfigParams };
@@ -3,6 +3,18 @@ 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
+ // Redis locker
7
+ import { RedisLockerConfigFactory } from './redis/redisLockerConfigFactory.js';
8
+ import { setRedisLock, removeRedisLock } from './redis/redisLocker.js';
9
+ // Redis lock checker
10
+ import { RedisLockCheckerConfigFactory } from './redis/redisLockCheckerConfigFactory.js';
11
+ import { createRedisLockChecker, checkIfLockedInRedis } from './redis/redisLockChecker.js';
6
12
  export { initCors, privateCors, publicCors };
7
13
  export { apiKeyAuthorization };
8
14
  export { validateQueryParams, validateBodyJson };
15
+ // Redis locker
16
+ export { RedisLockerConfigFactory };
17
+ export { setRedisLock, removeRedisLock };
18
+ // Redis lock checker
19
+ export { createRedisLockChecker, checkIfLockedInRedis };
20
+ export { RedisLockCheckerConfigFactory };
@@ -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 '../redis/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,10 @@ 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
+ setRedisLock(key, ttlSeconds);
24
+ }
20
25
  return {
21
26
  currentCounter,
22
27
  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?: RateLimitConfig) => (req: Request, res: Response, next: NextFunction) => Promise<void | Response<Record<string, any>, Record<string, any>>>;
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>>>;
@@ -8,11 +8,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { checkRateLimit } from './checkRateLimit.js';
11
- import { failure, HttpResponseStatus } from '../http/index.js';
12
- import { Msg } from '../internal/messaging/messageTags.js';
11
+ import { failure, HttpResponseStatus } from '../../http/index.js';
13
12
  import { RateLimitConfigFactory } from './rateLimitConfigFactory.js';
13
+ import { generateRedisLockKey } from '../redis/redisLockChecker.js';
14
+ import { Msg } from '../../internal/messaging/messageTags.js';
14
15
  export const createGlobalRateLimiter = (config) => {
15
- return createRateLimiter(config || RateLimitConfigFactory.globalIp);
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,17 @@ 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
- return { key, limit, windowSec, message };
37
+ const rateLimit = { key, limit, windowSec, message };
38
+ if (redisLockerConfig) {
39
+ const { keyPrefix, ttlSeconds } = redisLockerConfig;
40
+ const { keySuffixes } = config;
41
+ const key = generateRedisLockKey(keyPrefix, keySuffixes, req);
42
+ const redisLock = { key, ttlSeconds };
43
+ rateLimit.redisLock = redisLock;
44
+ }
45
+ return rateLimit;
35
46
  };
36
47
  const generateKeyFromConfig = (config, req) => {
37
48
  const { keyPrefix, keySuffixes } = config;
@@ -1,7 +1,8 @@
1
1
  import { checkRateLimit } from './checkRateLimit.js';
2
2
  import { createRateLimiter } from './createRateLimiter.js';
3
3
  import { RateLimitConfigFactory } from './rateLimitConfigFactory.js';
4
- import { RedisKeyFactory } from './redisKeysFactory.js';
5
- import { RateLimitConfig, RateLimit, RateLimitCheck } from './types.js';
4
+ import { RedisKeyFactory } from '../redis/redisKeysFactory.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,5 +1,5 @@
1
1
  import { checkRateLimit } from './checkRateLimit.js';
2
2
  import { createRateLimiter } from './createRateLimiter.js';
3
3
  import { RateLimitConfigFactory } from './rateLimitConfigFactory.js';
4
- import { RedisKeyFactory } from './redisKeysFactory.js';
4
+ import { RedisKeyFactory } from '../redis/redisKeysFactory.js';
5
5
  export { checkRateLimit, createRateLimiter, RateLimitConfigFactory, RedisKeyFactory };
@@ -0,0 +1,7 @@
1
+ import { RateLimitConfig, RateLimitConfigParams } from "./types.js";
2
+ export declare const RateLimitConfigFactory: {
3
+ globalIp: (params?: RateLimitConfigParams) => RateLimitConfig;
4
+ loginIp: (params?: RateLimitConfigParams) => RateLimitConfig;
5
+ loginIpMail: (params?: RateLimitConfigParams) => RateLimitConfig;
6
+ loginMail: (params?: RateLimitConfigParams) => RateLimitConfig;
7
+ };
@@ -0,0 +1,30 @@
1
+ import { RedisKeyFactory } from "../redis/redisKeysFactory.js";
2
+ import { Msg } from "../../internal/messaging/messageTags.js";
3
+ const defaultRateLimitConfig = {
4
+ keyPrefix: RedisKeyFactory.prefixes.login,
5
+ keySuffixes: RedisKeyFactory.suffixes.ip,
6
+ windowSec: 15 * 60,
7
+ limit: 5,
8
+ message: Msg.apiStatus.tooManyRequests,
9
+ };
10
+ const createRateLimitConfig = (params) => {
11
+ return Object.assign(Object.assign({}, defaultRateLimitConfig), params);
12
+ };
13
+ const globalIp = (params) => {
14
+ return createRateLimitConfig(Object.assign({ keyPrefix: RedisKeyFactory.prefixes.global, windowSec: 60, limit: 2 }, (params || {})));
15
+ };
16
+ const loginIp = (params) => {
17
+ return createRateLimitConfig(Object.assign({}, (params || {})));
18
+ };
19
+ const loginIpMail = (params) => {
20
+ return createRateLimitConfig(Object.assign({ keySuffixes: RedisKeyFactory.suffixes.ipMail }, (params || {})));
21
+ };
22
+ const loginMail = (params) => {
23
+ return createRateLimitConfig(Object.assign({ keySuffixes: RedisKeyFactory.suffixes.mail, redisLockerConfig: { keyPrefix: RedisKeyFactory.prefixes.lockEmail, ttlSeconds: 15 * 60 } }, (params || {})));
24
+ };
25
+ export const RateLimitConfigFactory = {
26
+ globalIp,
27
+ loginIp,
28
+ loginIpMail,
29
+ loginMail
30
+ };
@@ -0,0 +1,35 @@
1
+ import { NextFunction, Request, Response } from 'express';
2
+ import { RedisLockerConfig } from '../redis/types.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
+ };
12
+ export interface RateLimitConfig {
13
+ keyPrefix: string;
14
+ keySuffixes: (req: Request) => string[];
15
+ limit: number;
16
+ windowSec: number;
17
+ message?: string;
18
+ redisLockerConfig?: RedisLockerConfig | null;
19
+ }
20
+ export interface RateLimit {
21
+ key: string;
22
+ limit: number;
23
+ windowSec: number;
24
+ message?: string;
25
+ redisLock?: {
26
+ key: string;
27
+ ttlSeconds: number;
28
+ };
29
+ }
30
+ export interface RateLimitCheck {
31
+ currentCounter: number;
32
+ limit: number;
33
+ ttl: number;
34
+ allowed: boolean;
35
+ }
@@ -3,6 +3,7 @@ export declare const RedisKeyFactory: {
3
3
  prefixes: {
4
4
  readonly global: "global";
5
5
  readonly login: "login";
6
+ readonly lockEmail: "lock:email";
6
7
  readonly refresh: "refresh";
7
8
  };
8
9
  suffixes: {
@@ -1,7 +1,8 @@
1
1
  const prefixes = {
2
2
  global: 'global',
3
3
  login: 'login',
4
- refresh: 'refresh'
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
  };
@@ -0,0 +1,5 @@
1
+ import { RedisLockChecker, RedisLockCheckerConfig } from "./types.js";
2
+ import { Request } from "express";
3
+ export declare const createRedisLockChecker: (config: RedisLockCheckerConfig) => RedisLockChecker;
4
+ export declare const generateRedisLockKey: (keyPrefix: string, keySuffixes: (req: Request) => string[], req: Request) => string;
5
+ export declare const checkIfLockedInRedis: (key: string) => Promise<boolean>;
@@ -0,0 +1,31 @@
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 createRedisLockChecker = (config) => {
14
+ return (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
15
+ const { message, keyPrefix, keySuffixes } = config;
16
+ const key = generateRedisLockKey(keyPrefix, keySuffixes, 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 = (keyPrefix, keySuffixes, req) => {
25
+ return `${keyPrefix}:${keySuffixes(req).join(':')}`;
26
+ };
27
+ export const checkIfLockedInRedis = (key) => __awaiter(void 0, void 0, void 0, function* () {
28
+ const redisClient = yield getRedisClient();
29
+ const value = yield redisClient.get(key);
30
+ return value !== null;
31
+ });
@@ -0,0 +1,4 @@
1
+ import { RedisLockCheckerConfig, RedisLockCheckerConfigParams } from "./types.js";
2
+ export declare const RedisLockCheckerConfigFactory: {
3
+ mail: (params?: RedisLockCheckerConfigParams) => RedisLockCheckerConfig;
4
+ };
@@ -0,0 +1,16 @@
1
+ import { RedisKeyFactory } from "./redisKeysFactory.js";
2
+ import { Msg } from "../../internal/messaging/messageTags.js";
3
+ const defaultRedisLockCheckerConfig = {
4
+ keyPrefix: RedisKeyFactory.prefixes.lockEmail,
5
+ keySuffixes: RedisKeyFactory.suffixes.mail,
6
+ message: Msg.apiStatus.locked,
7
+ };
8
+ const createRedisLockCheckerConfig = (params) => {
9
+ return Object.assign(Object.assign({}, defaultRedisLockCheckerConfig), params);
10
+ };
11
+ const mail = (params) => {
12
+ return createRedisLockCheckerConfig(Object.assign({}, (params || {})));
13
+ };
14
+ export const RedisLockCheckerConfigFactory = {
15
+ mail,
16
+ };
@@ -0,0 +1,2 @@
1
+ export declare const setRedisLock: (key: string, ttlSeconds: number) => Promise<void>;
2
+ export declare const removeRedisLock: (key: string) => Promise<void>;
@@ -0,0 +1,23 @@
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
+ export const setRedisLock = (key, ttlSeconds) => __awaiter(void 0, void 0, void 0, function* () {
12
+ const redisClient = yield getRedisClient();
13
+ yield redisClient.set(key, JSON.stringify({ locked: true }), {
14
+ expiration: {
15
+ type: 'EX',
16
+ value: ttlSeconds
17
+ }
18
+ });
19
+ });
20
+ export const removeRedisLock = (key) => __awaiter(void 0, void 0, void 0, function* () {
21
+ const redisClient = yield getRedisClient();
22
+ yield redisClient.del(key);
23
+ });
@@ -0,0 +1,4 @@
1
+ import { RedisLockerConfig, RedisLockerConfigParams } from "./types.js";
2
+ export declare const RedisLockerConfigFactory: {
3
+ mail: (params?: RedisLockerConfigParams) => RedisLockerConfig;
4
+ };
@@ -0,0 +1,14 @@
1
+ import { RedisKeyFactory } from "./redisKeysFactory.js";
2
+ const defaultRedisLockerConfig = {
3
+ keyPrefix: RedisKeyFactory.prefixes.lockEmail,
4
+ ttlSeconds: 30 * 60,
5
+ };
6
+ const createRedisLockerConfig = (params) => {
7
+ return Object.assign(Object.assign({}, defaultRedisLockerConfig), params);
8
+ };
9
+ const mail = (params) => {
10
+ return createRedisLockerConfig(Object.assign({}, (params || {})));
11
+ };
12
+ export const RedisLockerConfigFactory = {
13
+ mail,
14
+ };
@@ -0,0 +1,20 @@
1
+ import { NextFunction, Request, Response } from "express";
2
+ export type RedisLockChecker = (req: Request, res: Response, next: NextFunction) => Promise<void | Response<Record<string, any>, Record<string, any>>>;
3
+ export interface RedisLockCheckerConfigParams {
4
+ keyPrefix?: string;
5
+ keySuffixes?: (req: Request) => string[];
6
+ message?: string;
7
+ }
8
+ export interface RedisLockCheckerConfig {
9
+ keyPrefix: string;
10
+ keySuffixes: (req: Request) => string[];
11
+ message: string;
12
+ }
13
+ export interface RedisLockerConfigParams {
14
+ keyPrefix?: string;
15
+ ttlSeconds?: number;
16
+ }
17
+ export interface RedisLockerConfig {
18
+ keyPrefix: string;
19
+ ttlSeconds: number;
20
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -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 { RateLimitConfig } from '../rateLimit/types.js';
5
+ import { RateLimitConfigParams } from '../middlewares/rateLimit/types.js';
6
6
  export type DbConfig = PostgreDbConfig | MsSqlDbConfig;
7
- export declare const createExpressApp: (isProd: boolean, dbConfig: DbConfig, corsConfig: CorsConfig, rateLimitConfig?: RateLimitConfig) => Promise<import("express-serve-static-core").Express>;
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;
@@ -11,7 +11,7 @@ import express from 'express';
11
11
  import { initDb as postgreInitDb } from '../db/pg/index.js';
12
12
  import { initDb as msSqlInitDb } from '../db/mssql/index.js';
13
13
  import { initCors } from '../middlewares/index.js';
14
- import { createGlobalRateLimiter } from '../rateLimit/createRateLimiter.js';
14
+ import { createGlobalRateLimiter } from '../middlewares/rateLimit/createRateLimiter.js';
15
15
  const env = {
16
16
  isProd: true,
17
17
  provider: undefined
@@ -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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mielk-api",
3
- "version": "1.4.0",
3
+ "version": "1.5.1",
4
4
  "keywords": [],
5
5
  "author": "mielk",
6
6
  "description": "Wrapper for API operations",
@@ -34,9 +34,9 @@
34
34
  "default": "./dist/middlewares/index.js"
35
35
  },
36
36
  "./rate-limit": {
37
- "types": "./dist/rateLimit/index.d.ts",
38
- "import": "./dist/rateLimit/index.js",
39
- "default": "./dist/rateLimit/index.js"
37
+ "types": "./dist/middlewares/rateLimit/index.d.ts",
38
+ "import": "./dist/middlewares/rateLimit/index.js",
39
+ "default": "./dist/middlewares/rateLimit/index.js"
40
40
  }
41
41
  },
42
42
  "scripts": {
@@ -1,7 +0,0 @@
1
- import { RateLimitConfig } from "./types.js";
2
- export declare const RateLimitConfigFactory: {
3
- globalIp: RateLimitConfig;
4
- loginIp: RateLimitConfig;
5
- loginIpMail: RateLimitConfig;
6
- loginMail: RateLimitConfig;
7
- };
@@ -1,30 +0,0 @@
1
- import { RedisKeyFactory } from "./redisKeysFactory.js";
2
- import { Msg } from "../internal/messaging/messageTags.js";
3
- const defaultRateLimitConfig = {
4
- keyPrefix: RedisKeyFactory.prefixes.login,
5
- keySuffixes: RedisKeyFactory.suffixes.ip,
6
- windowSec: 15 * 60,
7
- limit: 5,
8
- message: Msg.apiStatus.tooManyRequests,
9
- };
10
- const createRateLimitConfig = (params) => {
11
- return Object.assign(Object.assign({}, defaultRateLimitConfig), params);
12
- };
13
- const globalIp = createRateLimitConfig({
14
- keyPrefix: RedisKeyFactory.prefixes.global,
15
- windowSec: 60,
16
- limit: 100,
17
- });
18
- const loginIp = defaultRateLimitConfig;
19
- const loginIpMail = createRateLimitConfig({
20
- keySuffixes: RedisKeyFactory.suffixes.ipMail,
21
- });
22
- const loginMail = createRateLimitConfig({
23
- keySuffixes: RedisKeyFactory.suffixes.mail,
24
- });
25
- export const RateLimitConfigFactory = {
26
- globalIp,
27
- loginIp,
28
- loginIpMail,
29
- loginMail
30
- };
@@ -1,20 +0,0 @@
1
- import { Request } from "express";
2
- export interface RateLimitConfig {
3
- keyPrefix: string;
4
- keySuffixes: (req: Request) => string[];
5
- limit: number;
6
- windowSec: number;
7
- message?: string;
8
- }
9
- export interface RateLimit {
10
- key: string;
11
- limit: number;
12
- windowSec: number;
13
- message?: string;
14
- }
15
- export interface RateLimitCheck {
16
- currentCounter: number;
17
- limit: number;
18
- ttl: number;
19
- allowed: boolean;
20
- }