@prosopo/provider 5.5.1 → 5.6.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 (99) hide show
  1. package/.turbo/turbo-build$colon$cjs.log +18 -17
  2. package/.turbo/turbo-build$colon$tsc.log +25 -25
  3. package/.turbo/turbo-build.log +18 -17
  4. package/CHANGELOG.md +65 -0
  5. package/dist/api/blacklistRequestInspector.d.ts +1 -0
  6. package/dist/api/blacklistRequestInspector.d.ts.map +1 -1
  7. package/dist/api/blacklistRequestInspector.js +4 -2
  8. package/dist/api/blacklistRequestInspector.js.map +1 -1
  9. package/dist/api/block.d.ts.map +1 -1
  10. package/dist/api/block.js +6 -0
  11. package/dist/api/block.js.map +1 -1
  12. package/dist/api/captcha/getFrictionlessCaptchaChallenge/constants.d.ts +7 -0
  13. package/dist/api/captcha/getFrictionlessCaptchaChallenge/constants.d.ts.map +1 -1
  14. package/dist/api/captcha/getFrictionlessCaptchaChallenge/constants.js +23 -3
  15. package/dist/api/captcha/getFrictionlessCaptchaChallenge/constants.js.map +1 -1
  16. package/dist/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.d.ts +2 -0
  17. package/dist/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.d.ts.map +1 -1
  18. package/dist/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.js +30 -3
  19. package/dist/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.js.map +1 -1
  20. package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.d.ts.map +1 -1
  21. package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js +7 -4
  22. package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js.map +1 -1
  23. package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.d.ts.map +1 -1
  24. package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.js +2 -2
  25. package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.js.map +1 -1
  26. package/dist/api/captcha/getImageCaptchaChallenge.d.ts.map +1 -1
  27. package/dist/api/captcha/getImageCaptchaChallenge.js +17 -3
  28. package/dist/api/captcha/getImageCaptchaChallenge.js.map +1 -1
  29. package/dist/api/captcha/getPoWCaptchaChallenge.d.ts.map +1 -1
  30. package/dist/api/captcha/getPoWCaptchaChallenge.js +16 -2
  31. package/dist/api/captcha/getPoWCaptchaChallenge.js.map +1 -1
  32. package/dist/api/captcha/getPuzzleCaptchaChallenge.d.ts.map +1 -1
  33. package/dist/api/captcha/getPuzzleCaptchaChallenge.js +12 -0
  34. package/dist/api/captcha/getPuzzleCaptchaChallenge.js.map +1 -1
  35. package/dist/api/captcha/submitPoWCaptchaSolution.js +1 -1
  36. package/dist/api/hardBlockVerdictCache.d.ts +1 -1
  37. package/dist/api/hardBlockVerdictCache.d.ts.map +1 -1
  38. package/dist/api/hardBlockVerdictCache.js +2 -2
  39. package/dist/api/hardBlockVerdictCache.js.map +1 -1
  40. package/dist/cjs/api/blacklistRequestInspector.cjs +4 -2
  41. package/dist/cjs/api/block.cjs +6 -0
  42. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/constants.cjs +25 -3
  43. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.cjs +29 -2
  44. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/handler.cjs +7 -4
  45. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.cjs +2 -2
  46. package/dist/cjs/api/captcha/getImageCaptchaChallenge.cjs +17 -3
  47. package/dist/cjs/api/captcha/getPoWCaptchaChallenge.cjs +16 -2
  48. package/dist/cjs/api/captcha/getPuzzleCaptchaChallenge.cjs +12 -0
  49. package/dist/cjs/api/captcha/submitPoWCaptchaSolution.cjs +1 -1
  50. package/dist/cjs/api/hardBlockVerdictCache.cjs +2 -2
  51. package/dist/cjs/index.cjs +3 -0
  52. package/dist/cjs/migrations/frictionlessLadder.cjs +59 -0
  53. package/dist/cjs/tasks/captchaManager.cjs +4 -1
  54. package/dist/cjs/tasks/frictionless/frictionlessTasks.cjs +3 -1
  55. package/dist/index.d.ts +1 -0
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +2 -1
  58. package/dist/index.js.map +1 -1
  59. package/dist/migrations/frictionlessLadder.d.ts +9 -0
  60. package/dist/migrations/frictionlessLadder.d.ts.map +1 -0
  61. package/dist/migrations/frictionlessLadder.js +58 -0
  62. package/dist/migrations/frictionlessLadder.js.map +1 -0
  63. package/dist/tasks/captchaManager.d.ts +1 -0
  64. package/dist/tasks/captchaManager.d.ts.map +1 -1
  65. package/dist/tasks/captchaManager.js +4 -1
  66. package/dist/tasks/captchaManager.js.map +1 -1
  67. package/dist/tasks/frictionless/frictionlessTasks.d.ts.map +1 -1
  68. package/dist/tasks/frictionless/frictionlessTasks.js +3 -1
  69. package/dist/tasks/frictionless/frictionlessTasks.js.map +1 -1
  70. package/dist/tasks/frictionless/routingMachine.d.ts +1 -0
  71. package/dist/tasks/frictionless/routingMachine.d.ts.map +1 -1
  72. package/dist/tasks/frictionless/routingMachine.js.map +1 -1
  73. package/dist/tests/integration/api/admin/apiRegisterSiteKeyEndpoint.integration.test.js +8 -2
  74. package/dist/tests/integration/api/admin/apiRegisterSiteKeyEndpoint.integration.test.js.map +1 -1
  75. package/dist/tests/integration/clientSettingsPersistence.integration.test.js +5 -2
  76. package/dist/tests/integration/clientSettingsPersistence.integration.test.js.map +1 -1
  77. package/dist/tests/unit/api/admin/apiRegisterSiteKeyEndpoint.unit.test.js +4 -1
  78. package/dist/tests/unit/api/admin/apiRegisterSiteKeyEndpoint.unit.test.js.map +1 -1
  79. package/dist/tests/unit/api/block.unit.test.js +37 -0
  80. package/dist/tests/unit/api/block.unit.test.js.map +1 -1
  81. package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/accessPolicy.unit.test.js +29 -0
  82. package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/accessPolicy.unit.test.js.map +1 -1
  83. package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/constants.unit.test.js +62 -1
  84. package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/constants.unit.test.js.map +1 -1
  85. package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.unit.test.js +105 -1
  86. package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.unit.test.js.map +1 -1
  87. package/dist/tests/unit/api/hardBlockVerdictCache.unit.test.js +8 -0
  88. package/dist/tests/unit/api/hardBlockVerdictCache.unit.test.js.map +1 -1
  89. package/dist/tests/unit/migrations/frictionlessLadder.unit.test.d.ts +2 -0
  90. package/dist/tests/unit/migrations/frictionlessLadder.unit.test.d.ts.map +1 -0
  91. package/dist/tests/unit/migrations/frictionlessLadder.unit.test.js +119 -0
  92. package/dist/tests/unit/migrations/frictionlessLadder.unit.test.js.map +1 -0
  93. package/dist/tests/unit/tasks/captchaManager.unit.test.js +4 -1
  94. package/dist/tests/unit/tasks/captchaManager.unit.test.js.map +1 -1
  95. package/dist/tests/unit/tasks/frictionless/routerImageRoundsClamp.unit.test.d.ts +2 -0
  96. package/dist/tests/unit/tasks/frictionless/routerImageRoundsClamp.unit.test.d.ts.map +1 -0
  97. package/dist/tests/unit/tasks/frictionless/routerImageRoundsClamp.unit.test.js +112 -0
  98. package/dist/tests/unit/tasks/frictionless/routerImageRoundsClamp.unit.test.js.map +1 -0
  99. package/package.json +13 -13
@@ -2,9 +2,9 @@ import { validateAddr, validateSiteKey } from "../validateAddress.js";
2
2
  import { downgradePuzzleIfUnavailable } from "../../tasks/puzzle/puzzleRenderer.js";
3
3
  import { Tasks } from "../../tasks/tasks.js";
4
4
  import { getMaintenanceMode } from "../admin/apiToggleMaintenanceModeEndpoint.js";
5
+ import { resolveTestSiteKeyVerdict } from "../testSiteKey.js";
5
6
  import { derivePlatform } from "../../utils/devicePlatform.js";
6
7
  import { rawTlsSignalsForSession } from "../rawTlsSignalsMiddleware.js";
7
- import { resolveTestSiteKeyVerdict } from "../testSiteKey.js";
8
8
  import { ProsopoApiError } from "@prosopo/common";
9
9
  import { CaptchaType, SubmitPowCaptchaSolutionBody } from "@prosopo/types";
10
10
  import { flatten, getIPAddress } from "@prosopo/util";
@@ -14,5 +14,5 @@ export declare class HardBlockVerdictCache {
14
14
  size(): number;
15
15
  inflightSize(): number;
16
16
  }
17
- export declare const hardBlockCacheKey: (clientId: string | undefined, userScope: UserScope, blockOnly: boolean) => string;
17
+ export declare const hardBlockCacheKey: (clientId: string | undefined, userScope: UserScope, blockOnly: boolean, includeDeferred?: boolean) => string;
18
18
  //# sourceMappingURL=hardBlockVerdictCache.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hardBlockVerdictCache.d.ts","sourceRoot":"","sources":["../../src/api/hardBlockVerdictCache.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAWzE,eAAO,MAAM,4BAA4B,QAAS,CAAC;AAOnD,eAAO,MAAM,iCAAiC,QAAS,CAAC;AAyBxD,qBAAa,qBAAqB;IAUhC,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAV5B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IAMvD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4C;gBAGnD,KAAK,GAAE,MAAqC,EAC5C,UAAU,GAAE,MAA0C;IAGxE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,EAAE,GAAG,SAAS;IAkB1C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,IAAI;IAyCrC,YAAY,CACjB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC,GAClC,OAAO,CAAC,UAAU,EAAE,CAAC;IAkCxB,KAAK,IAAI,IAAI;IAKb,IAAI,IAAI,MAAM;IAKd,YAAY,IAAI,MAAM;CAGtB;AAOD,eAAO,MAAM,iBAAiB,aACnB,MAAM,GAAG,SAAS,aACjB,SAAS,aACT,OAAO,KAChB,MAqBF,CAAC"}
1
+ {"version":3,"file":"hardBlockVerdictCache.d.ts","sourceRoot":"","sources":["../../src/api/hardBlockVerdictCache.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAWzE,eAAO,MAAM,4BAA4B,QAAS,CAAC;AAOnD,eAAO,MAAM,iCAAiC,QAAS,CAAC;AAyBxD,qBAAa,qBAAqB;IAUhC,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAV5B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IAMvD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4C;gBAGnD,KAAK,GAAE,MAAqC,EAC5C,UAAU,GAAE,MAA0C;IAGxE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,EAAE,GAAG,SAAS;IAkB1C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,IAAI;IAyCrC,YAAY,CACjB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC,GAClC,OAAO,CAAC,UAAU,EAAE,CAAC;IAkCxB,KAAK,IAAI,IAAI;IAKb,IAAI,IAAI,MAAM;IAKd,YAAY,IAAI,MAAM;CAGtB;AAWD,eAAO,MAAM,iBAAiB,aACnB,MAAM,GAAG,SAAS,aACjB,SAAS,aACT,OAAO,gCAEhB,MAqBF,CAAC"}
@@ -96,8 +96,8 @@ var HardBlockVerdictCache = class {
96
96
  return this.inflight.size;
97
97
  }
98
98
  };
99
- var hardBlockCacheKey = (clientId, userScope, blockOnly) => {
100
- return `${blockOnly ? "1" : "0"}|${[
99
+ var hardBlockCacheKey = (clientId, userScope, blockOnly, includeDeferred = false) => {
100
+ return `${`${blockOnly ? "1" : "0"}${includeDeferred ? "d" : ""}`}|${[
101
101
  clientId ?? "",
102
102
  userScope.numericIp === void 0 ? "" : userScope.numericIp.toString(),
103
103
  userScope.numericIpMaskMin === void 0 ? "" : userScope.numericIpMaskMin.toString(),
@@ -1 +1 @@
1
- {"version":3,"file":"hardBlockVerdictCache.js","sourceRoot":"","sources":["../../src/api/hardBlockVerdictCache.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hardBlockVerdictCache.js","sourceRoot":"","sources":["../../src/api/hardBlockVerdictCache.ts"],"names":[],"mappings":"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"}
@@ -130,9 +130,10 @@ var getOrCreateRequestMemo = (requestMemoHost) => {
130
130
  var getPrioritisedAccessRule = async (userAccessRulesStorage, userScope, clientId, options) => {
131
131
  const parsedUserScope = _prosopo_user_access_policy.userScopeInput.parse(userScope);
132
132
  const blockOnly = options?.blockOnly ?? false;
133
+ const includeDeferred = options?.includeDeferred ?? false;
133
134
  const skipCache = options?.skipCache ?? false;
134
135
  const requestMemoHost = options?.requestMemoHost;
135
- const cacheKey = require_hardBlockVerdictCache.hardBlockCacheKey(clientId, parsedUserScope, blockOnly);
136
+ const cacheKey = require_hardBlockVerdictCache.hardBlockCacheKey(clientId, parsedUserScope, blockOnly, includeDeferred);
136
137
  const requestMemo = requestMemoHost ? getOrCreateRequestMemo(requestMemoHost) : void 0;
137
138
  if (requestMemo !== void 0) {
138
139
  const memoHit = requestMemo.get(cacheKey);
@@ -143,7 +144,8 @@ var getPrioritisedAccessRule = async (userAccessRulesStorage, userScope, clientI
143
144
  policyScopeMatch: _prosopo_user_access_policy.FilterScopeMatch.Greedy,
144
145
  userScope: parsedUserScope,
145
146
  userScopeMatch: _prosopo_user_access_policy.FilterScopeMatch.Greedy,
146
- ...blockOnly && { blockOnly: true }
147
+ ...blockOnly && { blockOnly: true },
148
+ ...includeDeferred && { includeDeferred: true }
147
149
  };
148
150
  const compute = async () => {
149
151
  return rankCandidateRules(await userAccessRulesStorage.findRules(filter, true, true), parsedUserScope, clientId);
@@ -1,11 +1,17 @@
1
1
  const require_blacklistRequestInspector = require("./blacklistRequestInspector.cjs");
2
2
  const require_apiToggleMaintenanceModeEndpoint = require("./admin/apiToggleMaintenanceModeEndpoint.cjs");
3
+ const require_testSiteKey = require("./testSiteKey.cjs");
3
4
  //#region src/api/block.ts
5
+ var isReservedTestSiteKeyRequest = (req) => {
6
+ const siteKey = req.headers?.["prosopo-site-key"];
7
+ return typeof siteKey === "string" && require_testSiteKey.isReservedTestSiteKey(siteKey);
8
+ };
4
9
  var blockMiddleware = (providerEnvironment) => {
5
10
  let blacklistRequestInspector;
6
11
  const environmentReadinessWaiter = providerEnvironment.isReady.bind(providerEnvironment);
7
12
  return (req, res, next) => {
8
13
  if (require_apiToggleMaintenanceModeEndpoint.getMaintenanceMode()) return next();
14
+ if (isReservedTestSiteKeyRequest(req)) return next();
9
15
  if (!blacklistRequestInspector) try {
10
16
  const db = providerEnvironment.getDb();
11
17
  const userAccessRulesStorage = db.getUserAccessRulesStorage();
@@ -1,5 +1,26 @@
1
- //#region src/api/captcha/getFrictionlessCaptchaChallenge/constants.ts
2
- var DEFAULT_FRICTIONLESS_THRESHOLD = .5;
1
+ let _prosopo_types = require("@prosopo/types");
2
+ _prosopo_types.frictionlessPuzzleThresholdDefault;
3
+ /**
4
+ * A client record's configured ladder, in the terms the decision machine
5
+ * compares against. Thin rename over `resolveFrictionlessThreshold`, which
6
+ * owns the tolerance for records written before the ladder existed.
7
+ */
8
+ var resolveScoreLadder = (configured) => {
9
+ const ladder = (0, _prosopo_types.resolveFrictionlessThreshold)(configured);
10
+ return {
11
+ botThreshold: ladder.frictionlessPuzzleThreshold,
12
+ botImageThreshold: ladder.frictionlessImageThreshold
13
+ };
14
+ };
15
+ /**
16
+ * Size an image challenge by how much was actually found. `base` is the
17
+ * sitekey's ordinary image round count; each triggered signal adds a round,
18
+ * capped by `MAX_DETECTOR_EXTRA_IMAGE_ROUNDS`. A session with nothing
19
+ * triggered gets exactly the baseline.
20
+ *
21
+ * The caller is still responsible for clamping to `imageMaxRounds`.
22
+ */
23
+ var getRoundsFromTriggeredDetectors = (base, triggeredDetectors) => base + Math.min(triggeredDetectors?.length ?? 0, 6);
3
24
  var getRoundsFromSimScore = (simScore) => {
4
25
  if (simScore >= .9) return 0;
5
26
  if (simScore >= .8) return 3;
@@ -9,5 +30,6 @@ var getRoundsFromSimScore = (simScore) => {
9
30
  return 8;
10
31
  };
11
32
  //#endregion
12
- exports.DEFAULT_FRICTIONLESS_THRESHOLD = DEFAULT_FRICTIONLESS_THRESHOLD;
13
33
  exports.getRoundsFromSimScore = getRoundsFromSimScore;
34
+ exports.getRoundsFromTriggeredDetectors = getRoundsFromTriggeredDetectors;
35
+ exports.resolveScoreLadder = resolveScoreLadder;
@@ -149,6 +149,31 @@ var runDecisionMachine = async (input, handle) => {
149
149
  headers: flatHeaders
150
150
  }));
151
151
  }
152
+ const scoredImageRounds = Math.min(require_constants.getRoundsFromTriggeredDetectors(env.config.captchas.solved.count, input.triggeredDetectors), clientRecord.settings.imageMaxRounds);
153
+ const botImageThreshold = input.botImageThreshold;
154
+ if (botImageThreshold > input.botThreshold && Number(botScore) > input.botThreshold && Number(botScore) < botImageThreshold) {
155
+ req.logger.info(() => ({
156
+ msg: "Frictionless decision",
157
+ data: {
158
+ decision: "bot_score_puzzle_band",
159
+ captchaType: _prosopo_types.CaptchaType.puzzle,
160
+ botScore,
161
+ botThreshold: input.botThreshold,
162
+ botImageThreshold,
163
+ token: input.token
164
+ }
165
+ }));
166
+ require_metrics.recordFrictionlessDecision("bot_score_puzzle_band");
167
+ require_honeypotResponse.attachHoneypot(res, clientRecord);
168
+ return res.json(await tasks.frictionlessManager.sendPuzzleCaptcha({
169
+ solvedImagesCount: scoredImageRounds,
170
+ userSitekeyIpHash,
171
+ reason: _prosopo_types.FrictionlessReason.BOT_SCORE_PUZZLE_BAND,
172
+ siteKey: dapp,
173
+ ipInfo,
174
+ headers: flatHeaders
175
+ }));
176
+ }
152
177
  if (Number(botScore) > input.botThreshold) {
153
178
  req.logger.info(() => ({
154
179
  msg: "Bot score is greater than threshold",
@@ -162,13 +187,15 @@ var runDecisionMachine = async (input, handle) => {
162
187
  msg: "Frictionless decision",
163
188
  data: {
164
189
  decision: "bot_score_above_threshold",
165
- captchaType: _prosopo_types.CaptchaType.image
190
+ captchaType: _prosopo_types.CaptchaType.image,
191
+ solvedImagesCount: scoredImageRounds,
192
+ triggeredDetectorCount: input.triggeredDetectors?.length ?? 0
166
193
  }
167
194
  }));
168
195
  require_metrics.recordFrictionlessDecision("bot_score_above_threshold");
169
196
  require_honeypotResponse.attachHoneypot(res, clientRecord);
170
197
  return res.json(await tasks.frictionlessManager.sendImageCaptcha({
171
- solvedImagesCount: Math.min(env.config.captchas.solved.count, clientRecord.settings.imageMaxRounds),
198
+ solvedImagesCount: scoredImageRounds,
172
199
  userSitekeyIpHash,
173
200
  reason: _prosopo_types.FrictionlessReason.BOT_SCORE_ABOVE_THRESHOLD,
174
201
  siteKey: dapp,
@@ -4,17 +4,17 @@ const require_metrics = require("../../metrics.cjs");
4
4
  const require_blacklistRequestInspector = require("../../blacklistRequestInspector.cjs");
5
5
  const require_tasks = require("../../../tasks/tasks.cjs");
6
6
  const require_apiToggleMaintenanceModeEndpoint = require("../../admin/apiToggleMaintenanceModeEndpoint.cjs");
7
+ const require_testSiteKey = require("../../testSiteKey.cjs");
7
8
  const require_devicePlatform = require("../../../utils/devicePlatform.cjs");
8
9
  const require_hashUserAgent = require("../../../utils/hashUserAgent.cjs");
9
10
  const require_hashUserIp = require("../../../utils/hashUserIp.cjs");
10
11
  const require_normalizeRequestIp = require("../../../utils/normalizeRequestIp.cjs");
11
12
  const require_rawTlsSignalsMiddleware = require("../../rawTlsSignalsMiddleware.cjs");
12
- const require_testSiteKey = require("../../testSiteKey.cjs");
13
13
  const require_maintenanceModeResponses = require("../maintenanceModeResponses.cjs");
14
14
  const require_trafficFilterRequestTime = require("../trafficFilterRequestTime.cjs");
15
15
  const require_honeypotResponse = require("./honeypotResponse.cjs");
16
16
  const require_accessPolicy = require("./accessPolicy.cjs");
17
- require("./constants.cjs");
17
+ const require_constants = require("./constants.cjs");
18
18
  const require_decisionMachine = require("./decisionMachine.cjs");
19
19
  const require_decryptSimdReadings = require("./decryptSimdReadings.cjs");
20
20
  const require_sessionDedup = require("./sessionDedup.cjs");
@@ -266,7 +266,7 @@ var handler_default = (env, userAccessRulesStorage) => async (req, res, next) =>
266
266
  }));
267
267
  require_metrics.recordBotScore(botScore);
268
268
  if (triggeredDetectors && triggeredDetectors.length > 0) require_metrics.recordDetectorTriggered(triggeredDetectors);
269
- const botThreshold = clientRecord.settings?.frictionlessThreshold || .5;
269
+ const { botThreshold, botImageThreshold } = require_constants.resolveScoreLadder(clientRecord.settings?.frictionlessThreshold);
270
270
  let scoreComponents = {
271
271
  baseScore: baseBotScore,
272
272
  ...lScore && { lScore },
@@ -312,6 +312,7 @@ var handler_default = (env, userAccessRulesStorage) => async (req, res, next) =>
312
312
  ip: normalizedIp,
313
313
  countryCode,
314
314
  score: botScore,
315
+ imageMaxRounds: clientRecord.settings.imageMaxRounds,
315
316
  platform: require_devicePlatform.derivePlatform(safeUserAgent, webView, { ...typeof ipInfoMobile === "boolean" && { isMobile: ipInfoMobile } }),
316
317
  raw: {
317
318
  headers: flatHeaders,
@@ -325,7 +326,7 @@ var handler_default = (env, userAccessRulesStorage) => async (req, res, next) =>
325
326
  ...iframeUrl && { iframeUrl }
326
327
  }
327
328
  });
328
- const userAccessPolicy = accessPolicies.find((p) => !p.deferToVerify);
329
+ const userAccessPolicy = accessPolicies.find((p) => !(p.deferToVerify === true && p.type === _prosopo_user_access_policy.AccessPolicyType.Block));
329
330
  const accessPolicyOutcome = await require_accessPolicy.handleAccessPolicy({
330
331
  tasks,
331
332
  clientRecord,
@@ -376,6 +377,8 @@ var handler_default = (env, userAccessRulesStorage) => async (req, res, next) =>
376
377
  token,
377
378
  headHash,
378
379
  botThreshold,
380
+ botImageThreshold,
381
+ triggeredDetectors,
379
382
  currentUrl,
380
383
  iframeUrl
381
384
  }, {
@@ -1,6 +1,6 @@
1
1
  const require_bundlePool = require("../../../tasks/detection/bundlePool.cjs");
2
2
  const require_honeypotResponse = require("./honeypotResponse.cjs");
3
- require("./constants.cjs");
3
+ const require_constants = require("./constants.cjs");
4
4
  let _prosopo_types = require("@prosopo/types");
5
5
  let uuid = require("uuid");
6
6
  //#region src/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.ts
@@ -9,7 +9,7 @@ var buildBypassSessionParams = async (input) => {
9
9
  return {
10
10
  token: input.token || `nodetector-${(0, uuid.v4)()}`,
11
11
  score: 0,
12
- threshold: input.clientRecord.settings?.frictionlessThreshold ?? .5,
12
+ threshold: require_constants.resolveScoreLadder(input.clientRecord.settings?.frictionlessThreshold).botThreshold,
13
13
  scoreComponents: { baseScore: 0 },
14
14
  ipAddress: input.ipAddress,
15
15
  webView: false,
@@ -3,6 +3,7 @@ const require_metrics = require("../metrics.cjs");
3
3
  const require_blacklistRequestInspector = require("../blacklistRequestInspector.cjs");
4
4
  const require_tasks = require("../../tasks/tasks.cjs");
5
5
  const require_apiToggleMaintenanceModeEndpoint = require("../admin/apiToggleMaintenanceModeEndpoint.cjs");
6
+ const require_testSiteKey = require("../testSiteKey.cjs");
6
7
  const require_normalizeRequestIp = require("../../utils/normalizeRequestIp.cjs");
7
8
  const require_maintenanceModeResponses = require("./maintenanceModeResponses.cjs");
8
9
  const require_trafficFilterRequestTime = require("./trafficFilterRequestTime.cjs");
@@ -58,6 +59,17 @@ var getImageCaptchaChallenge_default = (env, userAccessRulesStorage) => async (r
58
59
  }));
59
60
  return res.json(require_maintenanceModeResponses.buildImageMaintenanceResponse());
60
61
  }
62
+ if (require_testSiteKey.isReservedTestSiteKey(dapp)) {
63
+ req.logger.warn(() => ({
64
+ msg: "Reserved TEST site key - returning dummy image challenge",
65
+ data: {
66
+ dapp,
67
+ user,
68
+ sessionId
69
+ }
70
+ }));
71
+ return res.json(require_maintenanceModeResponses.buildImageMaintenanceResponse());
72
+ }
61
73
  const tasks = new require_tasks.Tasks(env, req.logger);
62
74
  try {
63
75
  const clientRecord = await tasks.db.getClientRecord(dapp);
@@ -73,7 +85,9 @@ var getImageCaptchaChallenge_default = (env, userAccessRulesStorage) => async (r
73
85
  const asn = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.asnNumber : void 0;
74
86
  const sessionRecord = sessionId ? await tasks.db.getSessionRecordBySessionId(sessionId) : void 0;
75
87
  const userScope = require_blacklistRequestInspector.getRequestUserScope((0, _prosopo_util.flatten)(req.headers), req.ja4, normalizedIp, user, sessionRecord?.decryptedHeadHash, void 0, countryCode, asn);
76
- const userAccessPolicy = (await tasks.imgCaptchaManager.getPrioritisedAccessPolicies(userAccessRulesStorage, dapp, userScope)).find((p) => !p.deferToVerify);
88
+ const accessPolicies = await tasks.imgCaptchaManager.getPrioritisedAccessPolicies(userAccessRulesStorage, dapp, userScope);
89
+ const userAccessPolicy = accessPolicies.find((p) => !p.deferToVerify);
90
+ const deferredParamsPolicy = accessPolicies.find((p) => p.deferToVerify === true);
77
91
  const { valid, reason, sessionId: validSessionId, solvedImagesCount } = await tasks.imgCaptchaManager.isValidRequest(clientRecord, _prosopo_types.CaptchaType.image, env, sessionId, userAccessPolicy, normalizedIp);
78
92
  if (!valid) return next(new _prosopo_common.ProsopoApiError(reason || "API.BAD_REQUEST", {
79
93
  context: {
@@ -87,8 +101,8 @@ var getImageCaptchaChallenge_default = (env, userAccessRulesStorage) => async (r
87
101
  const trafficVerdict = require_trafficFilterRequestTime.applyTrafficFilterAtRequestTime(req.ipInfo, clientRecord.settings?.trafficFilter, req.logger);
88
102
  const trafficSolvedImagesCount = trafficVerdict.kind === "challenge" ? trafficVerdict.solvedImagesCount : void 0;
89
103
  const captchaConfig = {
90
- solved: { count: Math.min(trafficSolvedImagesCount || solvedImagesCount || userAccessPolicy?.solvedImagesCount || env.config.captchas.solved.count, clientRecord.settings.imageMaxRounds ?? _prosopo_types.imageMaxRoundsDefault) },
91
- unsolved: { count: userAccessPolicy?.unsolvedImagesCount || env.config.captchas.unsolved.count }
104
+ solved: { count: Math.min(trafficSolvedImagesCount || solvedImagesCount || userAccessPolicy?.solvedImagesCount || deferredParamsPolicy?.solvedImagesCount || env.config.captchas.solved.count, clientRecord.settings.imageMaxRounds ?? _prosopo_types.imageMaxRoundsDefault) },
105
+ unsolved: { count: userAccessPolicy?.unsolvedImagesCount || deferredParamsPolicy?.unsolvedImagesCount || env.config.captchas.unsolved.count }
92
106
  };
93
107
  if (validSessionId && simdReadings) await tasks.frictionlessManager.decryptAndAttachSimdReadingsIfAbsent(validSessionId, simdReadings, _prosopo_types.SimdReadingsStage.challenge).catch((updateErr) => {
94
108
  req.logger.warn(() => ({
@@ -4,6 +4,7 @@ const require_metrics = require("../metrics.cjs");
4
4
  const require_blacklistRequestInspector = require("../blacklistRequestInspector.cjs");
5
5
  const require_tasks = require("../../tasks/tasks.cjs");
6
6
  const require_apiToggleMaintenanceModeEndpoint = require("../admin/apiToggleMaintenanceModeEndpoint.cjs");
7
+ const require_testSiteKey = require("../testSiteKey.cjs");
7
8
  const require_normalizeRequestIp = require("../../utils/normalizeRequestIp.cjs");
8
9
  const require_maintenanceModeResponses = require("./maintenanceModeResponses.cjs");
9
10
  const require_trafficFilterRequestTime = require("./trafficFilterRequestTime.cjs");
@@ -39,6 +40,17 @@ var getPoWCaptchaChallenge_default = (env, userAccessRulesStorage) => async (req
39
40
  }));
40
41
  return res.json(require_maintenanceModeResponses.buildPowMaintenanceResponse(user, dapp));
41
42
  }
43
+ if (require_testSiteKey.isReservedTestSiteKey(dapp)) {
44
+ req.logger.warn(() => ({
45
+ msg: "Reserved TEST site key - returning dummy PoW challenge",
46
+ data: {
47
+ dapp,
48
+ user,
49
+ sessionId
50
+ }
51
+ }));
52
+ return res.json(require_maintenanceModeResponses.buildPowMaintenanceResponse(user, dapp));
53
+ }
42
54
  const tasks = new require_tasks.Tasks(env, req.logger);
43
55
  try {
44
56
  const clientSettings = await tasks.db.getClientRecord(dapp);
@@ -56,7 +68,9 @@ var getPoWCaptchaChallenge_default = (env, userAccessRulesStorage) => async (req
56
68
  const asn = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.asnNumber : void 0;
57
69
  const sessionRecord = sessionId ? await tasks.db.getSessionRecordBySessionId(sessionId) : void 0;
58
70
  const userScope = require_blacklistRequestInspector.getRequestUserScope((0, _prosopo_util.flatten)(req.headers), req.ja4, normalizedIp, user, sessionRecord?.decryptedHeadHash, void 0, countryCode, asn);
59
- const userAccessPolicy = (await tasks.powCaptchaManager.getPrioritisedAccessPolicies(userAccessRulesStorage, dapp, userScope)).find((p) => !p.deferToVerify);
71
+ const accessPolicies = await tasks.powCaptchaManager.getPrioritisedAccessPolicies(userAccessRulesStorage, dapp, userScope);
72
+ const userAccessPolicy = accessPolicies.find((p) => !p.deferToVerify);
73
+ const deferredParamsPolicy = accessPolicies.find((p) => p.deferToVerify === true);
60
74
  const { valid, reason, sessionId: validSessionId, powDifficulty } = await tasks.powCaptchaManager.isValidRequest(clientSettings, _prosopo_types.CaptchaType.pow, env, sessionId, userAccessPolicy, normalizedIp);
61
75
  if (!valid) return next(new _prosopo_common.ProsopoApiError(reason || "API.BAD_REQUEST", {
62
76
  context: {
@@ -79,7 +93,7 @@ var getPoWCaptchaChallenge_default = (env, userAccessRulesStorage) => async (req
79
93
  logger: req.logger
80
94
  }));
81
95
  const trafficVerdict = require_trafficFilterRequestTime.applyTrafficFilterAtRequestTime(req.ipInfo, clientSettings.settings?.trafficFilter, req.logger);
82
- const difficulty = (trafficVerdict.kind === "challenge" ? trafficVerdict.powDifficulty : void 0) || powDifficulty || userAccessPolicy?.powDifficulty || clientSettings?.settings?.powDifficulty;
96
+ const difficulty = (trafficVerdict.kind === "challenge" ? trafficVerdict.powDifficulty : void 0) || powDifficulty || userAccessPolicy?.powDifficulty || deferredParamsPolicy?.powDifficulty || clientSettings?.settings?.powDifficulty;
83
97
  const challenge = await tasks.powCaptchaManager.getPowCaptchaChallenge(user, dapp, origin, difficulty);
84
98
  if (validSessionId && simdReadings) await tasks.frictionlessManager.decryptAndAttachSimdReadingsIfAbsent(validSessionId, simdReadings, _prosopo_types.SimdReadingsStage.challenge).catch((updateErr) => {
85
99
  req.logger.warn(() => ({
@@ -5,6 +5,7 @@ const require_blacklistRequestInspector = require("../blacklistRequestInspector.
5
5
  const require_puzzleRenderer = require("../../tasks/puzzle/puzzleRenderer.cjs");
6
6
  const require_tasks = require("../../tasks/tasks.cjs");
7
7
  const require_apiToggleMaintenanceModeEndpoint = require("../admin/apiToggleMaintenanceModeEndpoint.cjs");
8
+ const require_testSiteKey = require("../testSiteKey.cjs");
8
9
  const require_normalizeRequestIp = require("../../utils/normalizeRequestIp.cjs");
9
10
  const require_maintenanceModeResponses = require("./maintenanceModeResponses.cjs");
10
11
  const require_trafficFilterRequestTime = require("./trafficFilterRequestTime.cjs");
@@ -40,6 +41,17 @@ var getPuzzleCaptchaChallenge_default = (env, userAccessRulesStorage) => async (
40
41
  }));
41
42
  return res.json(await require_maintenanceModeResponses.buildPuzzleMaintenanceResponse(user, dapp));
42
43
  }
44
+ if (require_testSiteKey.isReservedTestSiteKey(dapp)) {
45
+ req.logger.warn(() => ({
46
+ msg: "Reserved TEST site key - returning dummy puzzle challenge",
47
+ data: {
48
+ dapp,
49
+ user,
50
+ sessionId
51
+ }
52
+ }));
53
+ return res.json(await require_maintenanceModeResponses.buildPuzzleMaintenanceResponse(user, dapp));
54
+ }
43
55
  const tasks = new require_tasks.Tasks(env, req.logger);
44
56
  try {
45
57
  const clientSettings = await tasks.db.getClientRecord(dapp);
@@ -2,9 +2,9 @@ const require_validateAddress = require("../validateAddress.cjs");
2
2
  const require_puzzleRenderer = require("../../tasks/puzzle/puzzleRenderer.cjs");
3
3
  const require_tasks = require("../../tasks/tasks.cjs");
4
4
  const require_apiToggleMaintenanceModeEndpoint = require("../admin/apiToggleMaintenanceModeEndpoint.cjs");
5
+ const require_testSiteKey = require("../testSiteKey.cjs");
5
6
  const require_devicePlatform = require("../../utils/devicePlatform.cjs");
6
7
  const require_rawTlsSignalsMiddleware = require("../rawTlsSignalsMiddleware.cjs");
7
- const require_testSiteKey = require("../testSiteKey.cjs");
8
8
  let _prosopo_common = require("@prosopo/common");
9
9
  let _prosopo_types = require("@prosopo/types");
10
10
  let _prosopo_util = require("@prosopo/util");
@@ -96,8 +96,8 @@ var HardBlockVerdictCache = class {
96
96
  return this.inflight.size;
97
97
  }
98
98
  };
99
- var hardBlockCacheKey = (clientId, userScope, blockOnly) => {
100
- return `${blockOnly ? "1" : "0"}|${[
99
+ var hardBlockCacheKey = (clientId, userScope, blockOnly, includeDeferred = false) => {
100
+ return `${`${blockOnly ? "1" : "0"}${includeDeferred ? "d" : ""}`}|${[
101
101
  clientId ?? "",
102
102
  userScope.numericIp === void 0 ? "" : userScope.numericIp.toString(),
103
103
  userScope.numericIpMaskMin === void 0 ? "" : userScope.numericIpMaskMin.toString(),
@@ -17,6 +17,7 @@ const require_headerCheckMiddleware = require("./api/headerCheckMiddleware.cjs")
17
17
  const require_ignoreMiddleware = require("./api/ignoreMiddleware.cjs");
18
18
  const require_robotsMiddleware = require("./api/robotsMiddleware.cjs");
19
19
  const require_startProviderApi = require("./api/startProviderApi.cjs");
20
+ const require_frictionlessLadder = require("./migrations/frictionlessLadder.cjs");
20
21
  const require_captchaScheduler = require("./schedulers/captchaScheduler.cjs");
21
22
  const require_getClientList = require("./schedulers/getClientList.cjs");
22
23
  const require_updateSpamEmailDomains$1 = require("./schedulers/updateSpamEmailDomains.cjs");
@@ -51,11 +52,13 @@ exports.headerCheckMiddleware = require_headerCheckMiddleware.headerCheckMiddlew
51
52
  exports.ignoreMiddleware = require_ignoreMiddleware.ignoreMiddleware;
52
53
  exports.isTlsAvailable = require_startProviderApi.isTlsAvailable;
53
54
  exports.ja4Middleware = require_ja4Middleware.ja4Middleware;
55
+ exports.migrateFrictionlessLadder = require_frictionlessLadder.migrateFrictionlessLadder;
54
56
  exports.prosopoRouter = require_captcha.prosopoRouter;
55
57
  exports.prosopoVerifyRouter = require_verify.prosopoVerifyRouter;
56
58
  exports.publicRouter = require_public.publicRouter;
57
59
  exports.rankCandidateRules = require_blacklistRequestInspector.rankCandidateRules;
58
60
  exports.robotsMiddleware = require_robotsMiddleware.robotsMiddleware;
61
+ exports.runFrictionlessLadderMigration = require_frictionlessLadder.runFrictionlessLadderMigration;
59
62
  exports.shuffleArray = require_util.shuffleArray;
60
63
  exports.startProviderApi = require_startProviderApi.startProviderApi;
61
64
  exports.storeCaptchasExternally = require_captchaScheduler.storeCaptchasExternally;
@@ -0,0 +1,59 @@
1
+ let _prosopo_types = require("@prosopo/types");
2
+ //#region src/migrations/frictionlessLadder.ts
3
+ /** Already the ladder object? Anything else gets rewritten. */
4
+ var isLadder = (value) => typeof value === "object" && value !== null && "frictionlessPuzzleThreshold" in value && "frictionlessImageThreshold" in value;
5
+ /**
6
+ * Rewrite any pre-ladder `frictionlessThreshold` on this provider's client
7
+ * records. Each record's existing number becomes its puzzle rung verbatim, so
8
+ * no site's silent-pass boundary moves.
9
+ *
10
+ * Idempotent — records already carrying the object shape are skipped, so
11
+ * restarting the container repeatedly is free after the first pass.
12
+ */
13
+ var migrateFrictionlessLadder = async (db, logger) => {
14
+ const clients = db.tables?.client;
15
+ if (!clients) {
16
+ logger.warn(() => ({ msg: "Frictionless ladder migration skipped - no client table" }));
17
+ return {
18
+ scanned: 0,
19
+ migrated: 0
20
+ };
21
+ }
22
+ const records = await clients.find().lean();
23
+ const ops = records.filter((record) => record.account !== void 0 && !isLadder(record.settings?.frictionlessThreshold)).map((record) => {
24
+ const current = record.settings?.frictionlessThreshold;
25
+ return { updateOne: {
26
+ filter: { account: record.account },
27
+ update: { $set: { "settings.frictionlessThreshold": (0, _prosopo_types.resolveFrictionlessThreshold)(typeof current === "number" ? current : void 0) } }
28
+ } };
29
+ });
30
+ if (ops.length > 0) await clients.bulkWrite(ops);
31
+ logger.info(() => ({
32
+ msg: "Frictionless ladder migration complete",
33
+ data: {
34
+ scanned: records.length,
35
+ migrated: ops.length
36
+ }
37
+ }));
38
+ return {
39
+ scanned: records.length,
40
+ migrated: ops.length
41
+ };
42
+ };
43
+ /**
44
+ * Boot-time wrapper. Never throws: a failed migration must not stop the
45
+ * provider from serving, because the read path already handles the old shape.
46
+ */
47
+ var runFrictionlessLadderMigration = async (db, logger) => {
48
+ try {
49
+ await migrateFrictionlessLadder(db, logger);
50
+ } catch (err) {
51
+ logger.error(() => ({
52
+ err,
53
+ msg: "Frictionless ladder migration failed - continuing startup"
54
+ }));
55
+ }
56
+ };
57
+ //#endregion
58
+ exports.migrateFrictionlessLadder = migrateFrictionlessLadder;
59
+ exports.runFrictionlessLadderMigration = runFrictionlessLadderMigration;
@@ -438,7 +438,10 @@ var CaptchaManager = class CaptchaManager {
438
438
  const coordsString = coords ? JSON.stringify(coords) : void 0;
439
439
  const ipAddressRecord = require_compositeIpAddress.getIpAddressFromComposite(challengeRecord.ipAddress);
440
440
  const userScope = require_blacklistRequestInspector.getRequestUserScope(headers, challengeRecord.ja4, ipAddressRecord.address, userAccount, headHash, coordsString, countryCode, asn);
441
- return findHardBlockPolicy(await this.getPrioritisedAccessPolicies(userAccessRulesStorage, challengeRecord.dappAccount, userScope, { blockOnly: true }));
441
+ return findHardBlockPolicy(await this.getPrioritisedAccessPolicies(userAccessRulesStorage, challengeRecord.dappAccount, userScope, {
442
+ blockOnly: true,
443
+ includeDeferred: true
444
+ }));
442
445
  }
443
446
  /**
444
447
  * Checks if the provided email address has a domain in the spam email domain list.
@@ -189,7 +189,9 @@ var FrictionlessManager = class extends require_captchaManager.CaptchaManager {
189
189
  };
190
190
  const routed = this.routingContext ? await require_routingMachine.applyRouter(this.decisionMachineRunner, this.usageCounters, baseline, this.routingContext, this.logger) : baseline;
191
191
  const finalCaptchaType = require_puzzleRenderer.downgradePuzzleIfUnavailable(routed.captchaType, this.logger);
192
- const finalSolvedImagesCount = finalCaptchaType === _prosopo_types.CaptchaType.image ? routed.solvedImagesCount ?? effectiveParams.solvedImagesCount : void 0;
192
+ const requestedSolvedImagesCount = routed.solvedImagesCount ?? effectiveParams.solvedImagesCount;
193
+ const imageRoundsCeiling = this.routingContext?.imageMaxRounds;
194
+ const finalSolvedImagesCount = finalCaptchaType === _prosopo_types.CaptchaType.image ? requestedSolvedImagesCount !== void 0 && imageRoundsCeiling !== void 0 ? Math.min(requestedSolvedImagesCount, imageRoundsCeiling) : requestedSolvedImagesCount : void 0;
193
195
  const finalPowDifficulty = finalCaptchaType === _prosopo_types.CaptchaType.pow ? routed.powDifficulty ?? effectiveParams.powDifficulty : void 0;
194
196
  const blocked = finalCaptchaType === _prosopo_types.CaptchaType.image ? effectiveParams.blocked : void 0;
195
197
  const sessionRecord = await this.createSession(effectiveParams.token, effectiveParams.score, effectiveParams.threshold, effectiveParams.scoreComponents, effectiveParams.ipAddress, finalCaptchaType, effectiveParams.siteKey, finalSolvedImagesCount, finalPowDifficulty, effectiveParams.userSitekeyIpHash, effectiveParams.webView ?? false, effectiveParams.iFrame ?? false, effectiveParams.decryptedHeadHash, effectiveParams.reason, blocked, void 0, effectiveParams.ipInfo, effectiveParams.headers, effectiveParams.mode, effectiveParams.simdReadings, effectiveParams.entropyMathRandomFingerprint, effectiveParams.entropyCryptoFingerprint, effectiveParams.entropyWallClockOffsetMs, effectiveParams.entropyMathRandomFirst, effectiveParams.bundleId, effectiveParams.currentUrl, effectiveParams.tcpToChelloUs, effectiveParams.chelloToHandshakeUs, void 0, effectiveParams.iframeUrl, effectiveParams.isProtect, void 0, effectiveParams.g, effectiveParams.matchedRule, effectiveParams.i, effectiveParams.sw, effectiveParams.md, effectiveParams.bn, effectiveParams.fs, {
package/dist/index.d.ts CHANGED
@@ -9,6 +9,7 @@ export * from "./api/handshakeTimingMiddleware.js";
9
9
  export * from "./api/public.js";
10
10
  export * from "./api/domainMiddleware.js";
11
11
  export * from "./api/startProviderApi.js";
12
+ export * from "./migrations/frictionlessLadder.js";
12
13
  export * from "./schedulers/captchaScheduler.js";
13
14
  export * from "./schedulers/getClientList.js";
14
15
  export * from "./schedulers/updateSpamEmailDomains.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAChF,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,oCAAoC,CAAC;AACnD,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kCAAkC,CAAC;AACjD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wCAAwC,CAAC;AACvD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6CAA6C,CAAC;AAC5D,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,oCAAoC,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAChF,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,oCAAoC,CAAC;AACnD,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAE1C,cAAc,oCAAoC,CAAC;AACnD,cAAc,kCAAkC,CAAC;AACjD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wCAAwC,CAAC;AACvD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6CAA6C,CAAC;AAC5D,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,oCAAoC,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC"}
package/dist/index.js CHANGED
@@ -18,7 +18,8 @@ import { headerCheckMiddleware } from "./api/headerCheckMiddleware.js";
18
18
  import { ignoreMiddleware } from "./api/ignoreMiddleware.js";
19
19
  import { robotsMiddleware } from "./api/robotsMiddleware.js";
20
20
  import { getClientApiPathsExpectingProsopoHeaders, getUserFromJWT, isTlsAvailable, startProviderApi } from "./api/startProviderApi.js";
21
+ import { migrateFrictionlessLadder, runFrictionlessLadderMigration } from "./migrations/frictionlessLadder.js";
21
22
  import { storeCaptchasExternally } from "./schedulers/captchaScheduler.js";
22
23
  import { getClientList } from "./schedulers/getClientList.js";
23
24
  import { updateSpamEmailDomainsScheduler } from "./schedulers/updateSpamEmailDomains.js";
24
- export { BlacklistRequestInspector, DEFAULT_JA4, FrictionlessReason, Tasks, asyncHandler, blockMiddleware, checkIfTaskIsRunning, compareIPs, createApiAdminRoutesProvider, deepValidateIpAddress, domainMiddleware, encodeStringAddress, evaluateIpValidationRules, getClientApiPathsExpectingProsopoHeaders, getClientList, getCompositeIpAddress, getHandshakeTiming, getIPAddress, getIPAddressFromBigInt, getIpAddressFromComposite, getJA4, getPrioritisedAccessRule, getRequestUserScope, getUserFromJWT, getVerdictCache, handshakeTimingMiddleware, headerCheckMiddleware, ignoreMiddleware, isTlsAvailable, ja4Middleware, prosopoRouter, prosopoVerifyRouter, publicRouter, rankCandidateRules, robotsMiddleware, shuffleArray, startProviderApi, storeCaptchasExternally, updateSpamEmailDomains, updateSpamEmailDomainsScheduler, validateIpAddress };
25
+ export { BlacklistRequestInspector, DEFAULT_JA4, FrictionlessReason, Tasks, asyncHandler, blockMiddleware, checkIfTaskIsRunning, compareIPs, createApiAdminRoutesProvider, deepValidateIpAddress, domainMiddleware, encodeStringAddress, evaluateIpValidationRules, getClientApiPathsExpectingProsopoHeaders, getClientList, getCompositeIpAddress, getHandshakeTiming, getIPAddress, getIPAddressFromBigInt, getIpAddressFromComposite, getJA4, getPrioritisedAccessRule, getRequestUserScope, getUserFromJWT, getVerdictCache, handshakeTimingMiddleware, headerCheckMiddleware, ignoreMiddleware, isTlsAvailable, ja4Middleware, migrateFrictionlessLadder, prosopoRouter, prosopoVerifyRouter, publicRouter, rankCandidateRules, robotsMiddleware, runFrictionlessLadderMigration, shuffleArray, startProviderApi, storeCaptchasExternally, updateSpamEmailDomains, updateSpamEmailDomainsScheduler, validateIpAddress };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAChF,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,oCAAoC,CAAC;AACnD,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kCAAkC,CAAC;AACjD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wCAAwC,CAAC;AACvD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6CAA6C,CAAC;AAC5D,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,oCAAoC,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAChF,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,oCAAoC,CAAC;AACnD,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAE1C,cAAc,oCAAoC,CAAC;AACnD,cAAc,kCAAkC,CAAC;AACjD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wCAAwC,CAAC;AACvD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6CAA6C,CAAC;AAC5D,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,oCAAoC,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { Logger } from "@prosopo/logger";
2
+ import type { IProviderDatabase } from "@prosopo/types-database";
3
+ export type FrictionlessLadderMigrationResult = {
4
+ scanned: number;
5
+ migrated: number;
6
+ };
7
+ export declare const migrateFrictionlessLadder: (db: IProviderDatabase, logger: Logger) => Promise<FrictionlessLadderMigrationResult>;
8
+ export declare const runFrictionlessLadderMigration: (db: IProviderDatabase, logger: Logger) => Promise<void>;
9
+ //# sourceMappingURL=frictionlessLadder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frictionlessLadder.d.ts","sourceRoot":"","sources":["../../src/migrations/frictionlessLadder.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAE9C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAcjE,MAAM,MAAM,iCAAiC,GAAG;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CACjB,CAAC;AAUF,eAAO,MAAM,yBAAyB,OACjC,iBAAiB,UACb,MAAM,KACZ,OAAO,CAAC,iCAAiC,CAyC3C,CAAC;AAMF,eAAO,MAAM,8BAA8B,OACtC,iBAAiB,UACb,MAAM,KACZ,OAAO,CAAC,IAAI,CASd,CAAC"}
@@ -0,0 +1,58 @@
1
+ import { resolveFrictionlessThreshold } from "@prosopo/types";
2
+ //#region src/migrations/frictionlessLadder.ts
3
+ /** Already the ladder object? Anything else gets rewritten. */
4
+ var isLadder = (value) => typeof value === "object" && value !== null && "frictionlessPuzzleThreshold" in value && "frictionlessImageThreshold" in value;
5
+ /**
6
+ * Rewrite any pre-ladder `frictionlessThreshold` on this provider's client
7
+ * records. Each record's existing number becomes its puzzle rung verbatim, so
8
+ * no site's silent-pass boundary moves.
9
+ *
10
+ * Idempotent — records already carrying the object shape are skipped, so
11
+ * restarting the container repeatedly is free after the first pass.
12
+ */
13
+ var migrateFrictionlessLadder = async (db, logger) => {
14
+ const clients = db.tables?.client;
15
+ if (!clients) {
16
+ logger.warn(() => ({ msg: "Frictionless ladder migration skipped - no client table" }));
17
+ return {
18
+ scanned: 0,
19
+ migrated: 0
20
+ };
21
+ }
22
+ const records = await clients.find().lean();
23
+ const ops = records.filter((record) => record.account !== void 0 && !isLadder(record.settings?.frictionlessThreshold)).map((record) => {
24
+ const current = record.settings?.frictionlessThreshold;
25
+ return { updateOne: {
26
+ filter: { account: record.account },
27
+ update: { $set: { "settings.frictionlessThreshold": resolveFrictionlessThreshold(typeof current === "number" ? current : void 0) } }
28
+ } };
29
+ });
30
+ if (ops.length > 0) await clients.bulkWrite(ops);
31
+ logger.info(() => ({
32
+ msg: "Frictionless ladder migration complete",
33
+ data: {
34
+ scanned: records.length,
35
+ migrated: ops.length
36
+ }
37
+ }));
38
+ return {
39
+ scanned: records.length,
40
+ migrated: ops.length
41
+ };
42
+ };
43
+ /**
44
+ * Boot-time wrapper. Never throws: a failed migration must not stop the
45
+ * provider from serving, because the read path already handles the old shape.
46
+ */
47
+ var runFrictionlessLadderMigration = async (db, logger) => {
48
+ try {
49
+ await migrateFrictionlessLadder(db, logger);
50
+ } catch (err) {
51
+ logger.error(() => ({
52
+ err,
53
+ msg: "Frictionless ladder migration failed - continuing startup"
54
+ }));
55
+ }
56
+ };
57
+ //#endregion
58
+ export { migrateFrictionlessLadder, runFrictionlessLadderMigration };