@futdevpro/nts-dynamo 1.15.31 → 1.15.33
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/build/_modules/rate-limit/_models/rate-limit-config.interface.d.ts +54 -0
- package/build/_modules/rate-limit/_models/rate-limit-config.interface.d.ts.map +1 -0
- package/build/_modules/rate-limit/_models/rate-limit-config.interface.js +3 -0
- package/build/_modules/rate-limit/_models/rate-limit-config.interface.js.map +1 -0
- package/build/_modules/rate-limit/_models/rate-limit-policy.interface.d.ts +16 -0
- package/build/_modules/rate-limit/_models/rate-limit-policy.interface.d.ts.map +1 -0
- package/build/_modules/rate-limit/_models/rate-limit-policy.interface.js +3 -0
- package/build/_modules/rate-limit/_models/rate-limit-policy.interface.js.map +1 -0
- package/build/_modules/rate-limit/index.d.ts +4 -0
- package/build/_modules/rate-limit/index.d.ts.map +1 -0
- package/build/_modules/rate-limit/index.js +6 -0
- package/build/_modules/rate-limit/index.js.map +1 -0
- package/build/_modules/rate-limit/rate-limit.middleware.d.ts +118 -0
- package/build/_modules/rate-limit/rate-limit.middleware.d.ts.map +1 -0
- package/build/_modules/rate-limit/rate-limit.middleware.js +262 -0
- package/build/_modules/rate-limit/rate-limit.middleware.js.map +1 -0
- package/build/_modules/server/errors/errors.data-service.d.ts.map +1 -1
- package/build/_modules/server/errors/errors.data-service.js +9 -1
- package/build/_modules/server/errors/errors.data-service.js.map +1 -1
- package/package.json +12 -3
- package/src/_modules/rate-limit/_models/rate-limit-config.interface.ts +60 -0
- package/src/_modules/rate-limit/_models/rate-limit-policy.interface.ts +16 -0
- package/src/_modules/rate-limit/index.ts +3 -0
- package/src/_modules/rate-limit/rate-limit.middleware.spec.ts +211 -0
- package/src/_modules/rate-limit/rate-limit.middleware.ts +310 -0
- package/src/_modules/server/errors/errors.data-service.ts +10 -2
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Request } from 'express';
|
|
2
|
+
import { DyNTS_RateLimit_Policy } from './rate-limit-policy.interface';
|
|
3
|
+
/**
|
|
4
|
+
* Config a `DyNTS_RateLimit_Middleware.configure(...)`-hoz.
|
|
5
|
+
*
|
|
6
|
+
* Minden mezo opcionalis — a default-ok megfelelnek a tipikus API
|
|
7
|
+
* rate-limit-elvarasoknak (100 req/min, sliding window, IP-alapu kulcs,
|
|
8
|
+
* path-alapu endpoint-csoportositas, X-RateLimit-* response header-ek).
|
|
9
|
+
*/
|
|
10
|
+
export interface DyNTS_RateLimit_Config {
|
|
11
|
+
/**
|
|
12
|
+
* Default request-limit `windowMs` alatt, ha az adott kulcsra nincs
|
|
13
|
+
* `setPolicyForKey()`-szel beallitott egyedi policy. Default: `100`.
|
|
14
|
+
*/
|
|
15
|
+
defaultLimit?: number;
|
|
16
|
+
/**
|
|
17
|
+
* Default sliding-window hossza milliszekundumban. Default: `60000` (1 perc).
|
|
18
|
+
*/
|
|
19
|
+
defaultWindowMs?: number;
|
|
20
|
+
/**
|
|
21
|
+
* Rate-limit subject-extractor. Visszater a karakterlanccal, ami azonositja
|
|
22
|
+
* a rate-limit alanyat (pl. IP-cim, API-kulcs ID, account ID).
|
|
23
|
+
*
|
|
24
|
+
* Default: a `req.headers['x-forwarded-for']` (csak az elso IP, ha lista)
|
|
25
|
+
* vagy ha hianyzik akkor `req.ip` vagy `'unknown'`. Ez webszerver elotti
|
|
26
|
+
* proxy/CDN-mentes setup-ra megfelelo; ha az nd-space mar identifikalja az
|
|
27
|
+
* API-kulcsot a `req`-ben, a host adhat sajat extractort ami a key-ID-t
|
|
28
|
+
* adja vissza.
|
|
29
|
+
*/
|
|
30
|
+
keyExtractor?: (req: Request) => string;
|
|
31
|
+
/**
|
|
32
|
+
* Endpoint-csoportosito. Visszater a karakterlanccal, ami azonositja az
|
|
33
|
+
* adott endpoint-csoportot. A storage-key `${subject}|${endpoint}` lesz.
|
|
34
|
+
*
|
|
35
|
+
* Default: `req.path` — minden uri-path kulon vodorbe kerul. Csoportositas
|
|
36
|
+
* mas szempontok szerint (pl. "datasets" csoport = `/api/datasets/*`)
|
|
37
|
+
* a hostnal felulirhato.
|
|
38
|
+
*/
|
|
39
|
+
endpointGrouper?: (req: Request) => string;
|
|
40
|
+
/**
|
|
41
|
+
* Beallitja-e a `X-RateLimit-Limit`, `X-RateLimit-Remaining`,
|
|
42
|
+
* `X-RateLimit-Reset` (es a 429-re `Retry-After`) response header-eket.
|
|
43
|
+
* Default: `true`.
|
|
44
|
+
*
|
|
45
|
+
* Test/dev kornyezetben opcionalisan kikapcsolhato.
|
|
46
|
+
*/
|
|
47
|
+
responseHeaders?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Per-policy override-ok az induloskor. A `setPolicyForKey()` runtime-ban is
|
|
50
|
+
* felulhatja ezeket.
|
|
51
|
+
*/
|
|
52
|
+
initialKeyPolicies?: Record<string, DyNTS_RateLimit_Policy>;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=rate-limit-config.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit-config.interface.d.ts","sourceRoot":"","sources":["../../../../src/_modules/rate-limit/_models/rate-limit-config.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAEvE;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,CAAC;IAExC;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,CAAC;IAE3C;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;CAC7D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit-config.interface.js","sourceRoot":"","sources":["../../../../src/_modules/rate-limit/_models/rate-limit-config.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-kulcs rate-limit policy.
|
|
3
|
+
*
|
|
4
|
+
* A `DyNTS_RateLimit_Middleware.setPolicyForKey(key, policy)` allitja be,
|
|
5
|
+
* vagy a `DyNTS_RateLimit_Config.initialKeyPolicies` map-en at.
|
|
6
|
+
*
|
|
7
|
+
* Tipikus use-case: subscription-tier-up — egy belepett user API-kulcsa
|
|
8
|
+
* magasabb `limit`-et kap, mint a default (anonim/IP-alapu) limit.
|
|
9
|
+
*/
|
|
10
|
+
export interface DyNTS_RateLimit_Policy {
|
|
11
|
+
/** Hany request engedelyezett a `windowMs` alatt. */
|
|
12
|
+
limit: number;
|
|
13
|
+
/** A sliding-window hossza milliszekundumban. */
|
|
14
|
+
windowMs: number;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=rate-limit-policy.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit-policy.interface.d.ts","sourceRoot":"","sources":["../../../../src/_modules/rate-limit/_models/rate-limit-policy.interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,WAAW,sBAAsB;IACrC,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAC;IAEd,iDAAiD;IACjD,QAAQ,EAAE,MAAM,CAAC;CAClB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit-policy.interface.js","sourceRoot":"","sources":["../../../../src/_modules/rate-limit/_models/rate-limit-policy.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/_modules/rate-limit/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAC/E,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DyNTS_RateLimit_Middleware = void 0;
|
|
4
|
+
var rate_limit_middleware_1 = require("./rate-limit.middleware");
|
|
5
|
+
Object.defineProperty(exports, "DyNTS_RateLimit_Middleware", { enumerable: true, get: function () { return rate_limit_middleware_1.DyNTS_RateLimit_Middleware; } });
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/_modules/rate-limit/index.ts"],"names":[],"mappings":";;;AAAA,iEAAqE;AAA5D,mIAAA,0BAA0B,OAAA"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { Request, Response } from 'express';
|
|
2
|
+
import { DyNTS_SingletonServiceBase } from '../../_services/base/singleton.service-base';
|
|
3
|
+
import { DyNTS_RateLimit_Config } from './_models/rate-limit-config.interface';
|
|
4
|
+
import { DyNTS_RateLimit_Policy } from './_models/rate-limit-policy.interface';
|
|
5
|
+
/**
|
|
6
|
+
* Sliding-window HTTP rate-limit middleware — opt-in service-szel, a meglevo
|
|
7
|
+
* `DyNTS_Endpoint_Params.preProcesses` mechanizmus mellol mukodik.
|
|
8
|
+
*
|
|
9
|
+
* **Hasznalat (host app):**
|
|
10
|
+
* ```ts
|
|
11
|
+
* const rateLimit = DyNTS_RateLimit_Middleware.getInstance();
|
|
12
|
+
* rateLimit.configure({
|
|
13
|
+
* defaultLimit: 100, // 100 req/perc default
|
|
14
|
+
* defaultWindowMs: 60_000,
|
|
15
|
+
* keyExtractor: (req) => req.headers['x-api-key'] as string || req.ip,
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* new DyNTS_Endpoint_Params({
|
|
19
|
+
* ...,
|
|
20
|
+
* preProcesses: [rateLimit.check, ...other],
|
|
21
|
+
* });
|
|
22
|
+
*
|
|
23
|
+
* // subscription-tier-up: per-kulcs egyedi limit
|
|
24
|
+
* rateLimit.setPolicyForKey('subscriber-tier-key-123', {
|
|
25
|
+
* limit: 1000,
|
|
26
|
+
* windowMs: 60_000,
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* **Viselkedes:**
|
|
31
|
+
* - Sliding-window algoritmus: minden request egy timestamp; a window-on
|
|
32
|
+
* kivuli timestamp-ek nem szamolnak. Tobb pontos mint a fix-bucket
|
|
33
|
+
* (boundary-burst nincs).
|
|
34
|
+
* - In-memory storage — single-instance MVP-nek megfelelo. Multi-instance
|
|
35
|
+
* prod-hoz Redis-backed extension kell (lasd a kozelebb dokumentumaltot).
|
|
36
|
+
* - Limit lepes: 429 DyFM_Error + `X-RateLimit-*` + `Retry-After` header-ek.
|
|
37
|
+
*
|
|
38
|
+
* **Storage:** `Map<storageKey, timestamps[]>` ahol storageKey = `${subject}|${endpoint}`.
|
|
39
|
+
* Periodikus GC takaritja a inaktiv kulcsokat.
|
|
40
|
+
*
|
|
41
|
+
* **Singleton:** `getInstance()`-szel hivd. A `.check` mezo binding-elve van
|
|
42
|
+
* `this`-re, igy direkt atadhato `preProcesses`-be ujracsomagolas nelkul.
|
|
43
|
+
*/
|
|
44
|
+
export declare class DyNTS_RateLimit_Middleware extends DyNTS_SingletonServiceBase {
|
|
45
|
+
static getInstance(): DyNTS_RateLimit_Middleware;
|
|
46
|
+
private defaultLimit;
|
|
47
|
+
private defaultWindowMs;
|
|
48
|
+
private responseHeaders;
|
|
49
|
+
private keyExtractor;
|
|
50
|
+
private endpointGrouper;
|
|
51
|
+
/** request-log: storageKey → timestamp-tomb (Date.now() ms). */
|
|
52
|
+
private requestLog;
|
|
53
|
+
/** Per-kulcs egyedi policy-k. */
|
|
54
|
+
private keyPolicies;
|
|
55
|
+
/** GC timer handle. */
|
|
56
|
+
private gcTimer;
|
|
57
|
+
/**
|
|
58
|
+
* Konfig override. Hianyzo mezok a default-okat orzik. Hivhato barmikor —
|
|
59
|
+
* a `check()` a friss config-ot olvassa.
|
|
60
|
+
*/
|
|
61
|
+
configure(config: DyNTS_RateLimit_Config): void;
|
|
62
|
+
/**
|
|
63
|
+
* Aktualis konfig olvasasa (diagnosztika celokra).
|
|
64
|
+
*/
|
|
65
|
+
getConfig(): {
|
|
66
|
+
defaultLimit: number;
|
|
67
|
+
defaultWindowMs: number;
|
|
68
|
+
responseHeaders: boolean;
|
|
69
|
+
activeKeyPolicies: number;
|
|
70
|
+
trackedStorageKeys: number;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Per-kulcs egyedi policy beallitas (pl. subscription-tier alapjan).
|
|
74
|
+
* A `key`-nek pontosan azzal a stringgel kell egyeznie, amit a `keyExtractor`
|
|
75
|
+
* visszaad.
|
|
76
|
+
*/
|
|
77
|
+
setPolicyForKey(key: string, policy: DyNTS_RateLimit_Policy): void;
|
|
78
|
+
/**
|
|
79
|
+
* Per-kulcs policy torlese (visszaall a default-ra).
|
|
80
|
+
*/
|
|
81
|
+
clearPolicyForKey(key: string): void;
|
|
82
|
+
/**
|
|
83
|
+
* Pre-process function — atadhato `DyNTS_Endpoint_Params.preProcesses`-be.
|
|
84
|
+
*
|
|
85
|
+
* Throws:
|
|
86
|
+
* - 429 ha az aktualis request meghaladna a limit-et a sliding window-on
|
|
87
|
+
*
|
|
88
|
+
* Side-effect: ha `responseHeaders === true`, beallitja az `X-RateLimit-Limit`,
|
|
89
|
+
* `X-RateLimit-Remaining`, `X-RateLimit-Reset` header-eket; 429 eseten
|
|
90
|
+
* a `Retry-After` header-t is.
|
|
91
|
+
*/
|
|
92
|
+
readonly check: (req: Request, res: Response) => Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* Default key-extractor: x-forwarded-for vagy req.ip vagy 'unknown'.
|
|
95
|
+
* Csak akkor hasznalt, ha a host nem allit be sajat extractort a configure-ben.
|
|
96
|
+
*/
|
|
97
|
+
private defaultKeyExtractor;
|
|
98
|
+
/**
|
|
99
|
+
* GC timer inditasa (idempotent). Periodikusan eltavolitja az inaktiv
|
|
100
|
+
* storage-key-eket a request-log-bol — memory-leak prevention.
|
|
101
|
+
*/
|
|
102
|
+
private startGcTimer;
|
|
103
|
+
/**
|
|
104
|
+
* GC sweep — minden storage-key-rol levagja a regi timestamp-eket, es
|
|
105
|
+
* eltavolitja az ureseket. Hivhato kulonosen test-bol.
|
|
106
|
+
*/
|
|
107
|
+
runGc(): void;
|
|
108
|
+
/**
|
|
109
|
+
* GC timer leallitasa (graceful shutdown vagy test-cleanup).
|
|
110
|
+
*/
|
|
111
|
+
stopGcTimer(): void;
|
|
112
|
+
/**
|
|
113
|
+
* Test-only: visszaallitja a default config-ot + uriti a state-et, hogy a
|
|
114
|
+
* specfajlok ne szivarogjak at egymas state-jet. Production code NE hivja.
|
|
115
|
+
*/
|
|
116
|
+
_resetForTesting(): void;
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=rate-limit.middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.middleware.d.ts","sourceRoot":"","sources":["../../../src/_modules/rate-limit/rate-limit.middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAI5C,OAAO,EAAE,0BAA0B,EAAE,MAAM,6CAA6C,CAAC;AAGzF,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAC/E,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AA2B/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,qBAAa,0BAA2B,SAAQ,0BAA0B;IAExE,MAAM,CAAC,WAAW,IAAI,0BAA0B;IAIhD,OAAO,CAAC,YAAY,CAAyB;IAC7C,OAAO,CAAC,eAAe,CAA6B;IACpD,OAAO,CAAC,eAAe,CAAqC;IAE5D,OAAO,CAAC,YAAY,CACsC;IAC1D,OAAO,CAAC,eAAe,CACc;IAErC,gEAAgE;IAChE,OAAO,CAAC,UAAU,CAAoC;IAEtD,iCAAiC;IACjC,OAAO,CAAC,WAAW,CAAkD;IAErE,uBAAuB;IACvB,OAAO,CAAC,OAAO,CAA+B;IAG9C;;;OAGG;IACH,SAAS,CAAC,MAAM,EAAE,sBAAsB,GAAG,IAAI;IAwB/C;;OAEG;IACH,SAAS,IAAI;QACX,YAAY,EAAE,MAAM,CAAC;QACrB,eAAe,EAAE,MAAM,CAAC;QACxB,eAAe,EAAE,OAAO,CAAC;QACzB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,kBAAkB,EAAE,MAAM,CAAC;KAC5B;IAUD;;;;OAIG;IACH,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,sBAAsB,GAAG,IAAI;IAIlE;;OAEG;IACH,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAKpC;;;;;;;;;OASG;IACH,QAAQ,CAAC,KAAK,QAAe,OAAO,OAAO,QAAQ,KAAG,OAAO,CAAC,IAAI,CAAC,CAmDjE;IAGF;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAkB3B;;;OAGG;IACH,OAAO,CAAC,YAAY;IAapB;;;OAGG;IACH,KAAK,IAAI,IAAI;IAcb;;OAEG;IACH,WAAW,IAAI,IAAI;IAQnB;;;OAGG;IACH,gBAAgB,IAAI,IAAI;CAUzB"}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DyNTS_RateLimit_Middleware = void 0;
|
|
4
|
+
const fsm_dynamo_1 = require("@futdevpro/fsm-dynamo");
|
|
5
|
+
const singleton_service_base_1 = require("../../_services/base/singleton.service-base");
|
|
6
|
+
const global_settings_const_1 = require("../../_collections/global-settings.const");
|
|
7
|
+
/** Default request-limit per default-window. */
|
|
8
|
+
const DEFAULT_LIMIT = 100;
|
|
9
|
+
/** Default sliding-window hossza ms-ben (1 perc). */
|
|
10
|
+
const DEFAULT_WINDOW_MS = 60000;
|
|
11
|
+
/** Default response-header allitas. */
|
|
12
|
+
const DEFAULT_RESPONSE_HEADERS = true;
|
|
13
|
+
/** Periodikus garbage-collection intervallum ms-ben (5 perc).
|
|
14
|
+
* A request-log-bol takaritja a regen inaktiv kulcsokat (memory-leak prevention).
|
|
15
|
+
*/
|
|
16
|
+
const GC_INTERVAL_MS = 5 * 60 * 1000;
|
|
17
|
+
/** Service-nev az error-okhoz. */
|
|
18
|
+
const SERVICE_NAME = 'DyNTS_RateLimit_Middleware';
|
|
19
|
+
/** ErrorCode-builder — system shortcode + sajat kod. */
|
|
20
|
+
const buildErrorCode = (subcode) => {
|
|
21
|
+
const sys = global_settings_const_1.DyNTS_global_settings.systemShortCodeName ?? 'DyNTS';
|
|
22
|
+
return `${sys}|DyNTS-RL-${subcode}`;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Sliding-window HTTP rate-limit middleware — opt-in service-szel, a meglevo
|
|
26
|
+
* `DyNTS_Endpoint_Params.preProcesses` mechanizmus mellol mukodik.
|
|
27
|
+
*
|
|
28
|
+
* **Hasznalat (host app):**
|
|
29
|
+
* ```ts
|
|
30
|
+
* const rateLimit = DyNTS_RateLimit_Middleware.getInstance();
|
|
31
|
+
* rateLimit.configure({
|
|
32
|
+
* defaultLimit: 100, // 100 req/perc default
|
|
33
|
+
* defaultWindowMs: 60_000,
|
|
34
|
+
* keyExtractor: (req) => req.headers['x-api-key'] as string || req.ip,
|
|
35
|
+
* });
|
|
36
|
+
*
|
|
37
|
+
* new DyNTS_Endpoint_Params({
|
|
38
|
+
* ...,
|
|
39
|
+
* preProcesses: [rateLimit.check, ...other],
|
|
40
|
+
* });
|
|
41
|
+
*
|
|
42
|
+
* // subscription-tier-up: per-kulcs egyedi limit
|
|
43
|
+
* rateLimit.setPolicyForKey('subscriber-tier-key-123', {
|
|
44
|
+
* limit: 1000,
|
|
45
|
+
* windowMs: 60_000,
|
|
46
|
+
* });
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* **Viselkedes:**
|
|
50
|
+
* - Sliding-window algoritmus: minden request egy timestamp; a window-on
|
|
51
|
+
* kivuli timestamp-ek nem szamolnak. Tobb pontos mint a fix-bucket
|
|
52
|
+
* (boundary-burst nincs).
|
|
53
|
+
* - In-memory storage — single-instance MVP-nek megfelelo. Multi-instance
|
|
54
|
+
* prod-hoz Redis-backed extension kell (lasd a kozelebb dokumentumaltot).
|
|
55
|
+
* - Limit lepes: 429 DyFM_Error + `X-RateLimit-*` + `Retry-After` header-ek.
|
|
56
|
+
*
|
|
57
|
+
* **Storage:** `Map<storageKey, timestamps[]>` ahol storageKey = `${subject}|${endpoint}`.
|
|
58
|
+
* Periodikus GC takaritja a inaktiv kulcsokat.
|
|
59
|
+
*
|
|
60
|
+
* **Singleton:** `getInstance()`-szel hivd. A `.check` mezo binding-elve van
|
|
61
|
+
* `this`-re, igy direkt atadhato `preProcesses`-be ujracsomagolas nelkul.
|
|
62
|
+
*/
|
|
63
|
+
class DyNTS_RateLimit_Middleware extends singleton_service_base_1.DyNTS_SingletonServiceBase {
|
|
64
|
+
static getInstance() {
|
|
65
|
+
return DyNTS_RateLimit_Middleware.getSingletonInstance();
|
|
66
|
+
}
|
|
67
|
+
defaultLimit = DEFAULT_LIMIT;
|
|
68
|
+
defaultWindowMs = DEFAULT_WINDOW_MS;
|
|
69
|
+
responseHeaders = DEFAULT_RESPONSE_HEADERS;
|
|
70
|
+
keyExtractor = (req) => this.defaultKeyExtractor(req);
|
|
71
|
+
endpointGrouper = (req) => req.path;
|
|
72
|
+
/** request-log: storageKey → timestamp-tomb (Date.now() ms). */
|
|
73
|
+
requestLog = new Map();
|
|
74
|
+
/** Per-kulcs egyedi policy-k. */
|
|
75
|
+
keyPolicies = new Map();
|
|
76
|
+
/** GC timer handle. */
|
|
77
|
+
gcTimer = null;
|
|
78
|
+
/**
|
|
79
|
+
* Konfig override. Hianyzo mezok a default-okat orzik. Hivhato barmikor —
|
|
80
|
+
* a `check()` a friss config-ot olvassa.
|
|
81
|
+
*/
|
|
82
|
+
configure(config) {
|
|
83
|
+
if (config.defaultLimit !== undefined) {
|
|
84
|
+
this.defaultLimit = config.defaultLimit;
|
|
85
|
+
}
|
|
86
|
+
if (config.defaultWindowMs !== undefined) {
|
|
87
|
+
this.defaultWindowMs = config.defaultWindowMs;
|
|
88
|
+
}
|
|
89
|
+
if (config.keyExtractor !== undefined) {
|
|
90
|
+
this.keyExtractor = config.keyExtractor;
|
|
91
|
+
}
|
|
92
|
+
if (config.endpointGrouper !== undefined) {
|
|
93
|
+
this.endpointGrouper = config.endpointGrouper;
|
|
94
|
+
}
|
|
95
|
+
if (config.responseHeaders !== undefined) {
|
|
96
|
+
this.responseHeaders = config.responseHeaders;
|
|
97
|
+
}
|
|
98
|
+
if (config.initialKeyPolicies !== undefined) {
|
|
99
|
+
for (const [key, policy] of Object.entries(config.initialKeyPolicies)) {
|
|
100
|
+
this.keyPolicies.set(key, policy);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
this.startGcTimer();
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Aktualis konfig olvasasa (diagnosztika celokra).
|
|
107
|
+
*/
|
|
108
|
+
getConfig() {
|
|
109
|
+
return {
|
|
110
|
+
defaultLimit: this.defaultLimit,
|
|
111
|
+
defaultWindowMs: this.defaultWindowMs,
|
|
112
|
+
responseHeaders: this.responseHeaders,
|
|
113
|
+
activeKeyPolicies: this.keyPolicies.size,
|
|
114
|
+
trackedStorageKeys: this.requestLog.size,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Per-kulcs egyedi policy beallitas (pl. subscription-tier alapjan).
|
|
119
|
+
* A `key`-nek pontosan azzal a stringgel kell egyeznie, amit a `keyExtractor`
|
|
120
|
+
* visszaad.
|
|
121
|
+
*/
|
|
122
|
+
setPolicyForKey(key, policy) {
|
|
123
|
+
this.keyPolicies.set(key, policy);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Per-kulcs policy torlese (visszaall a default-ra).
|
|
127
|
+
*/
|
|
128
|
+
clearPolicyForKey(key) {
|
|
129
|
+
this.keyPolicies.delete(key);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Pre-process function — atadhato `DyNTS_Endpoint_Params.preProcesses`-be.
|
|
133
|
+
*
|
|
134
|
+
* Throws:
|
|
135
|
+
* - 429 ha az aktualis request meghaladna a limit-et a sliding window-on
|
|
136
|
+
*
|
|
137
|
+
* Side-effect: ha `responseHeaders === true`, beallitja az `X-RateLimit-Limit`,
|
|
138
|
+
* `X-RateLimit-Remaining`, `X-RateLimit-Reset` header-eket; 429 eseten
|
|
139
|
+
* a `Retry-After` header-t is.
|
|
140
|
+
*/
|
|
141
|
+
check = async (req, res) => {
|
|
142
|
+
const subject = this.keyExtractor(req);
|
|
143
|
+
const endpoint = this.endpointGrouper(req);
|
|
144
|
+
const storageKey = `${subject}|${endpoint}`;
|
|
145
|
+
const policy = this.keyPolicies.get(subject) ?? {
|
|
146
|
+
limit: this.defaultLimit,
|
|
147
|
+
windowMs: this.defaultWindowMs,
|
|
148
|
+
};
|
|
149
|
+
const now = Date.now();
|
|
150
|
+
const windowStart = now - policy.windowMs;
|
|
151
|
+
// sliding-window: tartomanyon kivuli timestamp-eket eldobjuk
|
|
152
|
+
const existing = this.requestLog.get(storageKey) ?? [];
|
|
153
|
+
const recent = existing.filter((t) => t > windowStart);
|
|
154
|
+
if (recent.length >= policy.limit) {
|
|
155
|
+
const oldest = recent[0];
|
|
156
|
+
const resetAt = oldest + policy.windowMs;
|
|
157
|
+
const retryAfterSec = Math.max(1, Math.ceil((resetAt - now) / 1000));
|
|
158
|
+
if (this.responseHeaders) {
|
|
159
|
+
res.setHeader('X-RateLimit-Limit', policy.limit.toString());
|
|
160
|
+
res.setHeader('X-RateLimit-Remaining', '0');
|
|
161
|
+
res.setHeader('X-RateLimit-Reset', Math.ceil(resetAt / 1000).toString());
|
|
162
|
+
res.setHeader('Retry-After', retryAfterSec.toString());
|
|
163
|
+
}
|
|
164
|
+
// Frissitjuk a log-ot a kiszurt verzioval (felesleges regi timestamp-eket eldobtuk)
|
|
165
|
+
this.requestLog.set(storageKey, recent);
|
|
166
|
+
throw new fsm_dynamo_1.DyFM_Error({
|
|
167
|
+
status: 429,
|
|
168
|
+
errorCode: buildErrorCode('LIMIT'),
|
|
169
|
+
addECToUserMsg: true,
|
|
170
|
+
message: `Rate limit exceeded: ${policy.limit} req per ${policy.windowMs}ms for ${storageKey}`,
|
|
171
|
+
userMessage: `Too many requests, retry after ${retryAfterSec}s`,
|
|
172
|
+
issuerService: SERVICE_NAME,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
// alatta vagyunk a limit-nek: append the current request
|
|
176
|
+
recent.push(now);
|
|
177
|
+
this.requestLog.set(storageKey, recent);
|
|
178
|
+
if (this.responseHeaders) {
|
|
179
|
+
res.setHeader('X-RateLimit-Limit', policy.limit.toString());
|
|
180
|
+
res.setHeader('X-RateLimit-Remaining', Math.max(0, policy.limit - recent.length).toString());
|
|
181
|
+
res.setHeader('X-RateLimit-Reset', Math.ceil((now + policy.windowMs) / 1000).toString());
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
/**
|
|
185
|
+
* Default key-extractor: x-forwarded-for vagy req.ip vagy 'unknown'.
|
|
186
|
+
* Csak akkor hasznalt, ha a host nem allit be sajat extractort a configure-ben.
|
|
187
|
+
*/
|
|
188
|
+
defaultKeyExtractor(req) {
|
|
189
|
+
const xff = req.headers['x-forwarded-for'];
|
|
190
|
+
if (typeof xff === 'string' && xff.length > 0) {
|
|
191
|
+
const first = xff.split(',')[0]?.trim() ?? '';
|
|
192
|
+
if (first.length > 0) {
|
|
193
|
+
return first;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (Array.isArray(xff) && xff.length > 0) {
|
|
197
|
+
const first = xff[0]?.split(',')[0]?.trim() ?? '';
|
|
198
|
+
if (first.length > 0) {
|
|
199
|
+
return first;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return req.ip ?? 'unknown';
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* GC timer inditasa (idempotent). Periodikusan eltavolitja az inaktiv
|
|
206
|
+
* storage-key-eket a request-log-bol — memory-leak prevention.
|
|
207
|
+
*/
|
|
208
|
+
startGcTimer() {
|
|
209
|
+
if (this.gcTimer !== null) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
this.gcTimer = setInterval(() => {
|
|
213
|
+
this.runGc();
|
|
214
|
+
}, GC_INTERVAL_MS);
|
|
215
|
+
// unref hogy a process ne maradjon eletben a timer miatt
|
|
216
|
+
if (typeof this.gcTimer.unref === 'function') {
|
|
217
|
+
this.gcTimer.unref();
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* GC sweep — minden storage-key-rol levagja a regi timestamp-eket, es
|
|
222
|
+
* eltavolitja az ureseket. Hivhato kulonosen test-bol.
|
|
223
|
+
*/
|
|
224
|
+
runGc() {
|
|
225
|
+
const now = Date.now();
|
|
226
|
+
const horizon = now - this.defaultWindowMs;
|
|
227
|
+
for (const [key, timestamps] of this.requestLog) {
|
|
228
|
+
const recent = timestamps.filter((t) => t > horizon);
|
|
229
|
+
if (recent.length === 0) {
|
|
230
|
+
this.requestLog.delete(key);
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
this.requestLog.set(key, recent);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* GC timer leallitasa (graceful shutdown vagy test-cleanup).
|
|
239
|
+
*/
|
|
240
|
+
stopGcTimer() {
|
|
241
|
+
if (this.gcTimer !== null) {
|
|
242
|
+
clearInterval(this.gcTimer);
|
|
243
|
+
this.gcTimer = null;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Test-only: visszaallitja a default config-ot + uriti a state-et, hogy a
|
|
248
|
+
* specfajlok ne szivarogjak at egymas state-jet. Production code NE hivja.
|
|
249
|
+
*/
|
|
250
|
+
_resetForTesting() {
|
|
251
|
+
this.defaultLimit = DEFAULT_LIMIT;
|
|
252
|
+
this.defaultWindowMs = DEFAULT_WINDOW_MS;
|
|
253
|
+
this.responseHeaders = DEFAULT_RESPONSE_HEADERS;
|
|
254
|
+
this.keyExtractor = (req) => this.defaultKeyExtractor(req);
|
|
255
|
+
this.endpointGrouper = (req) => req.path;
|
|
256
|
+
this.requestLog.clear();
|
|
257
|
+
this.keyPolicies.clear();
|
|
258
|
+
this.stopGcTimer();
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
exports.DyNTS_RateLimit_Middleware = DyNTS_RateLimit_Middleware;
|
|
262
|
+
//# sourceMappingURL=rate-limit.middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.middleware.js","sourceRoot":"","sources":["../../../src/_modules/rate-limit/rate-limit.middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.data-service.d.ts","sourceRoot":"","sources":["../../../../src/_modules/server/errors/errors.data-service.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,aAAa,EAEU,UAAU,EAAE,eAAe,EACX,WAAW,EAClD,iBAAiB,EAEjB,UAAU,EAEV,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AAGvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAEzE,qBAAa,wBAAwB,CACnC,OAAO,SAAS,UAAU,EAC1B,cAAc,SAAS,WAAW,CAAC,OAAO,CAAC,CAC3C,SAAQ,iBAAiB,CAAC,cAAc,CAAE,YAAW,2BAA2B,CAAC,OAAO,EAAE,cAAc,CAAC;IAEzG,QAAQ,EAAE,OAAO,CAAS;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAuC;IAC/D,kBAAkB,EAAE,MAAM,CAAC;IAgBrB,WAAW,CACf,YAAY,EAAE,cAAc,EAC5B,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,OAAO,GACrB,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"errors.data-service.d.ts","sourceRoot":"","sources":["../../../../src/_modules/server/errors/errors.data-service.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,aAAa,EAEU,UAAU,EAAE,eAAe,EACX,WAAW,EAClD,iBAAiB,EAEjB,UAAU,EAEV,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AAGvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAEzE,qBAAa,wBAAwB,CACnC,OAAO,SAAS,UAAU,EAC1B,cAAc,SAAS,WAAW,CAAC,OAAO,CAAC,CAC3C,SAAQ,iBAAiB,CAAC,cAAc,CAAE,YAAW,2BAA2B,CAAC,OAAO,EAAE,cAAc,CAAC;IAEzG,QAAQ,EAAE,OAAO,CAAS;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAuC;IAC/D,kBAAkB,EAAE,MAAM,CAAC;IAgBrB,WAAW,CACf,YAAY,EAAE,cAAc,EAC5B,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,OAAO,GACrB,OAAO,CAAC,IAAI,CAAC;cAyKA,iBAAiB,CAC/B,KAAK,EAAE,aAAa,GAAG,GAAG,EAC1B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,cAAc,CAAC;IA2CpB,mBAAmB,CACvB,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,OAAO,GACrB,OAAO,CAAC,IAAI,CAAC;IAoBV,mBAAmB,CACvB,KAAK,EAAE,aAAa,GAAG,GAAG,EAC1B,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,OAAO,GACrB,OAAO,CAAC,IAAI,CAAC;IAwChB,qCAAqC,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,cAAc;IA0C/F,4BAA4B,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM;IAwBtD,iBAAiB,CACrB,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;IAqBhC,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBnF,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBtE,gBAAgB,CAAC,KAAK,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;IAuB/F,cAAc,CAClB,KAAK,EAAE,iBAAiB,EACxB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;IAuBhC,aAAa,CACjB,KAAK,EAAE,iBAAiB,EACxB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;IAyBhC,YAAY,CAChB,WAAW,EAAE,gBAAgB,CAAC,cAAc,CAAC,EAC7C,MAAM,EAAE,MAAM,GACX,OAAO,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC;CAehD"}
|
|
@@ -124,7 +124,15 @@ class DyNTS_Errors_DataService extends data_service_1.DyNTS_DataService {
|
|
|
124
124
|
errorsRecord.versions ??= [];
|
|
125
125
|
errorsRecord.versions.push(errorVersion);
|
|
126
126
|
this.duplicationCounter = 1;
|
|
127
|
-
|
|
127
|
+
// FR-027 (2026-05-24) — Pass `errorsRecord` explicitly. Korabban
|
|
128
|
+
// `saveData()` no-arg fallback `ensureData()`-on keresztul `this.data`-t
|
|
129
|
+
// hasznalt, ami a controller-szinten csak a `{issuer}` constructor
|
|
130
|
+
// wrapper, NEM az actual req.body adat. Eredmenykent minden client-
|
|
131
|
+
// forwarded error EMPTY rekordkent landolt: csak `issuer` mezo,
|
|
132
|
+
// semmilyen message/source/stackTrace/error/level/additionalContent
|
|
133
|
+
// mezo NEM kerult MongoDB-be. (Overseer-en 14454 ilyen empty record
|
|
134
|
+
// halmozodott fel — debug-level details elveszve.)
|
|
135
|
+
await this.saveData(errorsRecord);
|
|
128
136
|
fsm_dynamo_1.DyFM_Log.warn('error saved');
|
|
129
137
|
}
|
|
130
138
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.data-service.js","sourceRoot":"","sources":["../../../../src/_modules/server/errors/errors.data-service.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"errors.data-service.js","sourceRoot":"","sources":["../../../../src/_modules/server/errors/errors.data-service.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@futdevpro/nts-dynamo",
|
|
3
|
-
"version": "01.15.
|
|
3
|
+
"version": "01.15.33",
|
|
4
4
|
"description": "Dynamic NodeTS (NodeJS-Typescript), MongoDB Backend System Framework by Future Development Program Ltd.",
|
|
5
5
|
"DyBu_settings": {
|
|
6
6
|
"packageType": "server-package",
|
|
@@ -190,6 +190,12 @@
|
|
|
190
190
|
"types": "./build/_modules/oauth2/index.d.ts",
|
|
191
191
|
"typings": "./build/_modules/oauth2/index.d.ts"
|
|
192
192
|
},
|
|
193
|
+
"./rate-limit": {
|
|
194
|
+
"default": "./build/_modules/rate-limit/index.js",
|
|
195
|
+
"module": "./build/_modules/rate-limit/index.js",
|
|
196
|
+
"types": "./build/_modules/rate-limit/index.d.ts",
|
|
197
|
+
"typings": "./build/_modules/rate-limit/index.d.ts"
|
|
198
|
+
},
|
|
193
199
|
"./server": {
|
|
194
200
|
"default": "./build/_modules/server/index.js",
|
|
195
201
|
"module": "./build/_modules/server/index.js",
|
|
@@ -277,6 +283,9 @@
|
|
|
277
283
|
"oauth2": [
|
|
278
284
|
"build/_modules/oauth2/index.d.ts"
|
|
279
285
|
],
|
|
286
|
+
"rate-limit": [
|
|
287
|
+
"build/_modules/rate-limit/index.d.ts"
|
|
288
|
+
],
|
|
280
289
|
"server": [
|
|
281
290
|
"build/_modules/server/index.d.ts"
|
|
282
291
|
],
|
|
@@ -299,7 +308,7 @@
|
|
|
299
308
|
"empty": ""
|
|
300
309
|
},
|
|
301
310
|
"peerDependencies": {
|
|
302
|
-
"@futdevpro/fsm-dynamo": "1.15.
|
|
311
|
+
"@futdevpro/fsm-dynamo": "1.15.13",
|
|
303
312
|
"@types/express": "4.17.21",
|
|
304
313
|
"@types/geoip-lite": "~1.4.1",
|
|
305
314
|
"@types/node": "~24.1.0",
|
|
@@ -314,7 +323,7 @@
|
|
|
314
323
|
"ts-node": "~10.9.2"
|
|
315
324
|
},
|
|
316
325
|
"devDependencies": {
|
|
317
|
-
"@futdevpro/dynamo-eslint": "1.15.
|
|
326
|
+
"@futdevpro/dynamo-eslint": "1.15.10",
|
|
318
327
|
"@discordjs/opus": "^0.10.0",
|
|
319
328
|
"@discordjs/voice": "^0.18.0",
|
|
320
329
|
"@types/jasmine": "~4.3.5",
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Request } from 'express';
|
|
2
|
+
|
|
3
|
+
import { DyNTS_RateLimit_Policy } from './rate-limit-policy.interface';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Config a `DyNTS_RateLimit_Middleware.configure(...)`-hoz.
|
|
7
|
+
*
|
|
8
|
+
* Minden mezo opcionalis — a default-ok megfelelnek a tipikus API
|
|
9
|
+
* rate-limit-elvarasoknak (100 req/min, sliding window, IP-alapu kulcs,
|
|
10
|
+
* path-alapu endpoint-csoportositas, X-RateLimit-* response header-ek).
|
|
11
|
+
*/
|
|
12
|
+
export interface DyNTS_RateLimit_Config {
|
|
13
|
+
/**
|
|
14
|
+
* Default request-limit `windowMs` alatt, ha az adott kulcsra nincs
|
|
15
|
+
* `setPolicyForKey()`-szel beallitott egyedi policy. Default: `100`.
|
|
16
|
+
*/
|
|
17
|
+
defaultLimit?: number;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Default sliding-window hossza milliszekundumban. Default: `60000` (1 perc).
|
|
21
|
+
*/
|
|
22
|
+
defaultWindowMs?: number;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Rate-limit subject-extractor. Visszater a karakterlanccal, ami azonositja
|
|
26
|
+
* a rate-limit alanyat (pl. IP-cim, API-kulcs ID, account ID).
|
|
27
|
+
*
|
|
28
|
+
* Default: a `req.headers['x-forwarded-for']` (csak az elso IP, ha lista)
|
|
29
|
+
* vagy ha hianyzik akkor `req.ip` vagy `'unknown'`. Ez webszerver elotti
|
|
30
|
+
* proxy/CDN-mentes setup-ra megfelelo; ha az nd-space mar identifikalja az
|
|
31
|
+
* API-kulcsot a `req`-ben, a host adhat sajat extractort ami a key-ID-t
|
|
32
|
+
* adja vissza.
|
|
33
|
+
*/
|
|
34
|
+
keyExtractor?: (req: Request) => string;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Endpoint-csoportosito. Visszater a karakterlanccal, ami azonositja az
|
|
38
|
+
* adott endpoint-csoportot. A storage-key `${subject}|${endpoint}` lesz.
|
|
39
|
+
*
|
|
40
|
+
* Default: `req.path` — minden uri-path kulon vodorbe kerul. Csoportositas
|
|
41
|
+
* mas szempontok szerint (pl. "datasets" csoport = `/api/datasets/*`)
|
|
42
|
+
* a hostnal felulirhato.
|
|
43
|
+
*/
|
|
44
|
+
endpointGrouper?: (req: Request) => string;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Beallitja-e a `X-RateLimit-Limit`, `X-RateLimit-Remaining`,
|
|
48
|
+
* `X-RateLimit-Reset` (es a 429-re `Retry-After`) response header-eket.
|
|
49
|
+
* Default: `true`.
|
|
50
|
+
*
|
|
51
|
+
* Test/dev kornyezetben opcionalisan kikapcsolhato.
|
|
52
|
+
*/
|
|
53
|
+
responseHeaders?: boolean;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Per-policy override-ok az induloskor. A `setPolicyForKey()` runtime-ban is
|
|
57
|
+
* felulhatja ezeket.
|
|
58
|
+
*/
|
|
59
|
+
initialKeyPolicies?: Record<string, DyNTS_RateLimit_Policy>;
|
|
60
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-kulcs rate-limit policy.
|
|
3
|
+
*
|
|
4
|
+
* A `DyNTS_RateLimit_Middleware.setPolicyForKey(key, policy)` allitja be,
|
|
5
|
+
* vagy a `DyNTS_RateLimit_Config.initialKeyPolicies` map-en at.
|
|
6
|
+
*
|
|
7
|
+
* Tipikus use-case: subscription-tier-up — egy belepett user API-kulcsa
|
|
8
|
+
* magasabb `limit`-et kap, mint a default (anonim/IP-alapu) limit.
|
|
9
|
+
*/
|
|
10
|
+
export interface DyNTS_RateLimit_Policy {
|
|
11
|
+
/** Hany request engedelyezett a `windowMs` alatt. */
|
|
12
|
+
limit: number;
|
|
13
|
+
|
|
14
|
+
/** A sliding-window hossza milliszekundumban. */
|
|
15
|
+
windowMs: number;
|
|
16
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { Request, Response } from 'express';
|
|
2
|
+
|
|
3
|
+
import { DyFM_Error } from '@futdevpro/fsm-dynamo';
|
|
4
|
+
|
|
5
|
+
import { DyNTS_RateLimit_Middleware } from './rate-limit.middleware';
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
/** Test-only — minimal Request mock-ot ad vissza. */
|
|
9
|
+
const mockReq = (overrides: Partial<{ ip: string; path: string; headers: Record<string, string> }> = {}): Request => {
|
|
10
|
+
return {
|
|
11
|
+
ip: overrides.ip ?? '127.0.0.1',
|
|
12
|
+
path: overrides.path ?? '/api/test',
|
|
13
|
+
headers: overrides.headers ?? {},
|
|
14
|
+
} as unknown as Request;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/** Test-only — Response stub a setHeader-rel. */
|
|
18
|
+
const mockRes = (): Response & { _headers: Record<string, string> } => {
|
|
19
|
+
const headers: Record<string, string> = {};
|
|
20
|
+
return {
|
|
21
|
+
_headers: headers,
|
|
22
|
+
setHeader: function(name: string, value: string): void {
|
|
23
|
+
headers[name] = value;
|
|
24
|
+
},
|
|
25
|
+
} as unknown as Response & { _headers: Record<string, string> };
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
describe('| DyNTS_RateLimit_Middleware', (): void => {
|
|
30
|
+
let svc: DyNTS_RateLimit_Middleware;
|
|
31
|
+
|
|
32
|
+
beforeEach((): void => {
|
|
33
|
+
svc = DyNTS_RateLimit_Middleware.getInstance();
|
|
34
|
+
svc._resetForTesting();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
afterEach((): void => {
|
|
38
|
+
svc._resetForTesting();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
describe('| singleton', (): void => {
|
|
43
|
+
it('| ugyanazt az instance-t adja vissza', (): void => {
|
|
44
|
+
const a: DyNTS_RateLimit_Middleware = DyNTS_RateLimit_Middleware.getInstance();
|
|
45
|
+
const b: DyNTS_RateLimit_Middleware = DyNTS_RateLimit_Middleware.getInstance();
|
|
46
|
+
expect(a).toBe(b);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
describe('| check() — default limit', (): void => {
|
|
52
|
+
it('| atengedi az elso request-et', async (): Promise<void> => {
|
|
53
|
+
let thrown: any = null;
|
|
54
|
+
try { await svc.check(mockReq(), mockRes()); } catch (e) { thrown = e; }
|
|
55
|
+
expect(thrown).toBeNull();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('| 429 amikor a limit-et eleri', async (): Promise<void> => {
|
|
59
|
+
svc.configure({ defaultLimit: 3, defaultWindowMs: 10000 });
|
|
60
|
+
|
|
61
|
+
// 3 sikeres request a limit-en belul
|
|
62
|
+
await svc.check(mockReq(), mockRes());
|
|
63
|
+
await svc.check(mockReq(), mockRes());
|
|
64
|
+
await svc.check(mockReq(), mockRes());
|
|
65
|
+
|
|
66
|
+
// 4. request: 429
|
|
67
|
+
let thrown: any = null;
|
|
68
|
+
try { await svc.check(mockReq(), mockRes()); } catch (e) { thrown = e; }
|
|
69
|
+
expect(thrown).not.toBeNull();
|
|
70
|
+
expect(DyFM_Error.getErrorStatus(thrown)).toBe(429);
|
|
71
|
+
expect(DyFM_Error.getErrorCode(thrown)).toContain('DyNTS-RL-LIMIT');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('| kulonbozo IP-k kulon vodorbe kerulnek', async (): Promise<void> => {
|
|
75
|
+
svc.configure({ defaultLimit: 2, defaultWindowMs: 10000 });
|
|
76
|
+
|
|
77
|
+
await svc.check(mockReq({ ip: '1.1.1.1' }), mockRes());
|
|
78
|
+
await svc.check(mockReq({ ip: '1.1.1.1' }), mockRes());
|
|
79
|
+
// 1.1.1.1 most a limit-en van; 2.2.2.2 meg friss
|
|
80
|
+
let thrown: any = null;
|
|
81
|
+
try { await svc.check(mockReq({ ip: '2.2.2.2' }), mockRes()); } catch (e) { thrown = e; }
|
|
82
|
+
expect(thrown).toBeNull();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('| kulonbozo endpoint-ok kulon vodorbe kerulnek', async (): Promise<void> => {
|
|
86
|
+
svc.configure({ defaultLimit: 2, defaultWindowMs: 10000 });
|
|
87
|
+
|
|
88
|
+
await svc.check(mockReq({ path: '/api/a' }), mockRes());
|
|
89
|
+
await svc.check(mockReq({ path: '/api/a' }), mockRes());
|
|
90
|
+
// /api/a most a limit-en van; /api/b meg friss
|
|
91
|
+
let thrown: any = null;
|
|
92
|
+
try { await svc.check(mockReq({ path: '/api/b' }), mockRes()); } catch (e) { thrown = e; }
|
|
93
|
+
expect(thrown).toBeNull();
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
describe('| response headers', (): void => {
|
|
99
|
+
it('| beallitja az X-RateLimit-* header-eket sikeres request-nel', async (): Promise<void> => {
|
|
100
|
+
svc.configure({ defaultLimit: 10, defaultWindowMs: 60000 });
|
|
101
|
+
const res = mockRes();
|
|
102
|
+
await svc.check(mockReq(), res);
|
|
103
|
+
expect(res._headers['X-RateLimit-Limit']).toBe('10');
|
|
104
|
+
expect(res._headers['X-RateLimit-Remaining']).toBe('9');
|
|
105
|
+
expect(res._headers['X-RateLimit-Reset']).toBeDefined();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('| beallitja a Retry-After header-t 429-nel', async (): Promise<void> => {
|
|
109
|
+
svc.configure({ defaultLimit: 1, defaultWindowMs: 10000 });
|
|
110
|
+
await svc.check(mockReq(), mockRes());
|
|
111
|
+
|
|
112
|
+
const res = mockRes();
|
|
113
|
+
let thrown: any = null;
|
|
114
|
+
try { await svc.check(mockReq(), res); } catch (e) { thrown = e; }
|
|
115
|
+
expect(thrown).not.toBeNull();
|
|
116
|
+
expect(res._headers['Retry-After']).toBeDefined();
|
|
117
|
+
expect(res._headers['X-RateLimit-Remaining']).toBe('0');
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('| nem allit be header-t ha responseHeaders=false', async (): Promise<void> => {
|
|
121
|
+
svc.configure({ defaultLimit: 10, defaultWindowMs: 60000, responseHeaders: false });
|
|
122
|
+
const res = mockRes();
|
|
123
|
+
await svc.check(mockReq(), res);
|
|
124
|
+
expect(res._headers['X-RateLimit-Limit']).toBeUndefined();
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
describe('| setPolicyForKey() — subscription-tier-up', (): void => {
|
|
130
|
+
it('| egyedi limit a kulcsra felulhatja a default-ot', async (): Promise<void> => {
|
|
131
|
+
svc.configure({
|
|
132
|
+
defaultLimit: 2,
|
|
133
|
+
defaultWindowMs: 10000,
|
|
134
|
+
keyExtractor: (req: Request): string => (req.headers['x-api-key'] as string) ?? req.ip ?? 'anon',
|
|
135
|
+
});
|
|
136
|
+
svc.setPolicyForKey('premium-key', { limit: 10, windowMs: 10000 });
|
|
137
|
+
|
|
138
|
+
// premium-key 10-et kap
|
|
139
|
+
for (let i: number = 0; i < 10; i++) {
|
|
140
|
+
await svc.check(mockReq({ headers: { 'x-api-key': 'premium-key' } }), mockRes());
|
|
141
|
+
}
|
|
142
|
+
let thrown: any = null;
|
|
143
|
+
try { await svc.check(mockReq({ headers: { 'x-api-key': 'premium-key' } }), mockRes()); } catch (e) { thrown = e; }
|
|
144
|
+
expect(thrown).not.toBeNull();
|
|
145
|
+
expect(DyFM_Error.getErrorStatus(thrown)).toBe(429);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('| clearPolicyForKey visszaallit a default-ra', async (): Promise<void> => {
|
|
149
|
+
svc.configure({
|
|
150
|
+
defaultLimit: 1,
|
|
151
|
+
defaultWindowMs: 10000,
|
|
152
|
+
keyExtractor: (req: Request): string => (req.headers['x-api-key'] as string) ?? 'anon',
|
|
153
|
+
});
|
|
154
|
+
svc.setPolicyForKey('k1', { limit: 5, windowMs: 10000 });
|
|
155
|
+
svc.clearPolicyForKey('k1');
|
|
156
|
+
|
|
157
|
+
// most a default 1-es limit ervenyes
|
|
158
|
+
await svc.check(mockReq({ headers: { 'x-api-key': 'k1' } }), mockRes());
|
|
159
|
+
let thrown: any = null;
|
|
160
|
+
try { await svc.check(mockReq({ headers: { 'x-api-key': 'k1' } }), mockRes()); } catch (e) { thrown = e; }
|
|
161
|
+
expect(thrown).not.toBeNull();
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
describe('| keyExtractor override', (): void => {
|
|
167
|
+
it('| custom keyExtractor felulhatja a default IP-alapu-t', async (): Promise<void> => {
|
|
168
|
+
svc.configure({
|
|
169
|
+
defaultLimit: 1,
|
|
170
|
+
defaultWindowMs: 10000,
|
|
171
|
+
keyExtractor: (req: Request): string => (req.headers['x-api-key'] as string) ?? 'anon',
|
|
172
|
+
});
|
|
173
|
+
// ugyanaz a IP, kulonbozo api-key — kulon limit
|
|
174
|
+
await svc.check(mockReq({ ip: '1.1.1.1', headers: { 'x-api-key': 'k1' } }), mockRes());
|
|
175
|
+
await svc.check(mockReq({ ip: '1.1.1.1', headers: { 'x-api-key': 'k2' } }), mockRes());
|
|
176
|
+
// k1 most a limit-en, k2 meg friss; ujabb k1 → 429
|
|
177
|
+
let thrown: any = null;
|
|
178
|
+
try { await svc.check(mockReq({ ip: '1.1.1.1', headers: { 'x-api-key': 'k1' } }), mockRes()); } catch (e) { thrown = e; }
|
|
179
|
+
expect(thrown).not.toBeNull();
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
describe('| GC', (): void => {
|
|
185
|
+
it('| runGc eltavolitja az ures kulcsokat', async (): Promise<void> => {
|
|
186
|
+
svc.configure({ defaultLimit: 10, defaultWindowMs: 10 }); // 10ms-os window
|
|
187
|
+
await svc.check(mockReq(), mockRes());
|
|
188
|
+
expect(svc.getConfig().trackedStorageKeys).toBe(1);
|
|
189
|
+
|
|
190
|
+
// varjunk meg amig a window lejar
|
|
191
|
+
await new Promise<void>((resolve: () => void): void => { setTimeout(resolve, 50); });
|
|
192
|
+
|
|
193
|
+
svc.runGc();
|
|
194
|
+
expect(svc.getConfig().trackedStorageKeys).toBe(0);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
describe('| getConfig() diagnosztika', (): void => {
|
|
200
|
+
it('| visszaadja az aktualis allapotot', (): void => {
|
|
201
|
+
svc.configure({ defaultLimit: 50, defaultWindowMs: 30000 });
|
|
202
|
+
svc.setPolicyForKey('a', { limit: 100, windowMs: 60000 });
|
|
203
|
+
svc.setPolicyForKey('b', { limit: 200, windowMs: 60000 });
|
|
204
|
+
|
|
205
|
+
const cfg = svc.getConfig();
|
|
206
|
+
expect(cfg.defaultLimit).toBe(50);
|
|
207
|
+
expect(cfg.defaultWindowMs).toBe(30000);
|
|
208
|
+
expect(cfg.activeKeyPolicies).toBe(2);
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
});
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import { Request, Response } from 'express';
|
|
2
|
+
|
|
3
|
+
import { DyFM_Error } from '@futdevpro/fsm-dynamo';
|
|
4
|
+
|
|
5
|
+
import { DyNTS_SingletonServiceBase } from '../../_services/base/singleton.service-base';
|
|
6
|
+
import { DyNTS_global_settings } from '../../_collections/global-settings.const';
|
|
7
|
+
|
|
8
|
+
import { DyNTS_RateLimit_Config } from './_models/rate-limit-config.interface';
|
|
9
|
+
import { DyNTS_RateLimit_Policy } from './_models/rate-limit-policy.interface';
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
/** Default request-limit per default-window. */
|
|
13
|
+
const DEFAULT_LIMIT: number = 100;
|
|
14
|
+
|
|
15
|
+
/** Default sliding-window hossza ms-ben (1 perc). */
|
|
16
|
+
const DEFAULT_WINDOW_MS: number = 60000;
|
|
17
|
+
|
|
18
|
+
/** Default response-header allitas. */
|
|
19
|
+
const DEFAULT_RESPONSE_HEADERS: boolean = true;
|
|
20
|
+
|
|
21
|
+
/** Periodikus garbage-collection intervallum ms-ben (5 perc).
|
|
22
|
+
* A request-log-bol takaritja a regen inaktiv kulcsokat (memory-leak prevention).
|
|
23
|
+
*/
|
|
24
|
+
const GC_INTERVAL_MS: number = 5 * 60 * 1000;
|
|
25
|
+
|
|
26
|
+
/** Service-nev az error-okhoz. */
|
|
27
|
+
const SERVICE_NAME: string = 'DyNTS_RateLimit_Middleware';
|
|
28
|
+
|
|
29
|
+
/** ErrorCode-builder — system shortcode + sajat kod. */
|
|
30
|
+
const buildErrorCode = (subcode: string): string => {
|
|
31
|
+
const sys: string = DyNTS_global_settings.systemShortCodeName ?? 'DyNTS';
|
|
32
|
+
return `${sys}|DyNTS-RL-${subcode}`;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Sliding-window HTTP rate-limit middleware — opt-in service-szel, a meglevo
|
|
38
|
+
* `DyNTS_Endpoint_Params.preProcesses` mechanizmus mellol mukodik.
|
|
39
|
+
*
|
|
40
|
+
* **Hasznalat (host app):**
|
|
41
|
+
* ```ts
|
|
42
|
+
* const rateLimit = DyNTS_RateLimit_Middleware.getInstance();
|
|
43
|
+
* rateLimit.configure({
|
|
44
|
+
* defaultLimit: 100, // 100 req/perc default
|
|
45
|
+
* defaultWindowMs: 60_000,
|
|
46
|
+
* keyExtractor: (req) => req.headers['x-api-key'] as string || req.ip,
|
|
47
|
+
* });
|
|
48
|
+
*
|
|
49
|
+
* new DyNTS_Endpoint_Params({
|
|
50
|
+
* ...,
|
|
51
|
+
* preProcesses: [rateLimit.check, ...other],
|
|
52
|
+
* });
|
|
53
|
+
*
|
|
54
|
+
* // subscription-tier-up: per-kulcs egyedi limit
|
|
55
|
+
* rateLimit.setPolicyForKey('subscriber-tier-key-123', {
|
|
56
|
+
* limit: 1000,
|
|
57
|
+
* windowMs: 60_000,
|
|
58
|
+
* });
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* **Viselkedes:**
|
|
62
|
+
* - Sliding-window algoritmus: minden request egy timestamp; a window-on
|
|
63
|
+
* kivuli timestamp-ek nem szamolnak. Tobb pontos mint a fix-bucket
|
|
64
|
+
* (boundary-burst nincs).
|
|
65
|
+
* - In-memory storage — single-instance MVP-nek megfelelo. Multi-instance
|
|
66
|
+
* prod-hoz Redis-backed extension kell (lasd a kozelebb dokumentumaltot).
|
|
67
|
+
* - Limit lepes: 429 DyFM_Error + `X-RateLimit-*` + `Retry-After` header-ek.
|
|
68
|
+
*
|
|
69
|
+
* **Storage:** `Map<storageKey, timestamps[]>` ahol storageKey = `${subject}|${endpoint}`.
|
|
70
|
+
* Periodikus GC takaritja a inaktiv kulcsokat.
|
|
71
|
+
*
|
|
72
|
+
* **Singleton:** `getInstance()`-szel hivd. A `.check` mezo binding-elve van
|
|
73
|
+
* `this`-re, igy direkt atadhato `preProcesses`-be ujracsomagolas nelkul.
|
|
74
|
+
*/
|
|
75
|
+
export class DyNTS_RateLimit_Middleware extends DyNTS_SingletonServiceBase {
|
|
76
|
+
|
|
77
|
+
static getInstance(): DyNTS_RateLimit_Middleware {
|
|
78
|
+
return DyNTS_RateLimit_Middleware.getSingletonInstance() as DyNTS_RateLimit_Middleware;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private defaultLimit: number = DEFAULT_LIMIT;
|
|
82
|
+
private defaultWindowMs: number = DEFAULT_WINDOW_MS;
|
|
83
|
+
private responseHeaders: boolean = DEFAULT_RESPONSE_HEADERS;
|
|
84
|
+
|
|
85
|
+
private keyExtractor: (req: Request) => string =
|
|
86
|
+
(req: Request): string => this.defaultKeyExtractor(req);
|
|
87
|
+
private endpointGrouper: (req: Request) => string =
|
|
88
|
+
(req: Request): string => req.path;
|
|
89
|
+
|
|
90
|
+
/** request-log: storageKey → timestamp-tomb (Date.now() ms). */
|
|
91
|
+
private requestLog: Map<string, number[]> = new Map();
|
|
92
|
+
|
|
93
|
+
/** Per-kulcs egyedi policy-k. */
|
|
94
|
+
private keyPolicies: Map<string, DyNTS_RateLimit_Policy> = new Map();
|
|
95
|
+
|
|
96
|
+
/** GC timer handle. */
|
|
97
|
+
private gcTimer: NodeJS.Timeout | null = null;
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Konfig override. Hianyzo mezok a default-okat orzik. Hivhato barmikor —
|
|
102
|
+
* a `check()` a friss config-ot olvassa.
|
|
103
|
+
*/
|
|
104
|
+
configure(config: DyNTS_RateLimit_Config): void {
|
|
105
|
+
if (config.defaultLimit !== undefined) {
|
|
106
|
+
this.defaultLimit = config.defaultLimit;
|
|
107
|
+
}
|
|
108
|
+
if (config.defaultWindowMs !== undefined) {
|
|
109
|
+
this.defaultWindowMs = config.defaultWindowMs;
|
|
110
|
+
}
|
|
111
|
+
if (config.keyExtractor !== undefined) {
|
|
112
|
+
this.keyExtractor = config.keyExtractor;
|
|
113
|
+
}
|
|
114
|
+
if (config.endpointGrouper !== undefined) {
|
|
115
|
+
this.endpointGrouper = config.endpointGrouper;
|
|
116
|
+
}
|
|
117
|
+
if (config.responseHeaders !== undefined) {
|
|
118
|
+
this.responseHeaders = config.responseHeaders;
|
|
119
|
+
}
|
|
120
|
+
if (config.initialKeyPolicies !== undefined) {
|
|
121
|
+
for (const [ key, policy ] of Object.entries(config.initialKeyPolicies)) {
|
|
122
|
+
this.keyPolicies.set(key, policy);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
this.startGcTimer();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Aktualis konfig olvasasa (diagnosztika celokra).
|
|
130
|
+
*/
|
|
131
|
+
getConfig(): {
|
|
132
|
+
defaultLimit: number;
|
|
133
|
+
defaultWindowMs: number;
|
|
134
|
+
responseHeaders: boolean;
|
|
135
|
+
activeKeyPolicies: number;
|
|
136
|
+
trackedStorageKeys: number;
|
|
137
|
+
} {
|
|
138
|
+
return {
|
|
139
|
+
defaultLimit: this.defaultLimit,
|
|
140
|
+
defaultWindowMs: this.defaultWindowMs,
|
|
141
|
+
responseHeaders: this.responseHeaders,
|
|
142
|
+
activeKeyPolicies: this.keyPolicies.size,
|
|
143
|
+
trackedStorageKeys: this.requestLog.size,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Per-kulcs egyedi policy beallitas (pl. subscription-tier alapjan).
|
|
149
|
+
* A `key`-nek pontosan azzal a stringgel kell egyeznie, amit a `keyExtractor`
|
|
150
|
+
* visszaad.
|
|
151
|
+
*/
|
|
152
|
+
setPolicyForKey(key: string, policy: DyNTS_RateLimit_Policy): void {
|
|
153
|
+
this.keyPolicies.set(key, policy);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Per-kulcs policy torlese (visszaall a default-ra).
|
|
158
|
+
*/
|
|
159
|
+
clearPolicyForKey(key: string): void {
|
|
160
|
+
this.keyPolicies.delete(key);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Pre-process function — atadhato `DyNTS_Endpoint_Params.preProcesses`-be.
|
|
166
|
+
*
|
|
167
|
+
* Throws:
|
|
168
|
+
* - 429 ha az aktualis request meghaladna a limit-et a sliding window-on
|
|
169
|
+
*
|
|
170
|
+
* Side-effect: ha `responseHeaders === true`, beallitja az `X-RateLimit-Limit`,
|
|
171
|
+
* `X-RateLimit-Remaining`, `X-RateLimit-Reset` header-eket; 429 eseten
|
|
172
|
+
* a `Retry-After` header-t is.
|
|
173
|
+
*/
|
|
174
|
+
readonly check = async (req: Request, res: Response): Promise<void> => {
|
|
175
|
+
const subject: string = this.keyExtractor(req);
|
|
176
|
+
const endpoint: string = this.endpointGrouper(req);
|
|
177
|
+
const storageKey: string = `${subject}|${endpoint}`;
|
|
178
|
+
|
|
179
|
+
const policy: DyNTS_RateLimit_Policy = this.keyPolicies.get(subject) ?? {
|
|
180
|
+
limit: this.defaultLimit,
|
|
181
|
+
windowMs: this.defaultWindowMs,
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const now: number = Date.now();
|
|
185
|
+
const windowStart: number = now - policy.windowMs;
|
|
186
|
+
|
|
187
|
+
// sliding-window: tartomanyon kivuli timestamp-eket eldobjuk
|
|
188
|
+
const existing: number[] = this.requestLog.get(storageKey) ?? [];
|
|
189
|
+
const recent: number[] = existing.filter((t: number): boolean => t > windowStart);
|
|
190
|
+
|
|
191
|
+
if (recent.length >= policy.limit) {
|
|
192
|
+
const oldest: number = recent[0];
|
|
193
|
+
const resetAt: number = oldest + policy.windowMs;
|
|
194
|
+
const retryAfterSec: number = Math.max(1, Math.ceil((resetAt - now) / 1000));
|
|
195
|
+
|
|
196
|
+
if (this.responseHeaders) {
|
|
197
|
+
res.setHeader('X-RateLimit-Limit', policy.limit.toString());
|
|
198
|
+
res.setHeader('X-RateLimit-Remaining', '0');
|
|
199
|
+
res.setHeader('X-RateLimit-Reset', Math.ceil(resetAt / 1000).toString());
|
|
200
|
+
res.setHeader('Retry-After', retryAfterSec.toString());
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Frissitjuk a log-ot a kiszurt verzioval (felesleges regi timestamp-eket eldobtuk)
|
|
204
|
+
this.requestLog.set(storageKey, recent);
|
|
205
|
+
|
|
206
|
+
throw new DyFM_Error({
|
|
207
|
+
status: 429,
|
|
208
|
+
errorCode: buildErrorCode('LIMIT'),
|
|
209
|
+
addECToUserMsg: true,
|
|
210
|
+
message: `Rate limit exceeded: ${policy.limit} req per ${policy.windowMs}ms for ${storageKey}`,
|
|
211
|
+
userMessage: `Too many requests, retry after ${retryAfterSec}s`,
|
|
212
|
+
issuerService: SERVICE_NAME,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// alatta vagyunk a limit-nek: append the current request
|
|
217
|
+
recent.push(now);
|
|
218
|
+
this.requestLog.set(storageKey, recent);
|
|
219
|
+
|
|
220
|
+
if (this.responseHeaders) {
|
|
221
|
+
res.setHeader('X-RateLimit-Limit', policy.limit.toString());
|
|
222
|
+
res.setHeader('X-RateLimit-Remaining', Math.max(0, policy.limit - recent.length).toString());
|
|
223
|
+
res.setHeader('X-RateLimit-Reset', Math.ceil((now + policy.windowMs) / 1000).toString());
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Default key-extractor: x-forwarded-for vagy req.ip vagy 'unknown'.
|
|
230
|
+
* Csak akkor hasznalt, ha a host nem allit be sajat extractort a configure-ben.
|
|
231
|
+
*/
|
|
232
|
+
private defaultKeyExtractor(req: Request): string {
|
|
233
|
+
const xff: unknown = req.headers['x-forwarded-for'];
|
|
234
|
+
if (typeof xff === 'string' && xff.length > 0) {
|
|
235
|
+
const first: string = xff.split(',')[0]?.trim() ?? '';
|
|
236
|
+
if (first.length > 0) {
|
|
237
|
+
return first;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (Array.isArray(xff) && xff.length > 0) {
|
|
241
|
+
const first: string = xff[0]?.split(',')[0]?.trim() ?? '';
|
|
242
|
+
if (first.length > 0) {
|
|
243
|
+
return first;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return req.ip ?? 'unknown';
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* GC timer inditasa (idempotent). Periodikusan eltavolitja az inaktiv
|
|
252
|
+
* storage-key-eket a request-log-bol — memory-leak prevention.
|
|
253
|
+
*/
|
|
254
|
+
private startGcTimer(): void {
|
|
255
|
+
if (this.gcTimer !== null) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
this.gcTimer = setInterval((): void => {
|
|
259
|
+
this.runGc();
|
|
260
|
+
}, GC_INTERVAL_MS);
|
|
261
|
+
// unref hogy a process ne maradjon eletben a timer miatt
|
|
262
|
+
if (typeof this.gcTimer.unref === 'function') {
|
|
263
|
+
this.gcTimer.unref();
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* GC sweep — minden storage-key-rol levagja a regi timestamp-eket, es
|
|
269
|
+
* eltavolitja az ureseket. Hivhato kulonosen test-bol.
|
|
270
|
+
*/
|
|
271
|
+
runGc(): void {
|
|
272
|
+
const now: number = Date.now();
|
|
273
|
+
const horizon: number = now - this.defaultWindowMs;
|
|
274
|
+
|
|
275
|
+
for (const [ key, timestamps ] of this.requestLog) {
|
|
276
|
+
const recent: number[] = timestamps.filter((t: number): boolean => t > horizon);
|
|
277
|
+
if (recent.length === 0) {
|
|
278
|
+
this.requestLog.delete(key);
|
|
279
|
+
} else {
|
|
280
|
+
this.requestLog.set(key, recent);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* GC timer leallitasa (graceful shutdown vagy test-cleanup).
|
|
287
|
+
*/
|
|
288
|
+
stopGcTimer(): void {
|
|
289
|
+
if (this.gcTimer !== null) {
|
|
290
|
+
clearInterval(this.gcTimer);
|
|
291
|
+
this.gcTimer = null;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Test-only: visszaallitja a default config-ot + uriti a state-et, hogy a
|
|
298
|
+
* specfajlok ne szivarogjak at egymas state-jet. Production code NE hivja.
|
|
299
|
+
*/
|
|
300
|
+
_resetForTesting(): void {
|
|
301
|
+
this.defaultLimit = DEFAULT_LIMIT;
|
|
302
|
+
this.defaultWindowMs = DEFAULT_WINDOW_MS;
|
|
303
|
+
this.responseHeaders = DEFAULT_RESPONSE_HEADERS;
|
|
304
|
+
this.keyExtractor = (req: Request): string => this.defaultKeyExtractor(req);
|
|
305
|
+
this.endpointGrouper = (req: Request): string => req.path;
|
|
306
|
+
this.requestLog.clear();
|
|
307
|
+
this.keyPolicies.clear();
|
|
308
|
+
this.stopGcTimer();
|
|
309
|
+
}
|
|
310
|
+
}
|
|
@@ -178,7 +178,7 @@ export class DyNTS_Errors_DataService<
|
|
|
178
178
|
if (this.debugLog) DyFM_Log.error('Error:', errorsRecord);
|
|
179
179
|
|
|
180
180
|
errorsRecord.priority = this.getPriorityMultiplierByLevel(errorsRecord?.level);
|
|
181
|
-
|
|
181
|
+
|
|
182
182
|
errorsRecord.duplications ??= [];
|
|
183
183
|
errorsRecord.duplications.push(DyFM_Object.clone(errorsRecord));
|
|
184
184
|
|
|
@@ -187,7 +187,15 @@ export class DyNTS_Errors_DataService<
|
|
|
187
187
|
|
|
188
188
|
this.duplicationCounter = 1;
|
|
189
189
|
|
|
190
|
-
|
|
190
|
+
// FR-027 (2026-05-24) — Pass `errorsRecord` explicitly. Korabban
|
|
191
|
+
// `saveData()` no-arg fallback `ensureData()`-on keresztul `this.data`-t
|
|
192
|
+
// hasznalt, ami a controller-szinten csak a `{issuer}` constructor
|
|
193
|
+
// wrapper, NEM az actual req.body adat. Eredmenykent minden client-
|
|
194
|
+
// forwarded error EMPTY rekordkent landolt: csak `issuer` mezo,
|
|
195
|
+
// semmilyen message/source/stackTrace/error/level/additionalContent
|
|
196
|
+
// mezo NEM kerult MongoDB-be. (Overseer-en 14454 ilyen empty record
|
|
197
|
+
// halmozodott fel — debug-level details elveszve.)
|
|
198
|
+
await this.saveData(errorsRecord);
|
|
191
199
|
DyFM_Log.warn('error saved');
|
|
192
200
|
}
|
|
193
201
|
} catch (error) {
|