@prosopo/provider 5.8.0 → 5.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build$colon$cjs.log +15 -11
- package/.turbo/turbo-build$colon$tsc.log +29 -26
- package/.turbo/turbo-build.log +18 -14
- package/CHANGELOG.md +162 -0
- package/dist/api/blacklistRequestInspector.d.ts +1 -1
- package/dist/api/blacklistRequestInspector.d.ts.map +1 -1
- package/dist/api/blacklistRequestInspector.js +4 -2
- package/dist/api/blacklistRequestInspector.js.map +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.d.ts.map +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js +36 -5
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js.map +1 -1
- package/dist/api/captcha/getImageCaptchaChallenge.d.ts.map +1 -1
- package/dist/api/captcha/getImageCaptchaChallenge.js +3 -1
- package/dist/api/captcha/getImageCaptchaChallenge.js.map +1 -1
- package/dist/api/captcha/signedAssetsResolver.d.ts +20 -0
- package/dist/api/captcha/signedAssetsResolver.d.ts.map +1 -0
- package/dist/api/captcha/signedAssetsResolver.js +53 -0
- package/dist/api/captcha/signedAssetsResolver.js.map +1 -0
- package/dist/api/verify.d.ts.map +1 -1
- package/dist/api/verify.js +83 -0
- package/dist/api/verify.js.map +1 -1
- package/dist/cjs/api/blacklistRequestInspector.cjs +4 -2
- package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/handler.cjs +36 -5
- package/dist/cjs/api/captcha/getImageCaptchaChallenge.cjs +3 -1
- package/dist/cjs/api/captcha/signedAssetsResolver.cjs +54 -0
- package/dist/cjs/api/verify.cjs +83 -0
- package/dist/cjs/tasks/detection/getBotScore.cjs +3 -1
- package/dist/cjs/tasks/frictionless/frictionlessTasks.cjs +90 -2
- package/dist/cjs/tasks/frictionless/ipMatch.cjs +45 -0
- package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasks.cjs +1 -1
- package/dist/cjs/tasks/powCaptcha/powTasks.cjs +1 -1
- package/dist/cjs/tasks/puzzleCaptcha/puzzleTasks.cjs +1 -1
- package/dist/tasks/detection/getBotScore.d.ts +2 -0
- package/dist/tasks/detection/getBotScore.d.ts.map +1 -1
- package/dist/tasks/detection/getBotScore.js +3 -1
- package/dist/tasks/detection/getBotScore.js.map +1 -1
- package/dist/tasks/frictionless/frictionlessTasks.d.ts +5 -0
- package/dist/tasks/frictionless/frictionlessTasks.d.ts.map +1 -1
- package/dist/tasks/frictionless/frictionlessTasks.js +91 -3
- package/dist/tasks/frictionless/frictionlessTasks.js.map +1 -1
- package/dist/tasks/frictionless/ipMatch.d.ts +3 -0
- package/dist/tasks/frictionless/ipMatch.d.ts.map +1 -0
- package/dist/tasks/frictionless/ipMatch.js +45 -0
- package/dist/tasks/frictionless/ipMatch.js.map +1 -0
- package/dist/tasks/frictionless/routingMachine.d.ts +1 -0
- package/dist/tasks/frictionless/routingMachine.d.ts.map +1 -1
- package/dist/tasks/frictionless/routingMachine.js.map +1 -1
- package/dist/tasks/imgCaptcha/imgCaptchaTasks.js +1 -1
- package/dist/tasks/powCaptcha/powTasks.js +1 -1
- package/dist/tasks/puzzleCaptcha/puzzleTasks.js +1 -1
- package/dist/tests/integration/api/admin/apiRegisterSiteKeyEndpoint.integration.test.js +3 -1
- package/dist/tests/integration/api/admin/apiRegisterSiteKeyEndpoint.integration.test.js.map +1 -1
- package/dist/tests/integration/clientSettingsPersistence.integration.test.js +2 -1
- package/dist/tests/integration/clientSettingsPersistence.integration.test.js.map +1 -1
- package/dist/tests/integration/webBotAuthAuthenticated.integration.test.d.ts +2 -0
- package/dist/tests/integration/webBotAuthAuthenticated.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/webBotAuthAuthenticated.integration.test.js +448 -0
- package/dist/tests/integration/webBotAuthAuthenticated.integration.test.js.map +1 -0
- package/dist/tests/unit/api/admin/apiRegisterSiteKeyEndpoint.unit.test.js +2 -1
- package/dist/tests/unit/api/admin/apiRegisterSiteKeyEndpoint.unit.test.js.map +1 -1
- package/dist/tests/unit/api/getFrictionlessCaptchaChallenge.unit.test.js +26 -0
- package/dist/tests/unit/api/getFrictionlessCaptchaChallenge.unit.test.js.map +1 -1
- package/dist/tests/unit/signedAssetsResolver.unit.test.d.ts +2 -0
- package/dist/tests/unit/signedAssetsResolver.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/signedAssetsResolver.unit.test.js +77 -0
- package/dist/tests/unit/signedAssetsResolver.unit.test.js.map +1 -0
- package/dist/tests/unit/tasks/captchaManager.unit.test.js +2 -1
- package/dist/tests/unit/tasks/captchaManager.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/frictionless/ipMatch.unit.test.d.ts +2 -0
- package/dist/tests/unit/tasks/frictionless/ipMatch.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/tasks/frictionless/ipMatch.unit.test.js +107 -0
- package/dist/tests/unit/tasks/frictionless/ipMatch.unit.test.js.map +1 -0
- package/dist/tests/unit/tasks/frictionless/routerPuzzleOverrides.unit.test.js +88 -1
- package/dist/tests/unit/tasks/frictionless/routerPuzzleOverrides.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/puzzleMaxDifficultyMatchesLadder.unit.test.d.ts +2 -0
- package/dist/tests/unit/tasks/puzzleMaxDifficultyMatchesLadder.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/tasks/puzzleMaxDifficultyMatchesLadder.unit.test.js +16 -0
- package/dist/tests/unit/tasks/puzzleMaxDifficultyMatchesLadder.unit.test.js.map +1 -0
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js.map +1 -1
- package/package.json +16 -14
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
let node_crypto = require("node:crypto");
|
|
2
|
+
var SignedAssetsResolver = class {
|
|
3
|
+
constructor(options) {
|
|
4
|
+
this.securityKey = options.securityKey;
|
|
5
|
+
this.ttlSeconds = options.ttlSeconds ?? 300;
|
|
6
|
+
this.clientIp = options.clientIp;
|
|
7
|
+
this.now = options.now ?? (() => Date.now());
|
|
8
|
+
}
|
|
9
|
+
sign(path, expires) {
|
|
10
|
+
const base = `${this.securityKey}${path}${expires}${this.clientIp ?? ""}`;
|
|
11
|
+
return (0, node_crypto.createHash)("sha256").update(base).digest("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
12
|
+
}
|
|
13
|
+
resolveAsset(assetURI) {
|
|
14
|
+
const url = this.toUrl(assetURI);
|
|
15
|
+
if (!url) return {
|
|
16
|
+
URI: assetURI,
|
|
17
|
+
getURL: () => assetURI
|
|
18
|
+
};
|
|
19
|
+
if (url.search !== "") throw new Error(`Cannot sign an asset URL that already has a query string: ${assetURI}`);
|
|
20
|
+
const expires = Math.floor(this.now() / 1e3) + this.ttlSeconds;
|
|
21
|
+
const token = this.sign(url.pathname, expires);
|
|
22
|
+
const signed = `${url.origin}${url.pathname}?token=${token}&expires=${expires}`;
|
|
23
|
+
return {
|
|
24
|
+
URI: assetURI,
|
|
25
|
+
getURL: () => signed
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
toUrl(assetURI) {
|
|
29
|
+
try {
|
|
30
|
+
const url = new URL(assetURI);
|
|
31
|
+
return url.protocol === "http:" || url.protocol === "https:" ? url : void 0;
|
|
32
|
+
} catch {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Build the resolver from the environment, or `undefined` when it is not
|
|
39
|
+
* configured. Undefined means `parseCaptchaAssets` passes `item.data`
|
|
40
|
+
* through unchanged — the behaviour before this existed — so the feature is
|
|
41
|
+
* off until a key is deliberately supplied.
|
|
42
|
+
*/
|
|
43
|
+
function getSignedAssetsResolver(clientIp) {
|
|
44
|
+
const securityKey = process.env.PROSOPO_ASSET_TOKEN_KEY;
|
|
45
|
+
if (!securityKey) return;
|
|
46
|
+
return new SignedAssetsResolver({
|
|
47
|
+
securityKey,
|
|
48
|
+
ttlSeconds: Number.parseInt(process.env.PROSOPO_ASSET_TOKEN_TTL_SECONDS ?? "", 10) || 300,
|
|
49
|
+
...process.env.PROSOPO_ASSET_TOKEN_BIND_IP === "true" && clientIp ? { clientIp } : {}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
exports.SignedAssetsResolver = SignedAssetsResolver;
|
|
54
|
+
exports.getSignedAssetsResolver = getSignedAssetsResolver;
|
package/dist/cjs/api/verify.cjs
CHANGED
|
@@ -331,6 +331,89 @@ function prosopoVerifyRouter(env) {
|
|
|
331
331
|
}));
|
|
332
332
|
}
|
|
333
333
|
});
|
|
334
|
+
/**
|
|
335
|
+
* Verify a Web Bot Auth authenticated session token. Enforces IP binding:
|
|
336
|
+
* the operator MUST forward `ip` in the request body, and it must equal
|
|
337
|
+
* the client IP captured on the session at frictionless issuance. Only
|
|
338
|
+
* tokens minted with captchaType=authenticated are accepted here; a
|
|
339
|
+
* regular image/pow/puzzle token routed to this endpoint fails with
|
|
340
|
+
* INCORRECT_CAPTCHA_TYPE.
|
|
341
|
+
*/
|
|
342
|
+
router.post(_prosopo_types.ClientApiPaths.VerifyAuthenticatedSession, async (req, res, next) => {
|
|
343
|
+
if (require_apiToggleMaintenanceModeEndpoint.getMaintenanceMode()) {
|
|
344
|
+
const verificationResponse = require_maintenanceModeResponses.buildMaintenanceVerificationResponse(req.i18n.t);
|
|
345
|
+
return res.json(verificationResponse);
|
|
346
|
+
}
|
|
347
|
+
let parsed;
|
|
348
|
+
try {
|
|
349
|
+
parsed = _prosopo_types.VerifySolutionBody.parse(req.body);
|
|
350
|
+
} catch (err) {
|
|
351
|
+
return next(new _prosopo_common.ProsopoApiError("CAPTCHA.PARSE_ERROR", {
|
|
352
|
+
context: {
|
|
353
|
+
code: 400,
|
|
354
|
+
error: err,
|
|
355
|
+
body: req.body
|
|
356
|
+
},
|
|
357
|
+
i18n: req.i18n,
|
|
358
|
+
logger: req.logger
|
|
359
|
+
}));
|
|
360
|
+
}
|
|
361
|
+
const { dappSignature, token, ip, clientSessionId } = parsed;
|
|
362
|
+
try {
|
|
363
|
+
const { user, dapp, timestamp, commitmentId: sessionId, providerUrl } = (0, _prosopo_types.decodeProcaptchaOutput)(token);
|
|
364
|
+
const testVerdict = require_testSiteKey.resolveTestSiteKeyVerdict(dapp, req.logger);
|
|
365
|
+
if (testVerdict !== null) return res.json({
|
|
366
|
+
status: "ok",
|
|
367
|
+
verified: testVerdict
|
|
368
|
+
});
|
|
369
|
+
const forwarded = await require_forwardVerify.forwardVerifyIfNotIssuer({
|
|
370
|
+
env,
|
|
371
|
+
logger: req.logger,
|
|
372
|
+
path: _prosopo_types.ClientApiPaths.VerifyAuthenticatedSession,
|
|
373
|
+
providerUrl,
|
|
374
|
+
dapp,
|
|
375
|
+
user,
|
|
376
|
+
body: parsed,
|
|
377
|
+
alreadyForwarded: req.headers[_prosopo_api.VERIFY_FORWARDED_HEADER] !== void 0
|
|
378
|
+
});
|
|
379
|
+
if (forwarded) return res.json(forwarded);
|
|
380
|
+
const tasks = new require_tasks.Tasks(env, req.logger);
|
|
381
|
+
(0, _prosopo_util_crypto.validateAddress)(dapp, false, 42);
|
|
382
|
+
(0, _prosopo_util_crypto.validateAddress)(user, false, 42);
|
|
383
|
+
if (!await tasks.db.getClientRecord(dapp)) return next(new _prosopo_common.ProsopoApiError("API.SITE_KEY_NOT_REGISTERED", {
|
|
384
|
+
context: {
|
|
385
|
+
code: 400,
|
|
386
|
+
siteKey: dapp,
|
|
387
|
+
user
|
|
388
|
+
},
|
|
389
|
+
i18n: req.i18n,
|
|
390
|
+
logger: req.logger
|
|
391
|
+
}));
|
|
392
|
+
const keyPair = env.keyring.addFromAddress(dapp);
|
|
393
|
+
(0, _prosopo_api_express_router.verifySignature)(dappSignature, timestamp.toString(), keyPair);
|
|
394
|
+
if (!sessionId) return res.json({
|
|
395
|
+
status: "API.USER_NOT_VERIFIED_NO_SOLUTION",
|
|
396
|
+
verified: false
|
|
397
|
+
});
|
|
398
|
+
const outcome = await tasks.frictionlessManager.verifyAuthenticatedSession(sessionId, ip, clientSessionId);
|
|
399
|
+
res.json(outcome);
|
|
400
|
+
} catch (err) {
|
|
401
|
+
req.logger.error(() => ({
|
|
402
|
+
err,
|
|
403
|
+
msg: "Error in verifyAuthenticatedSession",
|
|
404
|
+
data: { body: req.body }
|
|
405
|
+
}));
|
|
406
|
+
return next(new _prosopo_common.ProsopoApiError("API.BAD_REQUEST", {
|
|
407
|
+
context: {
|
|
408
|
+
code: 500,
|
|
409
|
+
siteKey: req.body.dapp,
|
|
410
|
+
user: req.body.user
|
|
411
|
+
},
|
|
412
|
+
i18n: req.i18n,
|
|
413
|
+
logger: req.logger
|
|
414
|
+
}));
|
|
415
|
+
}
|
|
416
|
+
});
|
|
334
417
|
router.use(_prosopo_api_express_router.handleErrors);
|
|
335
418
|
return router;
|
|
336
419
|
}
|
|
@@ -21,6 +21,7 @@ var getBotScore = async (payload, headHash, privateKeyString, innerConfigEncoded
|
|
|
21
21
|
const md = result.md;
|
|
22
22
|
const bn = result.bn;
|
|
23
23
|
const fs = result.fs;
|
|
24
|
+
const b = result.b;
|
|
24
25
|
if (baseBotScore === void 0 || Number.isNaN(baseBotScore)) return {
|
|
25
26
|
baseBotScore: 1,
|
|
26
27
|
timestamp: 0
|
|
@@ -44,7 +45,8 @@ var getBotScore = async (payload, headHash, privateKeyString, innerConfigEncoded
|
|
|
44
45
|
sw,
|
|
45
46
|
md,
|
|
46
47
|
bn,
|
|
47
|
-
fs
|
|
48
|
+
fs,
|
|
49
|
+
b
|
|
48
50
|
};
|
|
49
51
|
};
|
|
50
52
|
//#endregion
|
|
@@ -2,10 +2,12 @@ const require_usageCounters = require("../../util/usageCounters.cjs");
|
|
|
2
2
|
const require_decisionMachineRunner = require("../decisionMachine/decisionMachineRunner.cjs");
|
|
3
3
|
const require_dnsEventUrl = require("../../api/dnsEventUrl.cjs");
|
|
4
4
|
const require_lang = require("../../rules/lang.cjs");
|
|
5
|
+
const require_clientMetaData = require("../../utils/clientMetaData.cjs");
|
|
5
6
|
const require_captchaManager = require("../captchaManager.cjs");
|
|
6
7
|
const require_captchaTypeSelection = require("../captchaTypeSelection.cjs");
|
|
7
8
|
const require_getBotScore = require("../detection/getBotScore.cjs");
|
|
8
9
|
const require_puzzleDifficulty = require("../puzzle/puzzleDifficulty.cjs");
|
|
10
|
+
const require_ipMatch = require("./ipMatch.cjs");
|
|
9
11
|
const require_routingMachine = require("./routingMachine.cjs");
|
|
10
12
|
let _prosopo_types = require("@prosopo/types");
|
|
11
13
|
let _prosopo_captcha_severity = require("@prosopo/captcha-severity");
|
|
@@ -172,6 +174,91 @@ var FrictionlessManager = class extends require_captchaManager.CaptchaManager {
|
|
|
172
174
|
}
|
|
173
175
|
return sessionRecord;
|
|
174
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* Dedicated issuance path for Web Bot Auth verified requests. The signature
|
|
179
|
+
* verification already carried the trust decision; there is no captcha to
|
|
180
|
+
* solve, no bot score to compute, no routing to run. The session is minted
|
|
181
|
+
* with `captchaType: authenticated`, `agent: true`, `webBotAuthAgent` set to
|
|
182
|
+
* the verified Signature-Agent URL, and `ipAddress` frozen for the verify-
|
|
183
|
+
* time IP-binding check. Consumed only by `/client/authenticated/verify`.
|
|
184
|
+
*/
|
|
185
|
+
async createAuthenticatedSession(token, ipAddress, webBotAuthAgent, siteKey, userSitekeyIpHash, headers, ipInfo, clientSessionId) {
|
|
186
|
+
const sessionRecord = {
|
|
187
|
+
sessionId: `${getSessionIDPrefix(this.config.host)}-${(0, uuid.v4)()}`,
|
|
188
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
189
|
+
token,
|
|
190
|
+
score: 0,
|
|
191
|
+
threshold: 0,
|
|
192
|
+
scoreComponents: { baseScore: 0 },
|
|
193
|
+
ipAddress,
|
|
194
|
+
captchaType: _prosopo_types.CaptchaType.authenticated,
|
|
195
|
+
userSitekeyIpHash,
|
|
196
|
+
webView: false,
|
|
197
|
+
iFrame: false,
|
|
198
|
+
decryptedHeadHash: "",
|
|
199
|
+
siteKey,
|
|
200
|
+
serverChecked: false,
|
|
201
|
+
agent: true,
|
|
202
|
+
webBotAuthAgent,
|
|
203
|
+
...ipInfo && { ipInfo },
|
|
204
|
+
...headers && { headers },
|
|
205
|
+
...clientSessionId && { clientMetaData: { clientSessionId } }
|
|
206
|
+
};
|
|
207
|
+
await this.db.storeSessionRecord(sessionRecord);
|
|
208
|
+
if (this.writeQueue) {
|
|
209
|
+
const cacheData = sessionRecord;
|
|
210
|
+
const cachePromises = [this.writeQueue.cacheSession(sessionRecord.sessionId, cacheData)];
|
|
211
|
+
if (userSitekeyIpHash) cachePromises.push(this.writeQueue.cacheSessionByHash(userSitekeyIpHash, sessionRecord.sessionId));
|
|
212
|
+
await Promise.all(cachePromises).catch(() => {});
|
|
213
|
+
}
|
|
214
|
+
return sessionRecord;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Verify an authenticated (Web Bot Auth) session. Called from
|
|
218
|
+
* `/client/authenticated/verify` after the operator forwards their
|
|
219
|
+
* dApp-signed token. Enforces the four properties that make replay
|
|
220
|
+
* infeasible:
|
|
221
|
+
* 1. session exists and was minted with captchaType=authenticated
|
|
222
|
+
* (so ordinary captcha tokens can't be redeemed here)
|
|
223
|
+
* 2. session hasn't been consumed (serverChecked === false)
|
|
224
|
+
* 3. operator forwarded the client IP (`ip` is required — silently
|
|
225
|
+
* dropping the check would nullify the whole binding)
|
|
226
|
+
* 4. the forwarded IP matches the IP the session was issued to
|
|
227
|
+
*
|
|
228
|
+
* Marks serverChecked=true on success so subsequent verifies fail loudly.
|
|
229
|
+
*/
|
|
230
|
+
async verifyAuthenticatedSession(sessionId, ip, clientSessionId) {
|
|
231
|
+
if (!ip) return {
|
|
232
|
+
verified: false,
|
|
233
|
+
status: "API.AUTHENTICATED_IP_REQUIRED"
|
|
234
|
+
};
|
|
235
|
+
const session = await this.db.getSessionRecordBySessionId(sessionId);
|
|
236
|
+
if (!session) return {
|
|
237
|
+
verified: false,
|
|
238
|
+
status: "API.USER_NOT_VERIFIED_NO_SOLUTION"
|
|
239
|
+
};
|
|
240
|
+
if (session.captchaType !== _prosopo_types.CaptchaType.authenticated) return {
|
|
241
|
+
verified: false,
|
|
242
|
+
status: "API.INCORRECT_CAPTCHA_TYPE"
|
|
243
|
+
};
|
|
244
|
+
if (session.serverChecked) return {
|
|
245
|
+
verified: false,
|
|
246
|
+
status: "API.USER_ALREADY_VERIFIED"
|
|
247
|
+
};
|
|
248
|
+
if (!require_ipMatch.ipMatchesSession(ip, session.ipAddress)) return {
|
|
249
|
+
verified: false,
|
|
250
|
+
status: "API.AUTHENTICATED_IP_MISMATCH"
|
|
251
|
+
};
|
|
252
|
+
if (require_clientMetaData.isClientSessionMismatch(clientSessionId, session.clientMetaData?.clientSessionId)) return {
|
|
253
|
+
verified: false,
|
|
254
|
+
status: "API.CLIENT_SESSION_MISMATCH"
|
|
255
|
+
};
|
|
256
|
+
await this.db.updateSessionRecord(sessionId, { serverChecked: true });
|
|
257
|
+
return {
|
|
258
|
+
verified: true,
|
|
259
|
+
status: "API.USER_VERIFIED"
|
|
260
|
+
};
|
|
261
|
+
}
|
|
175
262
|
async sendImageCaptcha(params) {
|
|
176
263
|
return this.sendCaptcha(_prosopo_types.CaptchaType.image, params);
|
|
177
264
|
}
|
|
@@ -198,8 +285,10 @@ var FrictionlessManager = class extends require_captchaManager.CaptchaManager {
|
|
|
198
285
|
const imageRoundsBounds = this.routingContext ?? {};
|
|
199
286
|
const finalSolvedImagesCount = finalCaptchaType === _prosopo_types.CaptchaType.image ? requestedSolvedImagesCount !== void 0 ? (0, _prosopo_types.clampImageRounds)(requestedSolvedImagesCount, imageRoundsBounds) : requestedSolvedImagesCount : void 0;
|
|
200
287
|
const finalPowDifficulty = finalCaptchaType === _prosopo_types.CaptchaType.pow ? routed.powDifficulty ?? effectiveParams.powDifficulty : void 0;
|
|
288
|
+
const finalReason = routed.reason ?? effectiveParams.reason;
|
|
201
289
|
const finalPuzzleOverrides = finalCaptchaType === _prosopo_types.CaptchaType.puzzle ? (() => {
|
|
202
|
-
const
|
|
290
|
+
const maxLevel = this.routingContext?.puzzleMaxDifficulty ?? _prosopo_types.puzzleMaxDifficultyDefault;
|
|
291
|
+
const level = finalReason !== void 0 && _prosopo_types.NO_MEASUREMENT_REASONS.has(finalReason) ? 0 : (0, _prosopo_captcha_severity.severityToPuzzleDifficulty)(requestedSolvedImagesCount, this.routingContext?.baseImageRounds ?? this.config.captchas.solved.count, maxLevel);
|
|
203
292
|
const difficulty = level > 0 ? require_puzzleDifficulty.samplePuzzleDifficulty(level, _prosopo_puzzle_assets.DEFAULT_RENDER_SETTINGS.holeDarken) : void 0;
|
|
204
293
|
const tolerance = routed.puzzleTolerance ?? difficulty?.tolerance;
|
|
205
294
|
const puzzle = routed.puzzle || difficulty ? {
|
|
@@ -211,7 +300,6 @@ var FrictionlessManager = class extends require_captchaManager.CaptchaManager {
|
|
|
211
300
|
...puzzle !== void 0 && { puzzle }
|
|
212
301
|
};
|
|
213
302
|
})() : {};
|
|
214
|
-
const finalReason = routed.reason ?? effectiveParams.reason;
|
|
215
303
|
const blocked = finalCaptchaType === _prosopo_types.CaptchaType.image ? effectiveParams.blocked : void 0;
|
|
216
304
|
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, finalReason, 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, {
|
|
217
305
|
synNs: effectiveParams.synNs,
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const require_compositeIpAddress = require("../../compositeIpAddress.cjs");
|
|
2
|
+
//#region src/tasks/frictionless/ipMatch.ts
|
|
3
|
+
/**
|
|
4
|
+
* `CompositeIpAddress` types its halves as `bigint`, but that is only true of
|
|
5
|
+
* a value just built by `getCompositeIpAddress`. Read back off a session the
|
|
6
|
+
* halves are whatever BSON stored — a `Decimal128`, or a `Long` on records
|
|
7
|
+
* written before the Decimal128 migration — so `===` against a real bigint is
|
|
8
|
+
* false for every session that has been through Mongo. Both BSON types
|
|
9
|
+
* stringify to plain digits at IP magnitudes (≤ 2^64, well inside
|
|
10
|
+
* Decimal128's 34 significant digits), so a string round-trip is exact.
|
|
11
|
+
*
|
|
12
|
+
* `null` for anything unparseable rather than a 0n default: two unparseable
|
|
13
|
+
* halves must not compare equal, or garbage would match garbage.
|
|
14
|
+
*/
|
|
15
|
+
var asBigInt = (half) => {
|
|
16
|
+
if (typeof half === "bigint") return half;
|
|
17
|
+
if (half === void 0 || half === null) return 0n;
|
|
18
|
+
try {
|
|
19
|
+
return BigInt(String(half));
|
|
20
|
+
} catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Compare an operator-supplied plain-string IP against the CompositeIpAddress
|
|
26
|
+
* captured on a session. Returns true iff the parsed IP has the same type
|
|
27
|
+
* (v4/v6) and numeric halves.
|
|
28
|
+
*
|
|
29
|
+
* Load-bearing for Web Bot Auth IP binding — a leaked authenticated token
|
|
30
|
+
* replayed from a different IP fails here. Malformed operator IPs degrade
|
|
31
|
+
* to {lower: 0n, type: v4} inside getCompositeIpAddress and can never match
|
|
32
|
+
* a real session (a real v4 session has a non-zero `lower`; a real v6 has
|
|
33
|
+
* type=v6). That degradation is deliberate: silently treating garbage as a
|
|
34
|
+
* match would nullify the whole binding.
|
|
35
|
+
*/
|
|
36
|
+
var ipMatchesSession = (operatorIp, sessionIp) => {
|
|
37
|
+
const parsed = require_compositeIpAddress.getCompositeIpAddress(operatorIp);
|
|
38
|
+
if (parsed.type !== sessionIp.type) return false;
|
|
39
|
+
const lower = asBigInt(sessionIp.lower);
|
|
40
|
+
const upper = asBigInt(sessionIp.upper);
|
|
41
|
+
if (lower === null || upper === null) return false;
|
|
42
|
+
return parsed.lower === lower && (parsed.upper ?? 0n) === upper;
|
|
43
|
+
};
|
|
44
|
+
//#endregion
|
|
45
|
+
exports.ipMatchesSession = ipMatchesSession;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
const require_usageCounters = require("../../util/usageCounters.cjs");
|
|
2
2
|
const require_decisionMachineRunner = require("../decisionMachine/decisionMachineRunner.cjs");
|
|
3
3
|
const require_lang = require("../../rules/lang.cjs");
|
|
4
|
+
const require_clientMetaData = require("../../utils/clientMetaData.cjs");
|
|
4
5
|
const require_compositeIpAddress = require("../../compositeIpAddress.cjs");
|
|
5
6
|
const require_enrichDnsEvent = require("../dnsEvent/enrichDnsEvent.cjs");
|
|
6
7
|
const require_captchaManager = require("../captchaManager.cjs");
|
|
7
8
|
const require_pairs = require("../../pairs.cjs");
|
|
8
9
|
const require_util = require("../../util.cjs");
|
|
9
|
-
const require_clientMetaData = require("../../utils/clientMetaData.cjs");
|
|
10
10
|
const require_devicePlatform = require("../../utils/devicePlatform.cjs");
|
|
11
11
|
const require_frictionlessTasksUtils = require("../frictionless/frictionlessTasksUtils.cjs");
|
|
12
12
|
const require_evaluateEmailSpamRules = require("../spam/evaluateEmailSpamRules.cjs");
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
const require_usageCounters = require("../../util/usageCounters.cjs");
|
|
2
2
|
const require_decisionMachineRunner = require("../decisionMachine/decisionMachineRunner.cjs");
|
|
3
|
+
const require_clientMetaData = require("../../utils/clientMetaData.cjs");
|
|
3
4
|
const require_compositeIpAddress = require("../../compositeIpAddress.cjs");
|
|
4
5
|
const require_enrichDnsEvent = require("../dnsEvent/enrichDnsEvent.cjs");
|
|
5
6
|
const require_captchaManager = require("../captchaManager.cjs");
|
|
6
7
|
const require_routingMachine = require("../frictionless/routingMachine.cjs");
|
|
7
8
|
const require_util = require("../../util.cjs");
|
|
8
|
-
const require_clientMetaData = require("../../utils/clientMetaData.cjs");
|
|
9
9
|
const require_devicePlatform = require("../../utils/devicePlatform.cjs");
|
|
10
10
|
const require_frictionlessTasksUtils = require("../frictionless/frictionlessTasksUtils.cjs");
|
|
11
11
|
const require_evaluateEmailSpamRules = require("../spam/evaluateEmailSpamRules.cjs");
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
const require_usageCounters = require("../../util/usageCounters.cjs");
|
|
2
2
|
const require_decisionMachineRunner = require("../decisionMachine/decisionMachineRunner.cjs");
|
|
3
|
+
const require_clientMetaData = require("../../utils/clientMetaData.cjs");
|
|
3
4
|
const require_compositeIpAddress = require("../../compositeIpAddress.cjs");
|
|
4
5
|
const require_enrichDnsEvent = require("../dnsEvent/enrichDnsEvent.cjs");
|
|
5
6
|
const require_captchaManager = require("../captchaManager.cjs");
|
|
6
7
|
const require_util = require("../../util.cjs");
|
|
7
|
-
const require_clientMetaData = require("../../utils/clientMetaData.cjs");
|
|
8
8
|
const require_devicePlatform = require("../../utils/devicePlatform.cjs");
|
|
9
9
|
const require_frictionlessTasksUtils = require("../frictionless/frictionlessTasksUtils.cjs");
|
|
10
10
|
const require_evaluateEmailSpamRules = require("../spam/evaluateEmailSpamRules.cjs");
|
|
@@ -18,6 +18,7 @@ export declare const getBotScore: (payload: string, headHash: string, privateKey
|
|
|
18
18
|
md?: undefined;
|
|
19
19
|
bn?: undefined;
|
|
20
20
|
fs?: undefined;
|
|
21
|
+
b?: undefined;
|
|
21
22
|
} | {
|
|
22
23
|
baseBotScore: number;
|
|
23
24
|
timestamp: number;
|
|
@@ -38,5 +39,6 @@ export declare const getBotScore: (payload: string, headHash: string, privateKey
|
|
|
38
39
|
md: boolean | undefined;
|
|
39
40
|
bn: boolean | undefined;
|
|
40
41
|
fs: boolean | undefined;
|
|
42
|
+
b: Record<string, string[]> | undefined;
|
|
41
43
|
}>;
|
|
42
44
|
//# sourceMappingURL=getBotScore.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getBotScore.d.ts","sourceRoot":"","sources":["../../../src/tasks/detection/getBotScore.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,WAAW,YACd,MAAM,YACL,MAAM,qBACG,MAAM,uBACJ,MAAM
|
|
1
|
+
{"version":3,"file":"getBotScore.d.ts","sourceRoot":"","sources":["../../../src/tasks/detection/getBotScore.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,WAAW,YACd,MAAM,YACL,MAAM,qBACG,MAAM,uBACJ,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8D3B,CAAC"}
|
|
@@ -21,6 +21,7 @@ var getBotScore = async (payload, headHash, privateKeyString, innerConfigEncoded
|
|
|
21
21
|
const md = result.md;
|
|
22
22
|
const bn = result.bn;
|
|
23
23
|
const fs = result.fs;
|
|
24
|
+
const b = result.b;
|
|
24
25
|
if (baseBotScore === void 0 || Number.isNaN(baseBotScore)) return {
|
|
25
26
|
baseBotScore: 1,
|
|
26
27
|
timestamp: 0
|
|
@@ -44,7 +45,8 @@ var getBotScore = async (payload, headHash, privateKeyString, innerConfigEncoded
|
|
|
44
45
|
sw,
|
|
45
46
|
md,
|
|
46
47
|
bn,
|
|
47
|
-
fs
|
|
48
|
+
fs,
|
|
49
|
+
b
|
|
48
50
|
};
|
|
49
51
|
};
|
|
50
52
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getBotScore.js","sourceRoot":"","sources":["../../../src/tasks/detection/getBotScore.ts"],"names":[],"mappings":"AAeA,OAAO,sBAAsB,MAAM,oBAAoB,CAAC;AAExD,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAC/B,OAAe,EACf,QAAgB,EAChB,gBAAyB,EACzB,kBAA2B,EAC1B,EAAE;IACH,MAAM,MAAM,GAAG,CAAC,MAAM,sBAAsB,CAC3C,OAAO,EACP,QAAQ,EACR,gBAAgB,EAChB,kBAAkB,CAClB,CAAmB,CAAC;IACrB,MAAM,YAAY,GAAW,MAAM,CAAC,KAAK,CAAC;IAC1C,MAAM,SAAS,GAAW,MAAM,CAAC,SAAS,CAAC;IAC3C,MAAM,MAAM,GAAW,MAAM,CAAC,MAAM,CAAC;IACrC,MAAM,SAAS,GAAW,MAAM,CAAC,SAAS,CAAC;IAC3C,MAAM,SAAS,GAAY,MAAM,CAAC,SAAS,IAAI,KAAK,CAAC;IACrD,MAAM,QAAQ,GAAY,MAAM,CAAC,QAAQ,IAAI,KAAK,CAAC;IACnD,MAAM,iBAAiB,GAAW,MAAM,CAAC,iBAAiB,CAAC;IAC3D,MAAM,kBAAkB,GAAyB,MAAM,CAAC,kBAAkB,CAAC;IAC3E,MAAM,gBAAgB,GAAwB,MAAM,CAAC,gBAAgB,CAAC;IACtE,MAAM,4BAA4B,GACjC,MAAM,CAAC,4BAA4B,CAAC;IACrC,MAAM,wBAAwB,GAC7B,MAAM,CAAC,wBAAwB,CAAC;IACjC,MAAM,wBAAwB,GAC7B,MAAM,CAAC,wBAAwB,CAAC;IACjC,MAAM,sBAAsB,GAC3B,MAAM,CAAC,sBAAsB,CAAC;IAC/B,MAAM,CAAC,GAAuB,MAAM,CAAC,CAAC,CAAC;IACvC,MAAM,CAAC,GAAwB,MAAM,CAAC,CAAC,CAAC;IACxC,MAAM,EAAE,GAAwB,MAAM,CAAC,EAAE,CAAC;IAC1C,MAAM,EAAE,GAAwB,MAAM,CAAC,EAAE,CAAC;IAC1C,MAAM,EAAE,GAAwB,MAAM,CAAC,EAAE,CAAC;IAC1C,MAAM,EAAE,GAAwB,MAAM,CAAC,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"getBotScore.js","sourceRoot":"","sources":["../../../src/tasks/detection/getBotScore.ts"],"names":[],"mappings":"AAeA,OAAO,sBAAsB,MAAM,oBAAoB,CAAC;AAExD,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAC/B,OAAe,EACf,QAAgB,EAChB,gBAAyB,EACzB,kBAA2B,EAC1B,EAAE;IACH,MAAM,MAAM,GAAG,CAAC,MAAM,sBAAsB,CAC3C,OAAO,EACP,QAAQ,EACR,gBAAgB,EAChB,kBAAkB,CAClB,CAAmB,CAAC;IACrB,MAAM,YAAY,GAAW,MAAM,CAAC,KAAK,CAAC;IAC1C,MAAM,SAAS,GAAW,MAAM,CAAC,SAAS,CAAC;IAC3C,MAAM,MAAM,GAAW,MAAM,CAAC,MAAM,CAAC;IACrC,MAAM,SAAS,GAAW,MAAM,CAAC,SAAS,CAAC;IAC3C,MAAM,SAAS,GAAY,MAAM,CAAC,SAAS,IAAI,KAAK,CAAC;IACrD,MAAM,QAAQ,GAAY,MAAM,CAAC,QAAQ,IAAI,KAAK,CAAC;IACnD,MAAM,iBAAiB,GAAW,MAAM,CAAC,iBAAiB,CAAC;IAC3D,MAAM,kBAAkB,GAAyB,MAAM,CAAC,kBAAkB,CAAC;IAC3E,MAAM,gBAAgB,GAAwB,MAAM,CAAC,gBAAgB,CAAC;IACtE,MAAM,4BAA4B,GACjC,MAAM,CAAC,4BAA4B,CAAC;IACrC,MAAM,wBAAwB,GAC7B,MAAM,CAAC,wBAAwB,CAAC;IACjC,MAAM,wBAAwB,GAC7B,MAAM,CAAC,wBAAwB,CAAC;IACjC,MAAM,sBAAsB,GAC3B,MAAM,CAAC,sBAAsB,CAAC;IAC/B,MAAM,CAAC,GAAuB,MAAM,CAAC,CAAC,CAAC;IACvC,MAAM,CAAC,GAAwB,MAAM,CAAC,CAAC,CAAC;IACxC,MAAM,EAAE,GAAwB,MAAM,CAAC,EAAE,CAAC;IAC1C,MAAM,EAAE,GAAwB,MAAM,CAAC,EAAE,CAAC;IAC1C,MAAM,EAAE,GAAwB,MAAM,CAAC,EAAE,CAAC;IAC1C,MAAM,EAAE,GAAwB,MAAM,CAAC,EAAE,CAAC;IAC1C,MAAM,CAAC,GAAyC,MAAM,CAAC,CAAC,CAAC;IAEzD,IAAI,YAAY,KAAK,SAAS,IAAI,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9D,OAAO;YACN,YAAY,EAAE,CAAC;YACf,SAAS,EAAE,CAAC;SACZ,CAAC;IACH,CAAC;IAED,OAAO;QACN,YAAY;QACZ,SAAS;QACT,MAAM;QACN,SAAS;QACT,SAAS;QACT,QAAQ;QACR,iBAAiB;QACjB,kBAAkB;QAClB,gBAAgB;QAChB,4BAA4B;QAC5B,wBAAwB;QACxB,wBAAwB;QACxB,sBAAsB;QACtB,CAAC;QACD,CAAC;QACD,EAAE;QACF,EAAE;QACF,EAAE;QACF,EAAE;QACF,CAAC;KACD,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -27,6 +27,11 @@ export declare class FrictionlessManager extends CaptchaManager {
|
|
|
27
27
|
updateScore(score: number, scoreComponents: ScoreComponents): void;
|
|
28
28
|
checkLangRules(acceptLanguage: string): number;
|
|
29
29
|
createSession(token: string, score: number, threshold: number, scoreComponents: ScoreComponents, ipAddress: CompositeIpAddress, captchaType: CaptchaType, siteKey: string, solvedImagesCount?: number, powDifficulty?: number, userSitekeyIpHash?: string, webView?: boolean, iFrame?: boolean, decryptedHeadHash?: string, reason?: FrictionlessReason, blocked?: boolean, deleted?: boolean, ipInfo?: IPInfoResponse, headers?: RequestHeaders, mode?: ModeEnum, simdReadings?: Session["simdReadings"], entropyMathRandomFingerprint?: Session["entropyMathRandomFingerprint"], entropyCryptoFingerprint?: Session["entropyCryptoFingerprint"], entropyWallClockOffsetMs?: Session["entropyWallClockOffsetMs"], entropyMathRandomFirst?: Session["entropyMathRandomFirst"], bundleId?: Session["bundleId"], currentUrl?: Session["currentUrl"], tcpToChelloUs?: Session["tcpToChelloUs"], chelloToHandshakeUs?: Session["chelloToHandshakeUs"], isEscalation?: Session["isEscalation"], iframeUrl?: Session["iframeUrl"], isProtect?: Session["isProtect"], originSessionId?: Session["originSessionId"], g?: Session["g"], matchedRule?: Session["matchedRule"], i?: Session["i"], sw?: Session["sw"], md?: Session["md"], bn?: Session["bn"], fs?: Session["fs"], rawTlsSignals?: Partial<RawTlsSignals>, puzzleOverrides?: Pick<Session, "puzzleTolerance" | "puzzle">): Promise<Session>;
|
|
30
|
+
createAuthenticatedSession(token: string, ipAddress: CompositeIpAddress, webBotAuthAgent: string, siteKey: string, userSitekeyIpHash?: string, headers?: RequestHeaders, ipInfo?: IPInfoResponse, clientSessionId?: string): Promise<Session>;
|
|
31
|
+
verifyAuthenticatedSession(sessionId: string, ip: string | undefined, clientSessionId: string | undefined): Promise<{
|
|
32
|
+
verified: boolean;
|
|
33
|
+
status: string;
|
|
34
|
+
}>;
|
|
30
35
|
sendImageCaptcha(params?: Partial<ImageCaptchaSessionParams>): Promise<GetFrictionlessCaptchaResponse>;
|
|
31
36
|
sendPowCaptcha(params?: Partial<PowCaptchaSessionParams>): Promise<GetFrictionlessCaptchaResponse>;
|
|
32
37
|
sendPuzzleCaptcha(params?: Partial<PuzzleCaptchaSessionParams>): Promise<GetFrictionlessCaptchaResponse>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frictionlessTasks.d.ts","sourceRoot":"","sources":["../../../src/tasks/frictionless/frictionlessTasks.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAE9C,OAAO,EAEN,WAAW,EACX,KAAK,kBAAkB,EACvB,kBAAkB,EAClB,KAAK,8BAA8B,EACnC,KAAK,cAAc,EAEnB,KAAK,WAAW,EAChB,KAAK,QAAQ,
|
|
1
|
+
{"version":3,"file":"frictionlessTasks.d.ts","sourceRoot":"","sources":["../../../src/tasks/frictionless/frictionlessTasks.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,12 +2,14 @@ import { buildAllWindowIncrements } from "../../util/usageCounters.js";
|
|
|
2
2
|
import { DecisionMachineRunner } from "../decisionMachine/decisionMachineRunner.js";
|
|
3
3
|
import { buildDnsEventUrl } from "../../api/dnsEventUrl.js";
|
|
4
4
|
import { checkLangRules } from "../../rules/lang.js";
|
|
5
|
+
import { isClientSessionMismatch } from "../../utils/clientMetaData.js";
|
|
5
6
|
import { CaptchaManager } from "../captchaManager.js";
|
|
6
7
|
import { coerceToEnabledCaptchaType } from "../captchaTypeSelection.js";
|
|
7
8
|
import { getBotScore } from "../detection/getBotScore.js";
|
|
8
9
|
import { samplePuzzleDifficulty } from "../puzzle/puzzleDifficulty.js";
|
|
10
|
+
import { ipMatchesSession } from "./ipMatch.js";
|
|
9
11
|
import { applyRouter } from "./routingMachine.js";
|
|
10
|
-
import { ApiParams, CaptchaType, FrictionlessReason as FrictionlessReason$1, SimdReadingsStage, clampImageRounds } from "@prosopo/types";
|
|
12
|
+
import { ApiParams, CaptchaType, FrictionlessReason as FrictionlessReason$1, NO_MEASUREMENT_REASONS, SimdReadingsStage, clampImageRounds, puzzleMaxDifficultyDefault } from "@prosopo/types";
|
|
11
13
|
import { severityToPuzzleDifficulty } from "@prosopo/captcha-severity";
|
|
12
14
|
import { DEFAULT_RENDER_SETTINGS } from "@prosopo/puzzle-assets";
|
|
13
15
|
import { v4 } from "uuid";
|
|
@@ -172,6 +174,91 @@ var FrictionlessManager = class extends CaptchaManager {
|
|
|
172
174
|
}
|
|
173
175
|
return sessionRecord;
|
|
174
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* Dedicated issuance path for Web Bot Auth verified requests. The signature
|
|
179
|
+
* verification already carried the trust decision; there is no captcha to
|
|
180
|
+
* solve, no bot score to compute, no routing to run. The session is minted
|
|
181
|
+
* with `captchaType: authenticated`, `agent: true`, `webBotAuthAgent` set to
|
|
182
|
+
* the verified Signature-Agent URL, and `ipAddress` frozen for the verify-
|
|
183
|
+
* time IP-binding check. Consumed only by `/client/authenticated/verify`.
|
|
184
|
+
*/
|
|
185
|
+
async createAuthenticatedSession(token, ipAddress, webBotAuthAgent, siteKey, userSitekeyIpHash, headers, ipInfo, clientSessionId) {
|
|
186
|
+
const sessionRecord = {
|
|
187
|
+
sessionId: `${getSessionIDPrefix(this.config.host)}-${v4()}`,
|
|
188
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
189
|
+
token,
|
|
190
|
+
score: 0,
|
|
191
|
+
threshold: 0,
|
|
192
|
+
scoreComponents: { baseScore: 0 },
|
|
193
|
+
ipAddress,
|
|
194
|
+
captchaType: CaptchaType.authenticated,
|
|
195
|
+
userSitekeyIpHash,
|
|
196
|
+
webView: false,
|
|
197
|
+
iFrame: false,
|
|
198
|
+
decryptedHeadHash: "",
|
|
199
|
+
siteKey,
|
|
200
|
+
serverChecked: false,
|
|
201
|
+
agent: true,
|
|
202
|
+
webBotAuthAgent,
|
|
203
|
+
...ipInfo && { ipInfo },
|
|
204
|
+
...headers && { headers },
|
|
205
|
+
...clientSessionId && { clientMetaData: { clientSessionId } }
|
|
206
|
+
};
|
|
207
|
+
await this.db.storeSessionRecord(sessionRecord);
|
|
208
|
+
if (this.writeQueue) {
|
|
209
|
+
const cacheData = sessionRecord;
|
|
210
|
+
const cachePromises = [this.writeQueue.cacheSession(sessionRecord.sessionId, cacheData)];
|
|
211
|
+
if (userSitekeyIpHash) cachePromises.push(this.writeQueue.cacheSessionByHash(userSitekeyIpHash, sessionRecord.sessionId));
|
|
212
|
+
await Promise.all(cachePromises).catch(() => {});
|
|
213
|
+
}
|
|
214
|
+
return sessionRecord;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Verify an authenticated (Web Bot Auth) session. Called from
|
|
218
|
+
* `/client/authenticated/verify` after the operator forwards their
|
|
219
|
+
* dApp-signed token. Enforces the four properties that make replay
|
|
220
|
+
* infeasible:
|
|
221
|
+
* 1. session exists and was minted with captchaType=authenticated
|
|
222
|
+
* (so ordinary captcha tokens can't be redeemed here)
|
|
223
|
+
* 2. session hasn't been consumed (serverChecked === false)
|
|
224
|
+
* 3. operator forwarded the client IP (`ip` is required — silently
|
|
225
|
+
* dropping the check would nullify the whole binding)
|
|
226
|
+
* 4. the forwarded IP matches the IP the session was issued to
|
|
227
|
+
*
|
|
228
|
+
* Marks serverChecked=true on success so subsequent verifies fail loudly.
|
|
229
|
+
*/
|
|
230
|
+
async verifyAuthenticatedSession(sessionId, ip, clientSessionId) {
|
|
231
|
+
if (!ip) return {
|
|
232
|
+
verified: false,
|
|
233
|
+
status: "API.AUTHENTICATED_IP_REQUIRED"
|
|
234
|
+
};
|
|
235
|
+
const session = await this.db.getSessionRecordBySessionId(sessionId);
|
|
236
|
+
if (!session) return {
|
|
237
|
+
verified: false,
|
|
238
|
+
status: "API.USER_NOT_VERIFIED_NO_SOLUTION"
|
|
239
|
+
};
|
|
240
|
+
if (session.captchaType !== CaptchaType.authenticated) return {
|
|
241
|
+
verified: false,
|
|
242
|
+
status: "API.INCORRECT_CAPTCHA_TYPE"
|
|
243
|
+
};
|
|
244
|
+
if (session.serverChecked) return {
|
|
245
|
+
verified: false,
|
|
246
|
+
status: "API.USER_ALREADY_VERIFIED"
|
|
247
|
+
};
|
|
248
|
+
if (!ipMatchesSession(ip, session.ipAddress)) return {
|
|
249
|
+
verified: false,
|
|
250
|
+
status: "API.AUTHENTICATED_IP_MISMATCH"
|
|
251
|
+
};
|
|
252
|
+
if (isClientSessionMismatch(clientSessionId, session.clientMetaData?.clientSessionId)) return {
|
|
253
|
+
verified: false,
|
|
254
|
+
status: "API.CLIENT_SESSION_MISMATCH"
|
|
255
|
+
};
|
|
256
|
+
await this.db.updateSessionRecord(sessionId, { serverChecked: true });
|
|
257
|
+
return {
|
|
258
|
+
verified: true,
|
|
259
|
+
status: "API.USER_VERIFIED"
|
|
260
|
+
};
|
|
261
|
+
}
|
|
175
262
|
async sendImageCaptcha(params) {
|
|
176
263
|
return this.sendCaptcha(CaptchaType.image, params);
|
|
177
264
|
}
|
|
@@ -198,8 +285,10 @@ var FrictionlessManager = class extends CaptchaManager {
|
|
|
198
285
|
const imageRoundsBounds = this.routingContext ?? {};
|
|
199
286
|
const finalSolvedImagesCount = finalCaptchaType === CaptchaType.image ? requestedSolvedImagesCount !== void 0 ? clampImageRounds(requestedSolvedImagesCount, imageRoundsBounds) : requestedSolvedImagesCount : void 0;
|
|
200
287
|
const finalPowDifficulty = finalCaptchaType === CaptchaType.pow ? routed.powDifficulty ?? effectiveParams.powDifficulty : void 0;
|
|
288
|
+
const finalReason = routed.reason ?? effectiveParams.reason;
|
|
201
289
|
const finalPuzzleOverrides = finalCaptchaType === CaptchaType.puzzle ? (() => {
|
|
202
|
-
const
|
|
290
|
+
const maxLevel = this.routingContext?.puzzleMaxDifficulty ?? puzzleMaxDifficultyDefault;
|
|
291
|
+
const level = finalReason !== void 0 && NO_MEASUREMENT_REASONS.has(finalReason) ? 0 : severityToPuzzleDifficulty(requestedSolvedImagesCount, this.routingContext?.baseImageRounds ?? this.config.captchas.solved.count, maxLevel);
|
|
203
292
|
const difficulty = level > 0 ? samplePuzzleDifficulty(level, DEFAULT_RENDER_SETTINGS.holeDarken) : void 0;
|
|
204
293
|
const tolerance = routed.puzzleTolerance ?? difficulty?.tolerance;
|
|
205
294
|
const puzzle = routed.puzzle || difficulty ? {
|
|
@@ -211,7 +300,6 @@ var FrictionlessManager = class extends CaptchaManager {
|
|
|
211
300
|
...puzzle !== void 0 && { puzzle }
|
|
212
301
|
};
|
|
213
302
|
})() : {};
|
|
214
|
-
const finalReason = routed.reason ?? effectiveParams.reason;
|
|
215
303
|
const blocked = finalCaptchaType === CaptchaType.image ? effectiveParams.blocked : void 0;
|
|
216
304
|
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, finalReason, 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, {
|
|
217
305
|
synNs: effectiveParams.synNs,
|