@prosopo/cli 3.6.64 → 3.6.65
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/.turbo/turbo-build$colon$cjs.log +2 -2
- package/.turbo/turbo-build$colon$tsc.log +27 -27
- package/.turbo/turbo-build.log +3 -3
- package/CHANGELOG.md +29 -0
- package/dist/bundle/provider.cli.bundle.js +1 -1
- package/dist/tests/RateLimiter.unit.test.d.ts +2 -0
- package/dist/tests/RateLimiter.unit.test.d.ts.map +1 -0
- package/dist/tests/RateLimiter.unit.test.js +161 -0
- package/dist/tests/RateLimiter.unit.test.js.map +1 -0
- package/dist/tests/commands/validators.unit.test.d.ts +2 -0
- package/dist/tests/commands/validators.unit.test.d.ts.map +1 -0
- package/dist/tests/commands/validators.unit.test.js +84 -0
- package/dist/tests/commands/validators.unit.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/cli@3.6.
|
|
2
|
+
> @prosopo/cli@3.6.65 build:cjs
|
|
3
3
|
> NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV
|
|
4
4
|
|
|
5
5
|
ViteCommonJSConfig: .
|
|
@@ -80,4 +80,4 @@ rendering chunks...
|
|
|
80
80
|
[2mdist/cjs/[22m[36mcommands/siteKeyRegister.cjs [39m[1m[2m3.81 kB[22m[1m[22m
|
|
81
81
|
[2mdist/cjs/[22m[36mprosopo.config.cjs [39m[1m[2m5.29 kB[22m[1m[22m
|
|
82
82
|
[2mdist/cjs/[22m[36mRateLimiter.cjs [39m[1m[2m5.48 kB[22m[1m[22m
|
|
83
|
-
[32m✓ built in
|
|
83
|
+
[32m✓ built in 197ms[39m
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/cli@3.6.
|
|
2
|
+
> @prosopo/cli@3.6.65 build:tsc
|
|
3
3
|
> tsc --build --verbose
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
9:22:49 AM - Projects in this build:
|
|
6
6
|
* ../../dev/config/tsconfig.json
|
|
7
7
|
* ../locale/tsconfig.json
|
|
8
8
|
* ../util/tsconfig.json
|
|
@@ -28,53 +28,53 @@
|
|
|
28
28
|
* ../../dev/workspace/tsconfig.json
|
|
29
29
|
* tsconfig.json
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
9:22:49 AM - Project '../../dev/config/tsconfig.json' is up to date because newest input '../../dev/config/src/webpack/webpack.config.ts' is older than output '../../dev/config/tsconfig.tsbuildinfo'
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
9:22:49 AM - Project '../locale/tsconfig.json' is up to date because newest input '../locale/src/translationKey.ts' is older than output '../locale/tsconfig.tsbuildinfo'
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
9:22:49 AM - Project '../util/tsconfig.json' is up to date because newest input '../util/src/url.ts' is older than output '../util/tsconfig.tsbuildinfo'
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
9:22:49 AM - Project '../util-crypto/tsconfig.json' is up to date because newest input '../util-crypto/src/types.ts' is older than output '../util-crypto/tsconfig.tsbuildinfo'
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
9:22:49 AM - Project '../types/tsconfig.json' is up to date because newest input '../types/src/keyring/keyring/types.ts' is older than output '../types/tsconfig.tsbuildinfo'
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
9:22:49 AM - Project '../api/tsconfig.json' is up to date because newest input '../api/src/index.ts' is older than output '../api/tsconfig.tsbuildinfo'
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
9:22:49 AM - Project '../logger/tsconfig.json' is up to date because newest input '../logger/src/index.ts' is older than output '../logger/tsconfig.tsbuildinfo'
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
9:22:49 AM - Project '../common/tsconfig.json' is up to date because newest input '../common/src/error.ts' is older than output '../common/tsconfig.tsbuildinfo'
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
9:22:49 AM - Project '../dotenv/tsconfig.json' is up to date because newest input '../dotenv/src/env.ts' is older than output '../dotenv/tsconfig.tsbuildinfo'
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
9:22:49 AM - Project '../ipinfo/tsconfig.json' is up to date because newest input '../ipinfo/src/index.ts' is older than output '../ipinfo/tsconfig.tsbuildinfo'
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
9:22:49 AM - Project '../api-route/tsconfig.json' is up to date because newest input '../api-route/src/apiRoutes.ts' is older than output '../api-route/tsconfig.tsbuildinfo'
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
9:22:49 AM - Project '../redis-client/tsconfig.json' is up to date because newest input '../redis-client/src/index.ts' is older than output '../redis-client/tsconfig.tsbuildinfo'
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
9:22:49 AM - Project '../user-access-policy/tsconfig.json' is up to date because newest input '../user-access-policy/src/transformRule.ts' is older than output '../user-access-policy/tsconfig.tsbuildinfo'
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
9:22:49 AM - Project '../types-database/tsconfig.json' is up to date because newest input '../types-database/src/types/captcha.ts' is older than output '../types-database/tsconfig.tsbuildinfo'
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
9:22:49 AM - Project '../database/tsconfig.json' is up to date because newest input '../database/src/tests/unit/redisCacheEscalation.unit.test.ts' is older than output '../database/tsconfig.tsbuildinfo'
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
9:22:49 AM - Project '../keyring/tsconfig.json' is up to date because newest input '../keyring/src/keyring/keyring.ts' is older than output '../keyring/tsconfig.tsbuildinfo'
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
9:22:49 AM - Project '../types-env/tsconfig.json' is up to date because newest input '../types-env/src/index.ts' is older than output '../types-env/tsconfig.tsbuildinfo'
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
9:22:49 AM - Project '../env/tsconfig.json' is up to date because newest input '../env/src/index.ts' is older than output '../env/tsconfig.tsbuildinfo'
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
9:22:49 AM - Project '../api-express-router/tsconfig.json' is up to date because newest input '../api-express-router/src/errorHandler.ts' is older than output '../api-express-router/tsconfig.tsbuildinfo'
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
9:22:49 AM - Project '../datasets/tsconfig.json' is up to date because newest input '../datasets/src/tests/dataset.unit.test.ts' is older than output '../datasets/tsconfig.tsbuildinfo'
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
9:22:49 AM - Project '../load-balancer/tsconfig.json' is up to date because newest input '../load-balancer/src/index.ts' is older than output '../load-balancer/tsconfig.tsbuildinfo'
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
9:22:50 AM - Project '../provider/tsconfig.json' is up to date because newest input '../provider/src/util.ts' is older than output '../provider/tsconfig.tsbuildinfo'
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
9:22:50 AM - Project '../../dev/workspace/tsconfig.json' is up to date because newest input '../../dev/workspace/src/index.ts' is older than output '../../dev/workspace/tsconfig.tsbuildinfo'
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
9:22:50 AM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
9:22:50 AM - Building project '/home/runner/work/captcha/captcha/packages/cli/tsconfig.json'...
|
|
80
80
|
|
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/cli@3.6.
|
|
2
|
+
> @prosopo/cli@3.6.65 build
|
|
3
3
|
> npm run build:cross-env -- --mode ${NODE_ENV:-development}
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
> @prosopo/cli@3.6.
|
|
6
|
+
> @prosopo/cli@3.6.65 build:cross-env
|
|
7
7
|
> vite build --config vite.esm.config.ts --mode production
|
|
8
8
|
|
|
9
9
|
ViteEsmConfig: .
|
|
@@ -83,4 +83,4 @@ rendering chunks...
|
|
|
83
83
|
[2mdist/[22m[36mcommands/siteKeyRegister.js [39m[1m[2m3.67 kB[22m[1m[22m
|
|
84
84
|
[2mdist/[22m[36mprosopo.config.js [39m[1m[2m4.91 kB[22m[1m[22m
|
|
85
85
|
[2mdist/[22m[36mRateLimiter.js [39m[1m[2m5.25 kB[22m[1m[22m
|
|
86
|
-
[32m✓ built in
|
|
86
|
+
[32m✓ built in 357ms[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# @prosopo/cli
|
|
2
2
|
|
|
3
|
+
## 3.6.65
|
|
4
|
+
### Patch Changes
|
|
5
|
+
|
|
6
|
+
- 6855422: test(cli): unit-test coverage for `RateLimiter.getRateLimitConfig` and `commands/validators`
|
|
7
|
+
|
|
8
|
+
Adds two new vitest files under `@prosopo/cli/src/tests/`:
|
|
9
|
+
|
|
10
|
+
- `RateLimiter.unit.test.ts` — 7 tests covering `getRateLimitConfig`:
|
|
11
|
+
every ClientApiPaths / AdminApiPaths / PublicApiPaths route referenced in
|
|
12
|
+
the source has a mapped entry (regression guard against silently dropping
|
|
13
|
+
routes on refactor); env vars are propagated verbatim to `windowMs` /
|
|
14
|
+
`limit`; no WINDOW/LIMIT crossover; and the config is re-read on every
|
|
15
|
+
invocation rather than cached at module load (so ops can hot-toggle a
|
|
16
|
+
rate window without restarting the provider). Snapshots and restores
|
|
17
|
+
every `PROSOPO_*` env var it touches so the suite doesn't leak state.
|
|
18
|
+
|
|
19
|
+
- `commands/validators.unit.test.ts` — 14 tests covering the four
|
|
20
|
+
argv validators: `validateAddress`, `validateSiteKey`, `validateValue`,
|
|
21
|
+
`validateScheduleExpression`. Verifies SS58 ↔ hex address round-tripping
|
|
22
|
+
through `encodeStringAddress`; `ProsopoContractError` with
|
|
23
|
+
`CONTRACT.INVALID_ADDRESS` on garbage address input;
|
|
24
|
+
`ProsopoEnvError` with `CLI.PARAMETER_ERROR` for non-numeric values
|
|
25
|
+
(string, boolean, object, null, undefined); and cron parsing across a
|
|
26
|
+
spread of standard schedule expressions.
|
|
27
|
+
|
|
28
|
+
No behaviour change — pure test additions. Fills a coverage gap in a
|
|
29
|
+
package that previously had a single integration-style bundle test and
|
|
30
|
+
no unit tests for these pure helpers.
|
|
31
|
+
|
|
3
32
|
## 3.6.64
|
|
4
33
|
### Patch Changes
|
|
5
34
|
|
|
@@ -1782,7 +1782,7 @@ function zr(e, t, r) {
|
|
|
1782
1782
|
throw new Error(`Index ${t} smaller than 0`);
|
|
1783
1783
|
return e[t];
|
|
1784
1784
|
}
|
|
1785
|
-
const MMe = typeof process < "u" ? "3.6.
|
|
1785
|
+
const MMe = typeof process < "u" ? "3.6.65" : void 0, xve = MMe || "dev", j6 = new Array(256), Lve = new Array(256 * 256);
|
|
1786
1786
|
for (let e = 0; e < 256; e++)
|
|
1787
1787
|
j6[e] = e.toString(16).padStart(2, "0");
|
|
1788
1788
|
for (let e = 0; e < 256; e++) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimiter.unit.test.d.ts","sourceRoot":"","sources":["../../src/tests/RateLimiter.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { AdminApiPaths, ClientApiPaths, PublicApiPaths } from "@prosopo/types";
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
3
|
+
import { getRateLimitConfig } from "../RateLimiter.js";
|
|
4
|
+
const RATE_ENV_KEYS = [
|
|
5
|
+
"PROSOPO_GET_IMAGE_CAPTCHA_CHALLENGE_WINDOW",
|
|
6
|
+
"PROSOPO_GET_IMAGE_CAPTCHA_CHALLENGE_LIMIT",
|
|
7
|
+
"PROSOPO_GET_POW_CAPTCHA_CHALLENGE_WINDOW",
|
|
8
|
+
"PROSOPO_GET_POW_CAPTCHA_CHALLENGE_LIMIT",
|
|
9
|
+
"PROSOPO_SUBMIT_IMAGE_CAPTCHA_SOLUTION_WINDOW",
|
|
10
|
+
"PROSOPO_SUBMIT_IMAGE_CAPTCHA_SOLUTION_LIMIT",
|
|
11
|
+
"PROSOPO_SUBMIT_POW_CAPTCHA_SOLUTION_WINDOW",
|
|
12
|
+
"PROSOPO_SUBMIT_POW_CAPTCHA_SOLUTION_LIMIT",
|
|
13
|
+
"PROSOPO_VERIFY_POW_CAPTCHA_SOLUTION_WINDOW",
|
|
14
|
+
"PROSOPO_VERIFY_POW_CAPTCHA_SOLUTION_LIMIT",
|
|
15
|
+
"PROSOPO_VERIFY_IMAGE_CAPTCHA_SOLUTION_DAPP_WINDOW",
|
|
16
|
+
"PROSOPO_VERIFY_IMAGE_CAPTCHA_SOLUTION_DAPP_LIMIT",
|
|
17
|
+
"PROSOPO_CHECK_SPAM_EMAIL_WINDOW",
|
|
18
|
+
"PROSOPO_CHECK_SPAM_EMAIL_LIMIT",
|
|
19
|
+
"PROSOPO_GET_PROVIDER_STATUS_WINDOW",
|
|
20
|
+
"PROSOPO_GET_PROVIDER_STATUS_LIMIT",
|
|
21
|
+
"PROSOPO_GET_PROVIDER_DETAILS_WINDOW",
|
|
22
|
+
"PROSOPO_GET_PROVIDER_DETAILS_LIMIT",
|
|
23
|
+
"PROSOPO_SUBMIT_USER_EVENTS_WINDOW",
|
|
24
|
+
"PROSOPO_SUBMIT_USER_EVENTS_LIMIT",
|
|
25
|
+
"PROSOPO_SITE_KEY_REGISTER_WINDOW",
|
|
26
|
+
"PROSOPO_SITE_KEY_REGISTER_LIMIT",
|
|
27
|
+
"PROSOPO_SITE_KEYS_REGISTER_WINDOW",
|
|
28
|
+
"PROSOPO_SITE_KEYS_REGISTER_LIMIT",
|
|
29
|
+
"PROSOPO_SITE_KEY_REMOVE_WINDOW",
|
|
30
|
+
"PROSOPO_SITE_KEY_REMOVE_LIMIT",
|
|
31
|
+
"PROSOPO_SITE_KEYS_REMOVE_WINDOW",
|
|
32
|
+
"PROSOPO_SITE_KEYS_REMOVE_LIMIT",
|
|
33
|
+
"PROSOPO_UPDATE_DETECTOR_KEY_WINDOW",
|
|
34
|
+
"PROSOPO_UPDATE_DETECTOR_KEY_LIMIT",
|
|
35
|
+
"PROSOPO_REMOVE_DETECTOR_KEY_WINDOW",
|
|
36
|
+
"PROSOPO_REMOVE_DETECTOR_KEY_LIMIT",
|
|
37
|
+
"PROSOPO_TOGGLE_MAINTENANCE_MODE_WINDOW",
|
|
38
|
+
"PROSOPO_TOGGLE_MAINTENANCE_MODE_LIMIT",
|
|
39
|
+
"PROSOPO_UPDATE_DECISION_MACHINE_WINDOW",
|
|
40
|
+
"PROSOPO_UPDATE_DECISION_MACHINE_LIMIT",
|
|
41
|
+
"PROSOPO_GET_FR_CAPTCHA_CHALLENGE_WINDOW",
|
|
42
|
+
"PROSOPO_GET_FR_CAPTCHA_CHALLENGE_LIMIT",
|
|
43
|
+
"PROSOPO_GET_DECISION_MACHINE_WINDOW",
|
|
44
|
+
"PROSOPO_GET_DECISION_MACHINE_LIMIT",
|
|
45
|
+
"PROSOPO_GET_ALL_DECISION_MACHINES_WINDOW",
|
|
46
|
+
"PROSOPO_GET_ALL_DECISION_MACHINES_LIMIT",
|
|
47
|
+
"PROSOPO_REMOVE_ALL_DECISION_MACHINES_WINDOW",
|
|
48
|
+
"PROSOPO_REMOVE_ALL_DECISION_MACHINES_LIMIT",
|
|
49
|
+
"PROSOPO_REMOVE_DECISION_MACHINE_WINDOW",
|
|
50
|
+
"PROSOPO_REMOVE_DECISION_MACHINE_LIMIT",
|
|
51
|
+
"PROSOPO_CLEAR_ALL_COUNTERS_WINDOW",
|
|
52
|
+
"PROSOPO_CLEAR_ALL_COUNTERS_LIMIT",
|
|
53
|
+
"PROSOPO_GET_PUZZLE_CAPTCHA_CHALLENGE_WINDOW",
|
|
54
|
+
"PROSOPO_GET_PUZZLE_CAPTCHA_CHALLENGE_LIMIT",
|
|
55
|
+
"PROSOPO_SUBMIT_PUZZLE_CAPTCHA_SOLUTION_WINDOW",
|
|
56
|
+
"PROSOPO_SUBMIT_PUZZLE_CAPTCHA_SOLUTION_LIMIT",
|
|
57
|
+
"PROSOPO_VERIFY_PUZZLE_CAPTCHA_SOLUTION_WINDOW",
|
|
58
|
+
"PROSOPO_VERIFY_PUZZLE_CAPTCHA_SOLUTION_LIMIT",
|
|
59
|
+
"PROSOPO_DNS_EVENT_WINDOW",
|
|
60
|
+
"PROSOPO_DNS_EVENT_LIMIT",
|
|
61
|
+
];
|
|
62
|
+
describe("RateLimiter.getRateLimitConfig", () => {
|
|
63
|
+
const originalEnv = {};
|
|
64
|
+
beforeEach(() => {
|
|
65
|
+
for (const key of RATE_ENV_KEYS) {
|
|
66
|
+
originalEnv[key] = process.env[key];
|
|
67
|
+
delete process.env[key];
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
afterEach(() => {
|
|
71
|
+
for (const key of RATE_ENV_KEYS) {
|
|
72
|
+
if (originalEnv[key] === undefined) {
|
|
73
|
+
delete process.env[key];
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
process.env[key] = originalEnv[key];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
it("returns undefined windowMs/limit for every route when no env vars are set", () => {
|
|
81
|
+
const cfg = getRateLimitConfig();
|
|
82
|
+
for (const [route, entry] of Object.entries(cfg)) {
|
|
83
|
+
expect(entry.windowMs, `${route}.windowMs should be undefined when env missing`).toBeUndefined();
|
|
84
|
+
expect(entry.limit, `${route}.limit should be undefined when env missing`).toBeUndefined();
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
it("exposes an entry for every ClientApiPaths route referenced in the source", () => {
|
|
88
|
+
const cfg = getRateLimitConfig();
|
|
89
|
+
const expected = [
|
|
90
|
+
ClientApiPaths.GetImageCaptchaChallenge,
|
|
91
|
+
ClientApiPaths.GetPowCaptchaChallenge,
|
|
92
|
+
ClientApiPaths.SubmitImageCaptchaSolution,
|
|
93
|
+
ClientApiPaths.SubmitPowCaptchaSolution,
|
|
94
|
+
ClientApiPaths.VerifyPowCaptchaSolution,
|
|
95
|
+
ClientApiPaths.VerifyImageCaptchaSolutionDapp,
|
|
96
|
+
ClientApiPaths.CheckSpamEmail,
|
|
97
|
+
ClientApiPaths.GetProviderStatus,
|
|
98
|
+
ClientApiPaths.SubmitUserEvents,
|
|
99
|
+
ClientApiPaths.GetFrictionlessCaptchaChallenge,
|
|
100
|
+
ClientApiPaths.GetPuzzleCaptchaChallenge,
|
|
101
|
+
ClientApiPaths.SubmitPuzzleCaptchaSolution,
|
|
102
|
+
ClientApiPaths.VerifyPuzzleCaptchaSolution,
|
|
103
|
+
];
|
|
104
|
+
for (const route of expected) {
|
|
105
|
+
expect(cfg).toHaveProperty(route);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
it("exposes an entry for every AdminApiPaths route referenced in the source", () => {
|
|
109
|
+
const cfg = getRateLimitConfig();
|
|
110
|
+
const expected = [
|
|
111
|
+
AdminApiPaths.SiteKeyRegister,
|
|
112
|
+
AdminApiPaths.SiteKeysRegister,
|
|
113
|
+
AdminApiPaths.SiteKeyRemove,
|
|
114
|
+
AdminApiPaths.SiteKeysRemove,
|
|
115
|
+
AdminApiPaths.UpdateDetectorKey,
|
|
116
|
+
AdminApiPaths.RemoveDetectorKey,
|
|
117
|
+
AdminApiPaths.ToggleMaintenanceMode,
|
|
118
|
+
AdminApiPaths.UpdateDecisionMachine,
|
|
119
|
+
AdminApiPaths.GetDecisionMachine,
|
|
120
|
+
AdminApiPaths.GetAllDecisionMachines,
|
|
121
|
+
AdminApiPaths.RemoveAllDecisionMachines,
|
|
122
|
+
AdminApiPaths.RemoveDecisionMachine,
|
|
123
|
+
AdminApiPaths.ClearAllCounters,
|
|
124
|
+
AdminApiPaths.DnsEvent,
|
|
125
|
+
];
|
|
126
|
+
for (const route of expected) {
|
|
127
|
+
expect(cfg).toHaveProperty(route);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
it("exposes an entry for every PublicApiPaths route referenced in the source", () => {
|
|
131
|
+
const cfg = getRateLimitConfig();
|
|
132
|
+
expect(cfg).toHaveProperty(PublicApiPaths.GetProviderDetails);
|
|
133
|
+
});
|
|
134
|
+
it("propagates env vars verbatim to the mapped route (strings)", () => {
|
|
135
|
+
process.env.PROSOPO_GET_IMAGE_CAPTCHA_CHALLENGE_WINDOW = "60000";
|
|
136
|
+
process.env.PROSOPO_GET_IMAGE_CAPTCHA_CHALLENGE_LIMIT = "10";
|
|
137
|
+
const cfg = getRateLimitConfig();
|
|
138
|
+
expect(cfg[ClientApiPaths.GetImageCaptchaChallenge]).toEqual({
|
|
139
|
+
windowMs: "60000",
|
|
140
|
+
limit: "10",
|
|
141
|
+
});
|
|
142
|
+
expect(cfg[ClientApiPaths.CheckSpamEmail].windowMs).toBeUndefined();
|
|
143
|
+
expect(cfg[ClientApiPaths.CheckSpamEmail].limit).toBeUndefined();
|
|
144
|
+
});
|
|
145
|
+
it("wires WINDOW and LIMIT env vars to distinct fields (no crossover)", () => {
|
|
146
|
+
process.env.PROSOPO_CHECK_SPAM_EMAIL_WINDOW = "WINDOW_MARKER";
|
|
147
|
+
process.env.PROSOPO_CHECK_SPAM_EMAIL_LIMIT = "LIMIT_MARKER";
|
|
148
|
+
const entry = getRateLimitConfig()[ClientApiPaths.CheckSpamEmail];
|
|
149
|
+
expect(entry.windowMs).toBe("WINDOW_MARKER");
|
|
150
|
+
expect(entry.limit).toBe("LIMIT_MARKER");
|
|
151
|
+
});
|
|
152
|
+
it("re-reads process.env on every invocation (no module-load caching)", () => {
|
|
153
|
+
process.env.PROSOPO_DNS_EVENT_WINDOW = "first";
|
|
154
|
+
expect(getRateLimitConfig()[AdminApiPaths.DnsEvent].windowMs).toBe("first");
|
|
155
|
+
process.env.PROSOPO_DNS_EVENT_WINDOW = "second";
|
|
156
|
+
expect(getRateLimitConfig()[AdminApiPaths.DnsEvent].windowMs).toBe("second");
|
|
157
|
+
delete process.env.PROSOPO_DNS_EVENT_WINDOW;
|
|
158
|
+
expect(getRateLimitConfig()[AdminApiPaths.DnsEvent].windowMs).toBeUndefined();
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
//# sourceMappingURL=RateLimiter.unit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimiter.unit.test.js","sourceRoot":"","sources":["../../src/tests/RateLimiter.unit.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.unit.test.d.ts","sourceRoot":"","sources":["../../../src/tests/commands/validators.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { ProsopoContractError, ProsopoEnvError } from "@prosopo/common";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { validateAddress, validateScheduleExpression, validateSiteKey, validateValue, } from "../../commands/validators.js";
|
|
4
|
+
const VALID_SS58_ADDRESS = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY";
|
|
5
|
+
const VALID_HEX_ADDRESS = "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";
|
|
6
|
+
const INVALID_ADDRESS = "not-a-real-address";
|
|
7
|
+
const argv = (extras) => ({
|
|
8
|
+
_: [],
|
|
9
|
+
$0: "test",
|
|
10
|
+
...extras,
|
|
11
|
+
});
|
|
12
|
+
describe("validateAddress", () => {
|
|
13
|
+
it("returns the encoded SS58 form of a valid SS58 input", () => {
|
|
14
|
+
const { address } = validateAddress(argv({ address: VALID_SS58_ADDRESS }));
|
|
15
|
+
expect(typeof address).toBe("string");
|
|
16
|
+
expect(address).toBe(VALID_SS58_ADDRESS);
|
|
17
|
+
});
|
|
18
|
+
it("returns the encoded SS58 form when given a hex address", () => {
|
|
19
|
+
const { address } = validateAddress(argv({ address: VALID_HEX_ADDRESS }));
|
|
20
|
+
expect(address).toBe(VALID_SS58_ADDRESS);
|
|
21
|
+
});
|
|
22
|
+
it("throws ProsopoContractError with INVALID_ADDRESS code on garbage input", () => {
|
|
23
|
+
expect(() => validateAddress(argv({ address: INVALID_ADDRESS }))).toThrow(ProsopoContractError);
|
|
24
|
+
expect(() => validateAddress(argv({ address: INVALID_ADDRESS }))).toThrow("CONTRACT.INVALID_ADDRESS");
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
describe("validateSiteKey", () => {
|
|
28
|
+
it("returns the encoded SS58 form of a valid SS58 input", () => {
|
|
29
|
+
const { sitekey } = validateSiteKey(argv({ sitekey: VALID_SS58_ADDRESS }));
|
|
30
|
+
expect(sitekey).toBe(VALID_SS58_ADDRESS);
|
|
31
|
+
});
|
|
32
|
+
it("returns the encoded SS58 form when given a hex site key", () => {
|
|
33
|
+
const { sitekey } = validateSiteKey(argv({ sitekey: VALID_HEX_ADDRESS }));
|
|
34
|
+
expect(sitekey).toBe(VALID_SS58_ADDRESS);
|
|
35
|
+
});
|
|
36
|
+
it("throws ProsopoContractError with INVALID_ADDRESS code on garbage input", () => {
|
|
37
|
+
expect(() => validateSiteKey(argv({ sitekey: INVALID_ADDRESS }))).toThrow(ProsopoContractError);
|
|
38
|
+
expect(() => validateSiteKey(argv({ sitekey: INVALID_ADDRESS }))).toThrow("CONTRACT.INVALID_ADDRESS");
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
describe("validateValue", () => {
|
|
42
|
+
it("returns the numeric value wrapped as Compact<u128> when input is a number", () => {
|
|
43
|
+
const result = validateValue(argv({ value: 42 }));
|
|
44
|
+
expect(result.value).toBe(42);
|
|
45
|
+
});
|
|
46
|
+
it("accepts zero", () => {
|
|
47
|
+
const result = validateValue(argv({ value: 0 }));
|
|
48
|
+
expect(result.value).toBe(0);
|
|
49
|
+
});
|
|
50
|
+
it("throws ProsopoEnvError with PARAMETER_ERROR on string input", () => {
|
|
51
|
+
expect(() => validateValue(argv({ value: "42" }))).toThrow(ProsopoEnvError);
|
|
52
|
+
expect(() => validateValue(argv({ value: "42" }))).toThrow("CLI.PARAMETER_ERROR");
|
|
53
|
+
});
|
|
54
|
+
it("throws ProsopoEnvError on undefined value", () => {
|
|
55
|
+
expect(() => validateValue(argv({}))).toThrow(ProsopoEnvError);
|
|
56
|
+
});
|
|
57
|
+
it("throws ProsopoEnvError on boolean / object / null inputs", () => {
|
|
58
|
+
expect(() => validateValue(argv({ value: true }))).toThrow(ProsopoEnvError);
|
|
59
|
+
expect(() => validateValue(argv({ value: null }))).toThrow(ProsopoEnvError);
|
|
60
|
+
expect(() => validateValue(argv({ value: {} }))).toThrow(ProsopoEnvError);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
describe("validateScheduleExpression", () => {
|
|
64
|
+
it("returns the cron string when it parses cleanly", () => {
|
|
65
|
+
const result = validateScheduleExpression(argv({ schedule: "0 0 * * *" }));
|
|
66
|
+
expect(result.schedule).toBe("0 0 * * *");
|
|
67
|
+
});
|
|
68
|
+
it("returns null schedule when argv.schedule is not a string", () => {
|
|
69
|
+
expect(validateScheduleExpression(argv({}))).toEqual({ schedule: null });
|
|
70
|
+
expect(validateScheduleExpression(argv({ schedule: 42 }))).toEqual({
|
|
71
|
+
schedule: null,
|
|
72
|
+
});
|
|
73
|
+
expect(validateScheduleExpression(argv({ schedule: undefined }))).toEqual({
|
|
74
|
+
schedule: null,
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
it("accepts a variety of valid cron expressions", () => {
|
|
78
|
+
const valid = ["*/5 * * * *", "30 3 * * 1", "0 12 1 * *", "15 14 1 * *"];
|
|
79
|
+
for (const expr of valid) {
|
|
80
|
+
expect(validateScheduleExpression(argv({ schedule: expr })).schedule, `cron expression ${expr} should parse`).toBe(expr);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
//# sourceMappingURL=validators.unit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.unit.test.js","sourceRoot":"","sources":["../../../src/tests/commands/validators.unit.test.ts"],"names":[],"mappings":"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"}
|