@prosopo/provider 5.0.5 → 5.1.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 +12 -11
- package/.turbo/turbo-build$colon$tsc.log +24 -24
- package/.turbo/turbo-build.log +13 -12
- package/CHANGELOG.md +37 -0
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.d.ts.map +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js +12 -0
- 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 +13 -1
- package/dist/api/captcha/getImageCaptchaChallenge.js.map +1 -1
- package/dist/api/captcha/getPoWCaptchaChallenge.d.ts.map +1 -1
- package/dist/api/captcha/getPoWCaptchaChallenge.js +12 -1
- package/dist/api/captcha/getPoWCaptchaChallenge.js.map +1 -1
- package/dist/api/captcha/getPuzzleCaptchaChallenge.d.ts.map +1 -1
- package/dist/api/captcha/getPuzzleCaptchaChallenge.js +12 -1
- package/dist/api/captcha/getPuzzleCaptchaChallenge.js.map +1 -1
- package/dist/api/captcha/trafficFilterRequestTime.d.ts +38 -0
- package/dist/api/captcha/trafficFilterRequestTime.d.ts.map +1 -0
- package/dist/api/captcha/trafficFilterRequestTime.js +109 -0
- package/dist/api/captcha/trafficFilterRequestTime.js.map +1 -0
- package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/handler.cjs +13 -0
- package/dist/cjs/api/captcha/getImageCaptchaChallenge.cjs +13 -1
- package/dist/cjs/api/captcha/getPoWCaptchaChallenge.cjs +12 -1
- package/dist/cjs/api/captcha/getPuzzleCaptchaChallenge.cjs +12 -1
- package/dist/cjs/api/captcha/trafficFilterRequestTime.cjs +111 -0
- package/dist/cjs/tasks/captchaManager.cjs +13 -6
- package/dist/cjs/tasks/dnsEvent/enrichDnsEvent.cjs +10 -8
- package/dist/cjs/tasks/puzzleCaptcha/puzzleTasks.cjs +2 -3
- package/dist/cjs/tasks/spam/checkTrafficFilter.cjs +101 -75
- package/dist/tasks/captchaManager.d.ts.map +1 -1
- package/dist/tasks/captchaManager.js +14 -7
- package/dist/tasks/captchaManager.js.map +1 -1
- package/dist/tasks/dnsEvent/enrichDnsEvent.d.ts.map +1 -1
- package/dist/tasks/dnsEvent/enrichDnsEvent.js +10 -8
- package/dist/tasks/dnsEvent/enrichDnsEvent.js.map +1 -1
- package/dist/tasks/puzzleCaptcha/puzzleTasks.d.ts.map +1 -1
- package/dist/tasks/puzzleCaptcha/puzzleTasks.js +2 -3
- package/dist/tasks/puzzleCaptcha/puzzleTasks.js.map +1 -1
- package/dist/tasks/spam/checkTrafficFilter.d.ts +18 -1
- package/dist/tasks/spam/checkTrafficFilter.d.ts.map +1 -1
- package/dist/tasks/spam/checkTrafficFilter.js +101 -77
- package/dist/tasks/spam/checkTrafficFilter.js.map +1 -1
- package/dist/tests/integration/clientSettingsPersistence.integration.test.js +24 -17
- package/dist/tests/integration/clientSettingsPersistence.integration.test.js.map +1 -1
- package/dist/tests/integration/trafficFilterHierarchy.integration.test.d.ts +2 -0
- package/dist/tests/integration/trafficFilterHierarchy.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/trafficFilterHierarchy.integration.test.js +215 -0
- package/dist/tests/integration/trafficFilterHierarchy.integration.test.js.map +1 -0
- package/dist/tests/unit/api/captcha/trafficFilterRequestTime.unit.test.d.ts +2 -0
- package/dist/tests/unit/api/captcha/trafficFilterRequestTime.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/api/captcha/trafficFilterRequestTime.unit.test.js +255 -0
- package/dist/tests/unit/api/captcha/trafficFilterRequestTime.unit.test.js.map +1 -0
- package/dist/tests/unit/tasks/dnsEvent/enrichDnsEvent.unit.test.js +6 -9
- package/dist/tests/unit/tasks/dnsEvent/enrichDnsEvent.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/puzzleCaptcha/puzzleTasks.unit.test.js +95 -0
- package/dist/tests/unit/tasks/puzzleCaptcha/puzzleTasks.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/spam/checkTrafficFilter.unit.test.js +272 -98
- package/dist/tests/unit/tasks/spam/checkTrafficFilter.unit.test.js.map +1 -1
- package/package.json +13 -13
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Logger } from "@prosopo/logger";
|
|
2
|
+
import { CaptchaType, type IPInfoResponse, type ITrafficFilter } from "@prosopo/types";
|
|
3
|
+
import type { ClientRecord } from "@prosopo/types-database";
|
|
4
|
+
import type { Response } from "express";
|
|
5
|
+
import type { FrictionlessManager } from "../../tasks/frictionless/frictionlessTasks.js";
|
|
6
|
+
import { type ResolvedChallengePolicy, type TrafficBlockReason } from "../../tasks/spam/checkTrafficFilter.js";
|
|
7
|
+
export type RequestTimeTrafficVerdict = {
|
|
8
|
+
kind: "pass";
|
|
9
|
+
} | {
|
|
10
|
+
kind: "block";
|
|
11
|
+
reason: TrafficBlockReason;
|
|
12
|
+
} | {
|
|
13
|
+
kind: "challenge";
|
|
14
|
+
captchaType: CaptchaType | undefined;
|
|
15
|
+
powDifficulty?: number;
|
|
16
|
+
solvedImagesCount?: number;
|
|
17
|
+
puzzleTolerance?: number;
|
|
18
|
+
sourceCategories: ResolvedChallengePolicy["sourceCategories"];
|
|
19
|
+
};
|
|
20
|
+
export declare const applyTrafficFilterAtRequestTime: (ipInfo: IPInfoResponse | undefined, trafficFilter: Partial<ITrafficFilter> | undefined, logger?: Logger) => RequestTimeTrafficVerdict;
|
|
21
|
+
export type FrictionlessTrafficFilterOutcome = {
|
|
22
|
+
handled: false;
|
|
23
|
+
} | {
|
|
24
|
+
handled: true;
|
|
25
|
+
response: Response;
|
|
26
|
+
};
|
|
27
|
+
export type FrictionlessTrafficFilterInput = {
|
|
28
|
+
verdict: RequestTimeTrafficVerdict;
|
|
29
|
+
frictionlessManager: FrictionlessManager;
|
|
30
|
+
clientRecord: ClientRecord;
|
|
31
|
+
userSitekeyIpHash: string;
|
|
32
|
+
dapp: string;
|
|
33
|
+
ipInfo: IPInfoResponse | undefined;
|
|
34
|
+
flatHeaders: Record<string, string>;
|
|
35
|
+
logger: Logger;
|
|
36
|
+
};
|
|
37
|
+
export declare const handleFrictionlessTrafficFilter: (input: FrictionlessTrafficFilterInput, res: Response) => Promise<FrictionlessTrafficFilterOutcome>;
|
|
38
|
+
//# sourceMappingURL=trafficFilterRequestTime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trafficFilterRequestTime.d.ts","sourceRoot":"","sources":["../../../src/api/captcha/trafficFilterRequestTime.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EACN,WAAW,EAEX,KAAK,cAAc,EACnB,KAAK,cAAc,EAEnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+CAA+C,CAAC;AACzF,OAAO,EACN,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,EAGvB,MAAM,wCAAwC,CAAC;AAEhD,MAAM,MAAM,yBAAyB,GAClC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,kBAAkB,CAAA;CAAE,GAC7C;IACA,IAAI,EAAE,WAAW,CAAC;IAGlB,WAAW,EAAE,WAAW,GAAG,SAAS,CAAC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,uBAAuB,CAAC,kBAAkB,CAAC,CAAC;CAC7D,CAAC;AAeL,eAAO,MAAM,+BAA+B,WACnC,cAAc,GAAG,SAAS,iBACnB,OAAO,CAAC,cAAc,CAAC,GAAG,SAAS,WACzC,MAAM,KACb,yBAwCF,CAAC;AAEF,MAAM,MAAM,gCAAgC,GACzC;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,GAClB;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEzC,MAAM,MAAM,8BAA8B,GAAG;IAC5C,OAAO,EAAE,yBAAyB,CAAC;IACnC,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,YAAY,EAAE,YAAY,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,cAAc,GAAG,SAAS,CAAC;IACnC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,MAAM,EAAE,MAAM,CAAC;CACf,CAAC;AAUF,eAAO,MAAM,+BAA+B,UACpC,8BAA8B,OAChC,QAAQ,KACX,OAAO,CAAC,gCAAgC,CAgE1C,CAAC"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { checkTrafficFilter, resolveChallengePolicy } from "../../tasks/spam/checkTrafficFilter.js";
|
|
2
|
+
import { CaptchaType, TrafficFilterAction } from "@prosopo/types";
|
|
3
|
+
//#region src/api/captcha/trafficFilterRequestTime.ts
|
|
4
|
+
/**
|
|
5
|
+
* Evaluate the site's `trafficFilter` against the current request's IP info
|
|
6
|
+
* at challenge-request time. Runs before captcha issuance so that a matched
|
|
7
|
+
* `block` policy short-circuits with 401 (no captcha issued, mirroring the
|
|
8
|
+
* `blockMiddleware` semantics) and a matched `challenge` policy hands back
|
|
9
|
+
* an override bundle for the caller to fold into its captcha-type +
|
|
10
|
+
* parameter selection.
|
|
11
|
+
*
|
|
12
|
+
* The verdict is authoritative for the request-time gate. Callers still run
|
|
13
|
+
* `resolveTrafficFilterCheck` at submit time to catch `block` policies that
|
|
14
|
+
* apply to the current (verify-time) IP even when the challenge-time IP
|
|
15
|
+
* passed.
|
|
16
|
+
*/
|
|
17
|
+
var applyTrafficFilterAtRequestTime = (ipInfo, trafficFilter, logger) => {
|
|
18
|
+
if (!trafficFilter) return { kind: "pass" };
|
|
19
|
+
const result = checkTrafficFilter(ipInfo, {
|
|
20
|
+
abuser: { action: TrafficFilterAction.Block },
|
|
21
|
+
...trafficFilter
|
|
22
|
+
});
|
|
23
|
+
if (result.isBlocked) {
|
|
24
|
+
logger?.info(() => ({
|
|
25
|
+
msg: "Traffic filter rejected challenge request",
|
|
26
|
+
data: { reason: result.reason }
|
|
27
|
+
}));
|
|
28
|
+
return {
|
|
29
|
+
kind: "block",
|
|
30
|
+
reason: result.reason
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const resolved = resolveChallengePolicy(result.matches);
|
|
34
|
+
if (!resolved) return { kind: "pass" };
|
|
35
|
+
logger?.info(() => ({
|
|
36
|
+
msg: "Traffic filter applied challenge overrides",
|
|
37
|
+
data: {
|
|
38
|
+
categories: resolved.sourceCategories,
|
|
39
|
+
captchaType: resolved.captchaType,
|
|
40
|
+
powDifficulty: resolved.powDifficulty,
|
|
41
|
+
solvedImagesCount: resolved.solvedImagesCount,
|
|
42
|
+
puzzleTolerance: resolved.puzzleTolerance
|
|
43
|
+
}
|
|
44
|
+
}));
|
|
45
|
+
return {
|
|
46
|
+
kind: "challenge",
|
|
47
|
+
captchaType: resolved.captchaType,
|
|
48
|
+
powDifficulty: resolved.powDifficulty,
|
|
49
|
+
solvedImagesCount: resolved.solvedImagesCount,
|
|
50
|
+
puzzleTolerance: resolved.puzzleTolerance,
|
|
51
|
+
sourceCategories: resolved.sourceCategories
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Frictionless-flow companion to `applyTrafficFilterAtRequestTime`. When the
|
|
56
|
+
* verdict is `block`, respond 401 and short-circuit. When the verdict is
|
|
57
|
+
* `challenge` and names a concrete captchaType, dispatch to the matching
|
|
58
|
+
* `send{Image,Pow,Puzzle}Captcha` helper with the resolved parameter
|
|
59
|
+
* overrides. Otherwise returns `{ handled: false }` so the caller falls
|
|
60
|
+
* through to the normal decision machine.
|
|
61
|
+
*/
|
|
62
|
+
var handleFrictionlessTrafficFilter = async (input, res) => {
|
|
63
|
+
const { verdict } = input;
|
|
64
|
+
if (verdict.kind === "pass") return { handled: false };
|
|
65
|
+
if (verdict.kind === "block") return {
|
|
66
|
+
handled: true,
|
|
67
|
+
response: res.status(401).json({ error: "Unauthorized" })
|
|
68
|
+
};
|
|
69
|
+
const baseParams = {
|
|
70
|
+
userSitekeyIpHash: input.userSitekeyIpHash,
|
|
71
|
+
siteKey: input.dapp,
|
|
72
|
+
ipInfo: input.ipInfo,
|
|
73
|
+
headers: input.flatHeaders
|
|
74
|
+
};
|
|
75
|
+
const logDispatch = (captchaType) => {
|
|
76
|
+
input.logger.info(() => ({
|
|
77
|
+
msg: "Frictionless decision",
|
|
78
|
+
data: {
|
|
79
|
+
decision: "traffic_filter",
|
|
80
|
+
captchaType,
|
|
81
|
+
categories: verdict.sourceCategories
|
|
82
|
+
}
|
|
83
|
+
}));
|
|
84
|
+
};
|
|
85
|
+
let response;
|
|
86
|
+
if (verdict.captchaType === CaptchaType.image) {
|
|
87
|
+
logDispatch(CaptchaType.image);
|
|
88
|
+
response = await input.frictionlessManager.sendImageCaptcha({
|
|
89
|
+
...baseParams,
|
|
90
|
+
solvedImagesCount: verdict.solvedImagesCount ? Math.min(verdict.solvedImagesCount, input.clientRecord.settings.imageMaxRounds) : input.clientRecord.settings.imageMaxRounds
|
|
91
|
+
});
|
|
92
|
+
} else if (verdict.captchaType === CaptchaType.pow) {
|
|
93
|
+
logDispatch(CaptchaType.pow);
|
|
94
|
+
response = await input.frictionlessManager.sendPowCaptcha({
|
|
95
|
+
...baseParams,
|
|
96
|
+
...verdict.powDifficulty !== void 0 && { powDifficulty: verdict.powDifficulty }
|
|
97
|
+
});
|
|
98
|
+
} else if (verdict.captchaType === CaptchaType.puzzle) {
|
|
99
|
+
logDispatch(CaptchaType.puzzle);
|
|
100
|
+
response = await input.frictionlessManager.sendPuzzleCaptcha(baseParams);
|
|
101
|
+
}
|
|
102
|
+
if (response) return {
|
|
103
|
+
handled: true,
|
|
104
|
+
response: res.json(response)
|
|
105
|
+
};
|
|
106
|
+
return { handled: false };
|
|
107
|
+
};
|
|
108
|
+
//#endregion
|
|
109
|
+
export { applyTrafficFilterAtRequestTime, handleFrictionlessTrafficFilter };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trafficFilterRequestTime.js","sourceRoot":"","sources":["../../../src/api/captcha/trafficFilterRequestTime.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,6 +10,7 @@ const require_hashUserIp = require("../../../utils/hashUserIp.cjs");
|
|
|
10
10
|
const require_normalizeRequestIp = require("../../../utils/normalizeRequestIp.cjs");
|
|
11
11
|
const require_testSiteKey = require("../../testSiteKey.cjs");
|
|
12
12
|
const require_maintenanceModeResponses = require("../maintenanceModeResponses.cjs");
|
|
13
|
+
const require_trafficFilterRequestTime = require("../trafficFilterRequestTime.cjs");
|
|
13
14
|
const require_honeypotResponse = require("./honeypotResponse.cjs");
|
|
14
15
|
const require_accessPolicy = require("./accessPolicy.cjs");
|
|
15
16
|
require("./constants.cjs");
|
|
@@ -313,6 +314,18 @@ var handler_default = (env, userAccessRulesStorage) => async (req, res, next) =>
|
|
|
313
314
|
if (accessPolicyOutcome.handled) return accessPolicyOutcome.response;
|
|
314
315
|
botScore = accessPolicyOutcome.botScore;
|
|
315
316
|
scoreComponents = accessPolicyOutcome.scoreComponents;
|
|
317
|
+
const trafficFilterVerdict = require_trafficFilterRequestTime.applyTrafficFilterAtRequestTime(req.ipInfo, clientRecord.settings?.trafficFilter, req.logger);
|
|
318
|
+
const trafficFilterOutcome = await require_trafficFilterRequestTime.handleFrictionlessTrafficFilter({
|
|
319
|
+
verdict: trafficFilterVerdict,
|
|
320
|
+
frictionlessManager: tasks.frictionlessManager,
|
|
321
|
+
clientRecord,
|
|
322
|
+
userSitekeyIpHash,
|
|
323
|
+
dapp,
|
|
324
|
+
ipInfo: req.ipInfo,
|
|
325
|
+
flatHeaders,
|
|
326
|
+
logger: req.logger
|
|
327
|
+
}, res);
|
|
328
|
+
if (trafficFilterOutcome.handled) return trafficFilterOutcome.response;
|
|
316
329
|
return await require_decisionMachine.runDecisionMachine({
|
|
317
330
|
tasks,
|
|
318
331
|
env,
|
|
@@ -5,6 +5,7 @@ const require_tasks = require("../../tasks/tasks.cjs");
|
|
|
5
5
|
const require_apiToggleMaintenanceModeEndpoint = require("../admin/apiToggleMaintenanceModeEndpoint.cjs");
|
|
6
6
|
const require_normalizeRequestIp = require("../../utils/normalizeRequestIp.cjs");
|
|
7
7
|
const require_maintenanceModeResponses = require("./maintenanceModeResponses.cjs");
|
|
8
|
+
const require_trafficFilterRequestTime = require("./trafficFilterRequestTime.cjs");
|
|
8
9
|
let _prosopo_common = require("@prosopo/common");
|
|
9
10
|
let _prosopo_types = require("@prosopo/types");
|
|
10
11
|
let _prosopo_util = require("@prosopo/util");
|
|
@@ -83,8 +84,19 @@ var getImageCaptchaChallenge_default = (env, userAccessRulesStorage) => async (r
|
|
|
83
84
|
i18n: req.i18n,
|
|
84
85
|
logger: req.logger
|
|
85
86
|
}));
|
|
87
|
+
const trafficVerdict = require_trafficFilterRequestTime.applyTrafficFilterAtRequestTime(req.ipInfo, clientRecord.settings?.trafficFilter, req.logger);
|
|
88
|
+
if (trafficVerdict.kind === "block") return next(new _prosopo_common.ProsopoApiError(trafficVerdict.reason, {
|
|
89
|
+
context: {
|
|
90
|
+
code: 401,
|
|
91
|
+
siteKey: dapp,
|
|
92
|
+
user
|
|
93
|
+
},
|
|
94
|
+
i18n: req.i18n,
|
|
95
|
+
logger: req.logger
|
|
96
|
+
}));
|
|
97
|
+
const trafficSolvedImagesCount = trafficVerdict.kind === "challenge" ? trafficVerdict.solvedImagesCount : void 0;
|
|
86
98
|
const captchaConfig = {
|
|
87
|
-
solved: { count: Math.min(solvedImagesCount || userAccessPolicy?.solvedImagesCount || env.config.captchas.solved.count, clientRecord.settings.imageMaxRounds ?? _prosopo_types.imageMaxRoundsDefault) },
|
|
99
|
+
solved: { count: Math.min(trafficSolvedImagesCount || solvedImagesCount || userAccessPolicy?.solvedImagesCount || env.config.captchas.solved.count, clientRecord.settings.imageMaxRounds ?? _prosopo_types.imageMaxRoundsDefault) },
|
|
88
100
|
unsolved: { count: userAccessPolicy?.unsolvedImagesCount || env.config.captchas.unsolved.count }
|
|
89
101
|
};
|
|
90
102
|
if (validSessionId && simdReadings) await tasks.frictionlessManager.decryptAndAttachSimdReadingsIfAbsent(validSessionId, simdReadings, _prosopo_types.SimdReadingsStage.challenge).catch((updateErr) => {
|
|
@@ -6,6 +6,7 @@ const require_tasks = require("../../tasks/tasks.cjs");
|
|
|
6
6
|
const require_apiToggleMaintenanceModeEndpoint = require("../admin/apiToggleMaintenanceModeEndpoint.cjs");
|
|
7
7
|
const require_normalizeRequestIp = require("../../utils/normalizeRequestIp.cjs");
|
|
8
8
|
const require_maintenanceModeResponses = require("./maintenanceModeResponses.cjs");
|
|
9
|
+
const require_trafficFilterRequestTime = require("./trafficFilterRequestTime.cjs");
|
|
9
10
|
let _prosopo_common = require("@prosopo/common");
|
|
10
11
|
let _prosopo_types = require("@prosopo/types");
|
|
11
12
|
let _prosopo_util = require("@prosopo/util");
|
|
@@ -77,7 +78,17 @@ var getPoWCaptchaChallenge_default = (env, userAccessRulesStorage) => async (req
|
|
|
77
78
|
i18n: req.i18n,
|
|
78
79
|
logger: req.logger
|
|
79
80
|
}));
|
|
80
|
-
const
|
|
81
|
+
const trafficVerdict = require_trafficFilterRequestTime.applyTrafficFilterAtRequestTime(req.ipInfo, clientSettings.settings?.trafficFilter, req.logger);
|
|
82
|
+
if (trafficVerdict.kind === "block") return next(new _prosopo_common.ProsopoApiError(trafficVerdict.reason, {
|
|
83
|
+
context: {
|
|
84
|
+
code: 401,
|
|
85
|
+
siteKey: dapp,
|
|
86
|
+
user
|
|
87
|
+
},
|
|
88
|
+
i18n: req.i18n,
|
|
89
|
+
logger: req.logger
|
|
90
|
+
}));
|
|
91
|
+
const difficulty = (trafficVerdict.kind === "challenge" ? trafficVerdict.powDifficulty : void 0) || powDifficulty || userAccessPolicy?.powDifficulty || clientSettings?.settings?.powDifficulty;
|
|
81
92
|
const challenge = await tasks.powCaptchaManager.getPowCaptchaChallenge(user, dapp, origin, difficulty);
|
|
82
93
|
if (validSessionId && simdReadings) await tasks.frictionlessManager.decryptAndAttachSimdReadingsIfAbsent(validSessionId, simdReadings, _prosopo_types.SimdReadingsStage.challenge).catch((updateErr) => {
|
|
83
94
|
req.logger.warn(() => ({
|
|
@@ -6,6 +6,7 @@ const require_tasks = require("../../tasks/tasks.cjs");
|
|
|
6
6
|
const require_apiToggleMaintenanceModeEndpoint = require("../admin/apiToggleMaintenanceModeEndpoint.cjs");
|
|
7
7
|
const require_normalizeRequestIp = require("../../utils/normalizeRequestIp.cjs");
|
|
8
8
|
const require_maintenanceModeResponses = require("./maintenanceModeResponses.cjs");
|
|
9
|
+
const require_trafficFilterRequestTime = require("./trafficFilterRequestTime.cjs");
|
|
9
10
|
let _prosopo_common = require("@prosopo/common");
|
|
10
11
|
let _prosopo_types = require("@prosopo/types");
|
|
11
12
|
let _prosopo_util = require("@prosopo/util");
|
|
@@ -77,7 +78,17 @@ var getPuzzleCaptchaChallenge_default = (env, userAccessRulesStorage) => async (
|
|
|
77
78
|
i18n: req.i18n,
|
|
78
79
|
logger: req.logger
|
|
79
80
|
}));
|
|
80
|
-
const
|
|
81
|
+
const trafficVerdict = require_trafficFilterRequestTime.applyTrafficFilterAtRequestTime(req.ipInfo, clientSettings.settings?.trafficFilter, req.logger);
|
|
82
|
+
if (trafficVerdict.kind === "block") return next(new _prosopo_common.ProsopoApiError(trafficVerdict.reason, {
|
|
83
|
+
context: {
|
|
84
|
+
code: 401,
|
|
85
|
+
siteKey: dapp,
|
|
86
|
+
user
|
|
87
|
+
},
|
|
88
|
+
i18n: req.i18n,
|
|
89
|
+
logger: req.logger
|
|
90
|
+
}));
|
|
91
|
+
const tolerance = (trafficVerdict.kind === "challenge" ? trafficVerdict.puzzleTolerance : void 0) ?? clientSettings?.settings?.puzzleTolerance;
|
|
81
92
|
const challenge = await tasks.puzzleCaptchaManager.getPuzzleCaptchaChallenge(user, dapp, origin, tolerance);
|
|
82
93
|
if (validSessionId && simdReadings) await tasks.frictionlessManager.decryptAndAttachSimdReadingsIfAbsent(validSessionId, simdReadings, _prosopo_types.SimdReadingsStage.challenge).catch((updateErr) => {
|
|
83
94
|
req.logger.warn(() => ({
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
const require_checkTrafficFilter = require("../../tasks/spam/checkTrafficFilter.cjs");
|
|
2
|
+
let _prosopo_types = require("@prosopo/types");
|
|
3
|
+
//#region src/api/captcha/trafficFilterRequestTime.ts
|
|
4
|
+
/**
|
|
5
|
+
* Evaluate the site's `trafficFilter` against the current request's IP info
|
|
6
|
+
* at challenge-request time. Runs before captcha issuance so that a matched
|
|
7
|
+
* `block` policy short-circuits with 401 (no captcha issued, mirroring the
|
|
8
|
+
* `blockMiddleware` semantics) and a matched `challenge` policy hands back
|
|
9
|
+
* an override bundle for the caller to fold into its captcha-type +
|
|
10
|
+
* parameter selection.
|
|
11
|
+
*
|
|
12
|
+
* The verdict is authoritative for the request-time gate. Callers still run
|
|
13
|
+
* `resolveTrafficFilterCheck` at submit time to catch `block` policies that
|
|
14
|
+
* apply to the current (verify-time) IP even when the challenge-time IP
|
|
15
|
+
* passed.
|
|
16
|
+
*/
|
|
17
|
+
var applyTrafficFilterAtRequestTime = (ipInfo, trafficFilter, logger) => {
|
|
18
|
+
if (!trafficFilter) return { kind: "pass" };
|
|
19
|
+
const effective = {
|
|
20
|
+
abuser: { action: _prosopo_types.TrafficFilterAction.Block },
|
|
21
|
+
...trafficFilter
|
|
22
|
+
};
|
|
23
|
+
const result = require_checkTrafficFilter.checkTrafficFilter(ipInfo, effective);
|
|
24
|
+
if (result.isBlocked) {
|
|
25
|
+
logger?.info(() => ({
|
|
26
|
+
msg: "Traffic filter rejected challenge request",
|
|
27
|
+
data: { reason: result.reason }
|
|
28
|
+
}));
|
|
29
|
+
return {
|
|
30
|
+
kind: "block",
|
|
31
|
+
reason: result.reason
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const resolved = require_checkTrafficFilter.resolveChallengePolicy(result.matches);
|
|
35
|
+
if (!resolved) return { kind: "pass" };
|
|
36
|
+
logger?.info(() => ({
|
|
37
|
+
msg: "Traffic filter applied challenge overrides",
|
|
38
|
+
data: {
|
|
39
|
+
categories: resolved.sourceCategories,
|
|
40
|
+
captchaType: resolved.captchaType,
|
|
41
|
+
powDifficulty: resolved.powDifficulty,
|
|
42
|
+
solvedImagesCount: resolved.solvedImagesCount,
|
|
43
|
+
puzzleTolerance: resolved.puzzleTolerance
|
|
44
|
+
}
|
|
45
|
+
}));
|
|
46
|
+
return {
|
|
47
|
+
kind: "challenge",
|
|
48
|
+
captchaType: resolved.captchaType,
|
|
49
|
+
powDifficulty: resolved.powDifficulty,
|
|
50
|
+
solvedImagesCount: resolved.solvedImagesCount,
|
|
51
|
+
puzzleTolerance: resolved.puzzleTolerance,
|
|
52
|
+
sourceCategories: resolved.sourceCategories
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Frictionless-flow companion to `applyTrafficFilterAtRequestTime`. When the
|
|
57
|
+
* verdict is `block`, respond 401 and short-circuit. When the verdict is
|
|
58
|
+
* `challenge` and names a concrete captchaType, dispatch to the matching
|
|
59
|
+
* `send{Image,Pow,Puzzle}Captcha` helper with the resolved parameter
|
|
60
|
+
* overrides. Otherwise returns `{ handled: false }` so the caller falls
|
|
61
|
+
* through to the normal decision machine.
|
|
62
|
+
*/
|
|
63
|
+
var handleFrictionlessTrafficFilter = async (input, res) => {
|
|
64
|
+
const { verdict } = input;
|
|
65
|
+
if (verdict.kind === "pass") return { handled: false };
|
|
66
|
+
if (verdict.kind === "block") return {
|
|
67
|
+
handled: true,
|
|
68
|
+
response: res.status(401).json({ error: "Unauthorized" })
|
|
69
|
+
};
|
|
70
|
+
const baseParams = {
|
|
71
|
+
userSitekeyIpHash: input.userSitekeyIpHash,
|
|
72
|
+
siteKey: input.dapp,
|
|
73
|
+
ipInfo: input.ipInfo,
|
|
74
|
+
headers: input.flatHeaders
|
|
75
|
+
};
|
|
76
|
+
const logDispatch = (captchaType) => {
|
|
77
|
+
input.logger.info(() => ({
|
|
78
|
+
msg: "Frictionless decision",
|
|
79
|
+
data: {
|
|
80
|
+
decision: "traffic_filter",
|
|
81
|
+
captchaType,
|
|
82
|
+
categories: verdict.sourceCategories
|
|
83
|
+
}
|
|
84
|
+
}));
|
|
85
|
+
};
|
|
86
|
+
let response;
|
|
87
|
+
if (verdict.captchaType === _prosopo_types.CaptchaType.image) {
|
|
88
|
+
logDispatch(_prosopo_types.CaptchaType.image);
|
|
89
|
+
response = await input.frictionlessManager.sendImageCaptcha({
|
|
90
|
+
...baseParams,
|
|
91
|
+
solvedImagesCount: verdict.solvedImagesCount ? Math.min(verdict.solvedImagesCount, input.clientRecord.settings.imageMaxRounds) : input.clientRecord.settings.imageMaxRounds
|
|
92
|
+
});
|
|
93
|
+
} else if (verdict.captchaType === _prosopo_types.CaptchaType.pow) {
|
|
94
|
+
logDispatch(_prosopo_types.CaptchaType.pow);
|
|
95
|
+
response = await input.frictionlessManager.sendPowCaptcha({
|
|
96
|
+
...baseParams,
|
|
97
|
+
...verdict.powDifficulty !== void 0 && { powDifficulty: verdict.powDifficulty }
|
|
98
|
+
});
|
|
99
|
+
} else if (verdict.captchaType === _prosopo_types.CaptchaType.puzzle) {
|
|
100
|
+
logDispatch(_prosopo_types.CaptchaType.puzzle);
|
|
101
|
+
response = await input.frictionlessManager.sendPuzzleCaptcha(baseParams);
|
|
102
|
+
}
|
|
103
|
+
if (response) return {
|
|
104
|
+
handled: true,
|
|
105
|
+
response: res.json(response)
|
|
106
|
+
};
|
|
107
|
+
return { handled: false };
|
|
108
|
+
};
|
|
109
|
+
//#endregion
|
|
110
|
+
exports.applyTrafficFilterAtRequestTime = applyTrafficFilterAtRequestTime;
|
|
111
|
+
exports.handleFrictionlessTrafficFilter = handleFrictionlessTrafficFilter;
|
|
@@ -438,7 +438,10 @@ var CaptchaManager = class CaptchaManager {
|
|
|
438
438
|
return require_checkSpamEmail.checkSpamEmail(email, this.db, this.config, this.logger);
|
|
439
439
|
}
|
|
440
440
|
/**
|
|
441
|
-
* Resolves the IP info to feed to `checkTrafficFilter` and runs the check
|
|
441
|
+
* Resolves the IP info to feed to `checkTrafficFilter` and runs the check
|
|
442
|
+
* at submit time. Only `action: "block"` matches produce `isBlocked:true`;
|
|
443
|
+
* `action: "challenge"` matches were already applied at request time and
|
|
444
|
+
* are ignored here.
|
|
442
445
|
*
|
|
443
446
|
* - The captcha record already carries the IPInfoResponse from request
|
|
444
447
|
* time (ipInfoMiddleware → storeXxxRecord), so by default we reuse it
|
|
@@ -448,9 +451,10 @@ var CaptchaManager = class CaptchaManager {
|
|
|
448
451
|
* and may differ from the IP that originally requested the captcha.
|
|
449
452
|
* - When the session carries a `dnsEvent`, its `peerIp` and `resolverIp`
|
|
450
453
|
* are enriched and passed alongside the primary IP.
|
|
451
|
-
* -
|
|
452
|
-
* blocked even when the site hasn't configured a
|
|
453
|
-
*
|
|
454
|
+
* - The abuser category defaults to `{action:"block"}` so abusive
|
|
455
|
+
* networks are always blocked even when the site hasn't configured a
|
|
456
|
+
* trafficFilter.
|
|
457
|
+
* - Returns `{ isBlocked: false }` if no category is active, without
|
|
454
458
|
* consulting the payload at all.
|
|
455
459
|
*
|
|
456
460
|
* Callers handle the "blocked" branch themselves (each verify path
|
|
@@ -459,10 +463,13 @@ var CaptchaManager = class CaptchaManager {
|
|
|
459
463
|
*/
|
|
460
464
|
async resolveTrafficFilterCheck(env, recordIpInfo, trafficFilter, currentIp, enrichedDnsEvent) {
|
|
461
465
|
const effective = {
|
|
462
|
-
|
|
466
|
+
abuser: { action: _prosopo_types.TrafficFilterAction.Block },
|
|
463
467
|
...trafficFilter
|
|
464
468
|
};
|
|
465
|
-
if (!
|
|
469
|
+
if (!(effective.vpn !== void 0 || effective.proxy !== void 0 || effective.tor !== void 0 || effective.abuser !== void 0 || effective.datacenter !== void 0 || effective.mobile !== void 0 || effective.satellite !== void 0 || effective.crawler !== void 0)) return {
|
|
470
|
+
isBlocked: false,
|
|
471
|
+
matches: []
|
|
472
|
+
};
|
|
466
473
|
const ipInfo = currentIp ? await env.ipInfoService.lookup(currentIp) : recordIpInfo;
|
|
467
474
|
return require_checkTrafficFilter.checkTrafficFilter(ipInfo, effective, require_enrichDnsEvent.extraIpInfosFromEnrichedDnsEvent(enrichedDnsEvent), enrichedDnsEvent?.pathValid);
|
|
468
475
|
}
|
|
@@ -46,15 +46,17 @@ var extraIpInfosFromEnrichedDnsEvent = (enriched) => {
|
|
|
46
46
|
* - client IP is a consumer ISP but resolver is datacenter (compound)
|
|
47
47
|
*
|
|
48
48
|
* When `trafficFilter` is supplied, the datacenter and abuser contributions
|
|
49
|
-
* are gated on the same rules `checkTrafficFilter` uses for the client IP
|
|
49
|
+
* are gated on the same rules `checkTrafficFilter` uses for the client IP.
|
|
50
|
+
* A category counts here whenever the operator has configured any policy
|
|
51
|
+
* for it (block or challenge) — either intent signals suspicion.
|
|
50
52
|
*
|
|
51
|
-
* -
|
|
53
|
+
* - datacenter category must be configured; IPs whose
|
|
52
54
|
* `providerType === "isp"` short-circuit; named allowlist skips
|
|
53
|
-
* -
|
|
55
|
+
* - abuser category defaults to configured, with the score threshold
|
|
54
56
|
* - cross-category suppression: VPN / proxy / Tor / crawler IPs that also
|
|
55
57
|
* carry `isDatacenter=true` are NOT counted as datacenter when the
|
|
56
|
-
* operator hasn't
|
|
57
|
-
*
|
|
58
|
+
* operator hasn't configured that more specific category — mirrors
|
|
59
|
+
* the `datacenterSuppressedByCategory` rule in evaluateIpInfo.
|
|
58
60
|
*
|
|
59
61
|
* `pathValid` is a protocol signal, not a category — it always contributes
|
|
60
62
|
* regardless of trafficFilter. When `trafficFilter` is omitted, all
|
|
@@ -68,16 +70,16 @@ var computeDnsAsymmetry = (enriched, clientIpInfo, trafficFilter) => {
|
|
|
68
70
|
const countDc = (ip) => {
|
|
69
71
|
if (!ip?.isValid || !ip.isDatacenter) return false;
|
|
70
72
|
if (!trafficFilter) return true;
|
|
71
|
-
if (trafficFilter.
|
|
73
|
+
if (trafficFilter.datacenter === void 0) return false;
|
|
72
74
|
if (require_checkTrafficFilter.isDatacenterDenylisted(ip, trafficFilter.datacenterNameDenylist)) return true;
|
|
73
|
-
if (ip.isVPN && trafficFilter.
|
|
75
|
+
if (ip.isVPN && trafficFilter.vpn === void 0 || ip.isProxy && trafficFilter.proxy === void 0 || ip.isTor && trafficFilter.tor === void 0 || ip.isCrawler && trafficFilter.crawler === void 0) return false;
|
|
74
76
|
if (ip.providerType === "isp") return false;
|
|
75
77
|
return !require_checkTrafficFilter.isDatacenterAllowlisted(ip, trafficFilter.datacenterNameAllowlist);
|
|
76
78
|
};
|
|
77
79
|
const countAbuser = (ip) => {
|
|
78
80
|
if (!ip?.isValid || !ip.isAbuser) return false;
|
|
79
81
|
if (!trafficFilter) return true;
|
|
80
|
-
if (trafficFilter.
|
|
82
|
+
if (trafficFilter.abuser === void 0) return false;
|
|
81
83
|
const threshold = trafficFilter.abuserScoreThreshold ?? _prosopo_types.trafficFilterAbuserScoreThresholdDefault;
|
|
82
84
|
return Math.max(ip.abuserScore ?? 0, ip.companyAbuserScore ?? 0) >= threshold;
|
|
83
85
|
};
|
|
@@ -127,6 +127,7 @@ var PuzzleCaptchaManager = class extends require_captchaManager.CaptchaManager {
|
|
|
127
127
|
const dappAccount = (0, _prosopo_util.at)(challengeSplit, 2);
|
|
128
128
|
this.usageCounters.incrManyAsync(dappAccount, require_usageCounters.buildAllWindowIncrements("solved", _prosopo_types.CaptchaType.puzzle, ipAddress.address, userAccount));
|
|
129
129
|
}
|
|
130
|
+
await this.db.updatePuzzleCaptchaRecord(challenge, { puzzleEvents });
|
|
130
131
|
if (behavioralData) try {
|
|
131
132
|
const bundle = await this.resolveBundleBySessionId(challengeRecord.sessionId);
|
|
132
133
|
const decryptedData = await this.decryptBehavioralData(behavioralData, bundle);
|
|
@@ -153,8 +154,7 @@ var PuzzleCaptchaManager = class extends require_captchaManager.CaptchaManager {
|
|
|
153
154
|
};
|
|
154
155
|
await this.db.updatePuzzleCaptchaRecord(challenge, {
|
|
155
156
|
behavioralDataPacked: packedData,
|
|
156
|
-
deviceCapability: decryptedData.deviceCapability
|
|
157
|
-
puzzleEvents
|
|
157
|
+
deviceCapability: decryptedData.deviceCapability
|
|
158
158
|
});
|
|
159
159
|
}
|
|
160
160
|
} catch (error) {
|
|
@@ -163,7 +163,6 @@ var PuzzleCaptchaManager = class extends require_captchaManager.CaptchaManager {
|
|
|
163
163
|
err: error
|
|
164
164
|
}));
|
|
165
165
|
}
|
|
166
|
-
else await this.db.updatePuzzleCaptchaRecord(challenge, { puzzleEvents });
|
|
167
166
|
if (clientMetaData?.hp) await this.db.updatePuzzleCaptchaRecord(challenge, { clientMetaData: { hp: clientMetaData.hp } });
|
|
168
167
|
await this.db.updatePuzzleCaptchaRecordResult(challenge, result, false, true, userTimestampSignature, coords);
|
|
169
168
|
if (challengeRecord.sessionId) {
|