@prosopo/provider 4.14.3 → 4.15.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 +11 -10
- package/.turbo/turbo-build$colon$tsc.log +24 -24
- package/.turbo/turbo-build.log +12 -11
- package/CHANGELOG.md +87 -0
- package/dist/api/admin/apiRemoveDetectorKeyEndpoint.d.ts.map +1 -1
- package/dist/api/blacklistRequestInspector.d.ts +8 -3
- package/dist/api/blacklistRequestInspector.d.ts.map +1 -1
- package/dist/api/blacklistRequestInspector.js +49 -11
- 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 +19 -13
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js.map +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.d.ts +2 -0
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.d.ts.map +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.js +7 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.js.map +1 -1
- package/dist/api/captcha/submitPoWCaptchaSolution.d.ts +4 -1
- package/dist/api/captcha/submitPoWCaptchaSolution.d.ts.map +1 -1
- package/dist/api/captcha/submitPoWCaptchaSolution.js +12 -7
- package/dist/api/captcha/submitPoWCaptchaSolution.js.map +1 -1
- package/dist/api/handshakeTimingMiddleware.d.ts +2 -2
- package/dist/api/handshakeTimingMiddleware.js +11 -11
- package/dist/api/hardBlockVerdictCache.d.ts +18 -0
- package/dist/api/hardBlockVerdictCache.d.ts.map +1 -0
- package/dist/api/hardBlockVerdictCache.js +119 -0
- package/dist/api/hardBlockVerdictCache.js.map +1 -0
- package/dist/api/startProviderApi.d.ts.map +1 -1
- package/dist/api/startProviderApi.js +17 -1
- package/dist/api/startProviderApi.js.map +1 -1
- package/dist/cjs/api/blacklistRequestInspector.cjs +49 -11
- package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/handler.cjs +19 -13
- package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.cjs +7 -1
- package/dist/cjs/api/captcha/submitPoWCaptchaSolution.cjs +12 -7
- package/dist/cjs/api/handshakeTimingMiddleware.cjs +11 -11
- package/dist/cjs/api/hardBlockVerdictCache.cjs +119 -0
- package/dist/cjs/api/startProviderApi.cjs +17 -1
- package/dist/cjs/index.cjs +1 -0
- package/dist/cjs/tasks/frictionless/frictionlessTasks.cjs +9 -9
- package/dist/cjs/tasks/spam/checkTrafficFilter.cjs +6 -9
- package/dist/index.js +2 -1
- package/dist/tasks/captchaManager.d.ts +1 -0
- package/dist/tasks/captchaManager.d.ts.map +1 -1
- package/dist/tasks/captchaManager.js.map +1 -1
- package/dist/tasks/frictionless/frictionlessTasks.d.ts +1 -1
- package/dist/tasks/frictionless/frictionlessTasks.js +9 -9
- package/dist/tasks/spam/checkTrafficFilter.d.ts.map +1 -1
- package/dist/tasks/spam/checkTrafficFilter.js +6 -9
- package/dist/tasks/spam/checkTrafficFilter.js.map +1 -1
- package/dist/tests/integration/api/blacklistRequestInspector.integration.test.js +2 -1
- package/dist/tests/integration/api/blacklistRequestInspector.integration.test.js.map +1 -1
- package/dist/tests/integration/api/blacklistRequestInspector.storm.integration.test.d.ts +2 -0
- package/dist/tests/integration/api/blacklistRequestInspector.storm.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/api/blacklistRequestInspector.storm.integration.test.js +295 -0
- package/dist/tests/integration/api/blacklistRequestInspector.storm.integration.test.js.map +1 -0
- package/dist/tests/unit/api/blacklistRequestInspector.unit.test.js +8 -2
- package/dist/tests/unit/api/blacklistRequestInspector.unit.test.js.map +1 -1
- package/dist/tests/unit/api/handshakeTimingMiddleware.unit.test.js +22 -22
- package/dist/tests/unit/api/hardBlockVerdictCache.unit.test.d.ts +2 -0
- package/dist/tests/unit/api/hardBlockVerdictCache.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/api/hardBlockVerdictCache.unit.test.js +192 -0
- package/dist/tests/unit/api/hardBlockVerdictCache.unit.test.js.map +1 -0
- package/dist/tests/unit/tasks/powCaptcha/powTasks.unit.test.js +2 -0
- package/dist/tests/unit/tasks/powCaptcha/powTasks.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/spam/checkTrafficFilter.unit.test.js +73 -1
- package/dist/tests/unit/tasks/spam/checkTrafficFilter.unit.test.js.map +1 -1
- package/package.json +13 -13
|
@@ -4,6 +4,7 @@ const node_crypto = require("node:crypto");
|
|
|
4
4
|
const types = require("@prosopo/types");
|
|
5
5
|
const userAccessPolicy = require("@prosopo/user-access-policy");
|
|
6
6
|
const compositeIpAddress = require("../compositeIpAddress.cjs");
|
|
7
|
+
const hardBlockVerdictCache = require("./hardBlockVerdictCache.cjs");
|
|
7
8
|
const metrics = require("./metrics.cjs");
|
|
8
9
|
const getRequestUserScope = (requestHeaders, ja4, ip, user, headHash, coords, countryCode, asn) => {
|
|
9
10
|
const userAgent = requestHeaders["user-agent"] ? requestHeaders["user-agent"].toString() : void 0;
|
|
@@ -130,8 +131,30 @@ const rankCandidateRules = (rules, request, requestClientId) => rules.filter((ru
|
|
|
130
131
|
}
|
|
131
132
|
return ruleHarshness(b) - ruleHarshness(a);
|
|
132
133
|
});
|
|
134
|
+
const verdictCache = new hardBlockVerdictCache.HardBlockVerdictCache();
|
|
135
|
+
const getVerdictCache = () => verdictCache;
|
|
136
|
+
const REQUEST_MEMO_SYMBOL = Symbol.for("prosopo.accessRuleRequestMemo");
|
|
137
|
+
const getOrCreateRequestMemo = (requestMemoHost) => {
|
|
138
|
+
let memo = requestMemoHost[REQUEST_MEMO_SYMBOL];
|
|
139
|
+
if (memo === void 0) {
|
|
140
|
+
memo = /* @__PURE__ */ new Map();
|
|
141
|
+
requestMemoHost[REQUEST_MEMO_SYMBOL] = memo;
|
|
142
|
+
}
|
|
143
|
+
return memo;
|
|
144
|
+
};
|
|
133
145
|
const getPrioritisedAccessRule = async (userAccessRulesStorage, userScope, clientId, options) => {
|
|
134
146
|
const parsedUserScope = userAccessPolicy.userScopeInput.parse(userScope);
|
|
147
|
+
const blockOnly = options?.blockOnly ?? false;
|
|
148
|
+
const skipCache = options?.skipCache ?? false;
|
|
149
|
+
const requestMemoHost = options?.requestMemoHost;
|
|
150
|
+
const cacheKey = hardBlockVerdictCache.hardBlockCacheKey(clientId, parsedUserScope, blockOnly);
|
|
151
|
+
const requestMemo = requestMemoHost ? getOrCreateRequestMemo(requestMemoHost) : void 0;
|
|
152
|
+
if (requestMemo !== void 0) {
|
|
153
|
+
const memoHit = requestMemo.get(cacheKey);
|
|
154
|
+
if (memoHit !== void 0) {
|
|
155
|
+
return memoHit;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
135
158
|
const filter = {
|
|
136
159
|
...clientId && {
|
|
137
160
|
policyScope: {
|
|
@@ -141,15 +164,25 @@ const getPrioritisedAccessRule = async (userAccessRulesStorage, userScope, clien
|
|
|
141
164
|
policyScopeMatch: userAccessPolicy.FilterScopeMatch.Greedy,
|
|
142
165
|
userScope: parsedUserScope,
|
|
143
166
|
userScopeMatch: userAccessPolicy.FilterScopeMatch.Greedy,
|
|
144
|
-
...
|
|
167
|
+
...blockOnly && { blockOnly: true }
|
|
145
168
|
};
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
169
|
+
const compute = async () => {
|
|
170
|
+
const candidates = await userAccessRulesStorage.findRules(
|
|
171
|
+
filter,
|
|
172
|
+
true,
|
|
173
|
+
// matchingFieldsOnly — engages the split-query hot path
|
|
174
|
+
true
|
|
175
|
+
);
|
|
176
|
+
return rankCandidateRules(candidates, parsedUserScope, clientId);
|
|
177
|
+
};
|
|
178
|
+
let ranked;
|
|
179
|
+
if (skipCache) {
|
|
180
|
+
ranked = await compute();
|
|
181
|
+
} else {
|
|
182
|
+
ranked = await verdictCache.getOrCompute(cacheKey, compute);
|
|
183
|
+
}
|
|
184
|
+
requestMemo?.set(cacheKey, ranked);
|
|
185
|
+
return ranked;
|
|
153
186
|
};
|
|
154
187
|
class BlacklistRequestInspector {
|
|
155
188
|
constructor(userAccessRulesStorage, environmentReadinessWaiter, db) {
|
|
@@ -169,7 +202,11 @@ class BlacklistRequestInspector {
|
|
|
169
202
|
request.headers,
|
|
170
203
|
request.body,
|
|
171
204
|
request.logger,
|
|
172
|
-
request.ipInfo
|
|
205
|
+
request.ipInfo,
|
|
206
|
+
// Share the per-request memo so a downstream captcha task
|
|
207
|
+
// hitting checkForHardBlock in the same request reuses this
|
|
208
|
+
// lookup rather than re-querying Redis.
|
|
209
|
+
request
|
|
173
210
|
);
|
|
174
211
|
if (shouldAbortRequest) {
|
|
175
212
|
res.status(403).json({ error: "Forbidden" });
|
|
@@ -177,7 +214,7 @@ class BlacklistRequestInspector {
|
|
|
177
214
|
}
|
|
178
215
|
next();
|
|
179
216
|
}
|
|
180
|
-
async shouldAbortRequest(requestedRoute, rawIp, ja4, requestHeaders, requestBody, logger, ipInfo) {
|
|
217
|
+
async shouldAbortRequest(requestedRoute, rawIp, ja4, requestHeaders, requestBody, logger, ipInfo, requestMemoHost) {
|
|
181
218
|
if (this.isApiUnrelatedRoute(requestedRoute)) {
|
|
182
219
|
return false;
|
|
183
220
|
}
|
|
@@ -222,7 +259,7 @@ class BlacklistRequestInspector {
|
|
|
222
259
|
// candidate pool so the SERVER_SIDE_RANK_TOP_N cap can't
|
|
223
260
|
// crowd out hard-block rules in clients with dense Restrict
|
|
224
261
|
// rule populations.
|
|
225
|
-
{ blockOnly: true }
|
|
262
|
+
{ blockOnly: true, requestMemoHost }
|
|
226
263
|
);
|
|
227
264
|
const enforceable = (accessPolicies ?? []).filter(
|
|
228
265
|
(p) => !p.deferToVerify
|
|
@@ -352,4 +389,5 @@ class BlacklistRequestInspector {
|
|
|
352
389
|
exports.BlacklistRequestInspector = BlacklistRequestInspector;
|
|
353
390
|
exports.getPrioritisedAccessRule = getPrioritisedAccessRule;
|
|
354
391
|
exports.getRequestUserScope = getRequestUserScope;
|
|
392
|
+
exports.getVerdictCache = getVerdictCache;
|
|
355
393
|
exports.rankCandidateRules = rankCandidateRules;
|
|
@@ -168,11 +168,11 @@ const getFrictionlessCaptchaChallenge = (env, userAccessRulesStorage) => async (
|
|
|
168
168
|
// Timing values are per-connection so they come from
|
|
169
169
|
// the current request even in the dedup replay path —
|
|
170
170
|
// dedup.session was created on a different TCP conn.
|
|
171
|
-
...req.
|
|
172
|
-
|
|
171
|
+
...req.tcpToChelloUs !== void 0 && {
|
|
172
|
+
tcpToChelloUs: req.tcpToChelloUs
|
|
173
173
|
},
|
|
174
|
-
...req.
|
|
175
|
-
|
|
174
|
+
...req.chelloToHandshakeUs !== void 0 && {
|
|
175
|
+
chelloToHandshakeUs: req.chelloToHandshakeUs
|
|
176
176
|
},
|
|
177
177
|
// currentUrl uses the cached session's value to
|
|
178
178
|
// match the rest of the dedup routing input (score,
|
|
@@ -250,7 +250,13 @@ const getFrictionlessCaptchaChallenge = (env, userAccessRulesStorage) => async (
|
|
|
250
250
|
flatHeaders,
|
|
251
251
|
sessionMode,
|
|
252
252
|
userSitekeyIpHash,
|
|
253
|
-
logger: req.logger
|
|
253
|
+
logger: req.logger,
|
|
254
|
+
...req.tcpToChelloUs !== void 0 && {
|
|
255
|
+
tcpToChelloUs: req.tcpToChelloUs
|
|
256
|
+
},
|
|
257
|
+
...req.chelloToHandshakeUs !== void 0 && {
|
|
258
|
+
chelloToHandshakeUs: req.chelloToHandshakeUs
|
|
259
|
+
}
|
|
254
260
|
},
|
|
255
261
|
res
|
|
256
262
|
);
|
|
@@ -363,11 +369,11 @@ const getFrictionlessCaptchaChallenge = (env, userAccessRulesStorage) => async (
|
|
|
363
369
|
...entropyMathRandomFirst !== void 0 && {
|
|
364
370
|
entropyMathRandomFirst
|
|
365
371
|
},
|
|
366
|
-
...req.
|
|
367
|
-
|
|
372
|
+
...req.tcpToChelloUs !== void 0 && {
|
|
373
|
+
tcpToChelloUs: req.tcpToChelloUs
|
|
368
374
|
},
|
|
369
|
-
...req.
|
|
370
|
-
|
|
375
|
+
...req.chelloToHandshakeUs !== void 0 && {
|
|
376
|
+
chelloToHandshakeUs: req.chelloToHandshakeUs
|
|
371
377
|
}
|
|
372
378
|
});
|
|
373
379
|
const ipInfoMobile = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.isMobile : void 0;
|
|
@@ -385,11 +391,11 @@ const getFrictionlessCaptchaChallenge = (env, userAccessRulesStorage) => async (
|
|
|
385
391
|
headers: flatHeaders,
|
|
386
392
|
userAgent: safeUserAgent,
|
|
387
393
|
...req.ja4 && { ja4: req.ja4 },
|
|
388
|
-
...req.
|
|
389
|
-
|
|
394
|
+
...req.tcpToChelloUs !== void 0 && {
|
|
395
|
+
tcpToChelloUs: req.tcpToChelloUs
|
|
390
396
|
},
|
|
391
|
-
...req.
|
|
392
|
-
|
|
397
|
+
...req.chelloToHandshakeUs !== void 0 && {
|
|
398
|
+
chelloToHandshakeUs: req.chelloToHandshakeUs
|
|
393
399
|
},
|
|
394
400
|
...currentUrl && { currentUrl }
|
|
395
401
|
}
|
|
@@ -21,7 +21,13 @@ const runConfiguredCaptchaTypeShortCircuit = async (input, res) => {
|
|
|
21
21
|
ipInfo: input.ipInfo,
|
|
22
22
|
headers: input.flatHeaders,
|
|
23
23
|
mode: input.sessionMode,
|
|
24
|
-
userSitekeyIpHash: input.userSitekeyIpHash
|
|
24
|
+
userSitekeyIpHash: input.userSitekeyIpHash,
|
|
25
|
+
...input.tcpToChelloUs !== void 0 && {
|
|
26
|
+
tcpToChelloUs: input.tcpToChelloUs
|
|
27
|
+
},
|
|
28
|
+
...input.chelloToHandshakeUs !== void 0 && {
|
|
29
|
+
chelloToHandshakeUs: input.chelloToHandshakeUs
|
|
30
|
+
}
|
|
25
31
|
};
|
|
26
32
|
input.logger.info(() => ({
|
|
27
33
|
msg: "Frictionless decision",
|
|
@@ -87,11 +87,11 @@ const submitPoWCaptchaSolution = (env) => async (req, res, next) => {
|
|
|
87
87
|
userAgent,
|
|
88
88
|
...req.ja4 && { ja4: req.ja4 },
|
|
89
89
|
...fingerprintProof && { fingerprintProof },
|
|
90
|
-
...req.
|
|
91
|
-
|
|
90
|
+
...req.tcpToChelloUs !== void 0 && {
|
|
91
|
+
tcpToChelloUs: req.tcpToChelloUs
|
|
92
92
|
},
|
|
93
|
-
...req.
|
|
94
|
-
|
|
93
|
+
...req.chelloToHandshakeUs !== void 0 && {
|
|
94
|
+
chelloToHandshakeUs: req.chelloToHandshakeUs
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
});
|
|
@@ -120,7 +120,10 @@ const submitPoWCaptchaSolution = (env) => async (req, res, next) => {
|
|
|
120
120
|
}
|
|
121
121
|
}));
|
|
122
122
|
}
|
|
123
|
-
const escalation = await buildEscalation(tasks$1, result, challenge
|
|
123
|
+
const escalation = await buildEscalation(tasks$1, result, challenge, {
|
|
124
|
+
tcpToChelloUs: req.tcpToChelloUs,
|
|
125
|
+
chelloToHandshakeUs: req.chelloToHandshakeUs
|
|
126
|
+
});
|
|
124
127
|
const response = {
|
|
125
128
|
status: "ok",
|
|
126
129
|
// On escalation the user is not done — they still need to clear
|
|
@@ -148,7 +151,7 @@ const submitPoWCaptchaSolution = (env) => async (req, res, next) => {
|
|
|
148
151
|
);
|
|
149
152
|
}
|
|
150
153
|
};
|
|
151
|
-
const buildEscalation = async (tasks2, result, challenge) => {
|
|
154
|
+
const buildEscalation = async (tasks2, result, challenge, handshakeTiming) => {
|
|
152
155
|
if (!result.verified || !result.routingOutput) return void 0;
|
|
153
156
|
const routedType = result.routingOutput.captchaType;
|
|
154
157
|
if (routedType !== types.CaptchaType.image && routedType !== types.CaptchaType.puzzle) {
|
|
@@ -187,7 +190,9 @@ const buildEscalation = async (tasks2, result, challenge) => {
|
|
|
187
190
|
originSession.entropyCryptoFingerprint,
|
|
188
191
|
originSession.entropyWallClockOffsetMs,
|
|
189
192
|
originSession.entropyMathRandomFirst,
|
|
190
|
-
originSession.currentUrl
|
|
193
|
+
originSession.currentUrl,
|
|
194
|
+
handshakeTiming?.tcpToChelloUs,
|
|
195
|
+
handshakeTiming?.chelloToHandshakeUs
|
|
191
196
|
);
|
|
192
197
|
if (tasks2.writeQueue) {
|
|
193
198
|
await tasks2.writeQueue.cacheSessionEscalation(
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const apiExpressRouter = require("@prosopo/api-express-router");
|
|
4
4
|
const logger = require("@prosopo/logger");
|
|
5
|
-
const HEADER_TCP_TO_CHELLO = "x-tls-tcp-to-chello-
|
|
6
|
-
const HEADER_CHELLO_TO_HANDSHAKE = "x-tls-chello-to-handshake-
|
|
5
|
+
const HEADER_TCP_TO_CHELLO = "x-tls-tcp-to-chello-us";
|
|
6
|
+
const HEADER_CHELLO_TO_HANDSHAKE = "x-tls-chello-to-handshake-us";
|
|
7
7
|
const parseTimingHeader = (raw, logger2, headerName) => {
|
|
8
8
|
if (raw === void 0) {
|
|
9
9
|
return void 0;
|
|
@@ -25,12 +25,12 @@ const parseTimingHeader = (raw, logger2, headerName) => {
|
|
|
25
25
|
const getHandshakeTiming = (headers, logger$1) => {
|
|
26
26
|
const log = logger$1 ?? logger.getLogger("info", "provider:handshake-timing");
|
|
27
27
|
return {
|
|
28
|
-
|
|
28
|
+
tcpToChelloUs: parseTimingHeader(
|
|
29
29
|
headers[HEADER_TCP_TO_CHELLO],
|
|
30
30
|
log,
|
|
31
31
|
HEADER_TCP_TO_CHELLO
|
|
32
32
|
),
|
|
33
|
-
|
|
33
|
+
chelloToHandshakeUs: parseTimingHeader(
|
|
34
34
|
headers[HEADER_CHELLO_TO_HANDSHAKE],
|
|
35
35
|
log,
|
|
36
36
|
HEADER_CHELLO_TO_HANDSHAKE
|
|
@@ -41,17 +41,17 @@ const handshakeTimingMiddleware = (env) => {
|
|
|
41
41
|
return async (req, res, next) => {
|
|
42
42
|
try {
|
|
43
43
|
const timing = getHandshakeTiming(req.headers, req.logger);
|
|
44
|
-
if (timing.
|
|
45
|
-
req.
|
|
44
|
+
if (timing.tcpToChelloUs !== void 0) {
|
|
45
|
+
req.tcpToChelloUs = timing.tcpToChelloUs;
|
|
46
46
|
}
|
|
47
|
-
if (timing.
|
|
48
|
-
req.
|
|
47
|
+
if (timing.chelloToHandshakeUs !== void 0) {
|
|
48
|
+
req.chelloToHandshakeUs = timing.chelloToHandshakeUs;
|
|
49
49
|
}
|
|
50
|
-
if (timing.
|
|
50
|
+
if (timing.tcpToChelloUs !== void 0 || timing.chelloToHandshakeUs !== void 0) {
|
|
51
51
|
req.logger = req.logger.with(
|
|
52
52
|
{
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
tcpToChelloUs: timing.tcpToChelloUs,
|
|
54
|
+
chelloToHandshakeUs: timing.chelloToHandshakeUs
|
|
55
55
|
},
|
|
56
56
|
"handshakeTiming"
|
|
57
57
|
);
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const DEFAULT_VERDICT_CACHE_TTL_MS = 1e4;
|
|
4
|
+
const DEFAULT_VERDICT_CACHE_MAX_ENTRIES = 5e4;
|
|
5
|
+
class HardBlockVerdictCache {
|
|
6
|
+
constructor(ttlMs = DEFAULT_VERDICT_CACHE_TTL_MS, maxEntries = DEFAULT_VERDICT_CACHE_MAX_ENTRIES) {
|
|
7
|
+
this.ttlMs = ttlMs;
|
|
8
|
+
this.maxEntries = maxEntries;
|
|
9
|
+
this.store = /* @__PURE__ */ new Map();
|
|
10
|
+
this.inflight = /* @__PURE__ */ new Map();
|
|
11
|
+
}
|
|
12
|
+
get(key) {
|
|
13
|
+
const entry = this.store.get(key);
|
|
14
|
+
if (entry === void 0) {
|
|
15
|
+
return void 0;
|
|
16
|
+
}
|
|
17
|
+
if (entry.expiresAt <= Date.now()) {
|
|
18
|
+
this.store.delete(key);
|
|
19
|
+
return void 0;
|
|
20
|
+
}
|
|
21
|
+
this.store.delete(key);
|
|
22
|
+
this.store.set(key, entry);
|
|
23
|
+
return entry.value;
|
|
24
|
+
}
|
|
25
|
+
set(key, value) {
|
|
26
|
+
this.store.delete(key);
|
|
27
|
+
if (this.store.size >= this.maxEntries) {
|
|
28
|
+
const oldest = this.store.keys().next().value;
|
|
29
|
+
if (oldest !== void 0) {
|
|
30
|
+
this.store.delete(oldest);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
this.store.set(key, {
|
|
34
|
+
value,
|
|
35
|
+
expiresAt: Date.now() + this.ttlMs
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Cache lookup with singleflight dedupe of concurrent misses.
|
|
40
|
+
*
|
|
41
|
+
* Fast path: cache hit → return immediately (with LRU move-to-tail
|
|
42
|
+
* via `get()`).
|
|
43
|
+
*
|
|
44
|
+
* Slow path: cache miss →
|
|
45
|
+
* 1. If an in-flight Promise exists for this key, join it. This
|
|
46
|
+
* is the coalescing behaviour — N concurrent identical misses
|
|
47
|
+
* all await the same underlying storage call.
|
|
48
|
+
* 2. Otherwise, invoke `compute()`, register the Promise, and
|
|
49
|
+
* populate the cache with the result on resolve. The Promise
|
|
50
|
+
* is removed from the in-flight map in a `finally` so a
|
|
51
|
+
* rejection doesn't wedge future callers.
|
|
52
|
+
*
|
|
53
|
+
* Rejection semantics: if `compute()` throws, all joined waiters
|
|
54
|
+
* see the same rejection. Callers should handle it — the underlying
|
|
55
|
+
* `getPrioritisedAccessRule` catches its own storage errors and
|
|
56
|
+
* returns `[]` (fail-open), so in practice this never propagates.
|
|
57
|
+
*/
|
|
58
|
+
async getOrCompute(key, compute) {
|
|
59
|
+
const cached = this.get(key);
|
|
60
|
+
if (cached !== void 0) {
|
|
61
|
+
return cached;
|
|
62
|
+
}
|
|
63
|
+
const existing = this.inflight.get(key);
|
|
64
|
+
if (existing !== void 0) {
|
|
65
|
+
return existing;
|
|
66
|
+
}
|
|
67
|
+
const promise = (async () => {
|
|
68
|
+
const value = await compute();
|
|
69
|
+
this.set(key, value);
|
|
70
|
+
return value;
|
|
71
|
+
})();
|
|
72
|
+
this.inflight.set(key, promise);
|
|
73
|
+
try {
|
|
74
|
+
return await promise;
|
|
75
|
+
} finally {
|
|
76
|
+
if (this.inflight.get(key) === promise) {
|
|
77
|
+
this.inflight.delete(key);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Test/ops hook — the running cache is not exposed on the wire, but
|
|
82
|
+
// admin tooling (e.g. a rule-mutation notifier) may need to flush
|
|
83
|
+
// after a bulk insert to bound the staleness window. Clears both
|
|
84
|
+
// the stored entries and any in-flight Promises so a rule mutation
|
|
85
|
+
// can't leave a stale computation in flight.
|
|
86
|
+
clear() {
|
|
87
|
+
this.store.clear();
|
|
88
|
+
this.inflight.clear();
|
|
89
|
+
}
|
|
90
|
+
size() {
|
|
91
|
+
return this.store.size;
|
|
92
|
+
}
|
|
93
|
+
// Test hook: number of in-flight computations. Not on the hot path.
|
|
94
|
+
inflightSize() {
|
|
95
|
+
return this.inflight.size;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const hardBlockCacheKey = (clientId, userScope, blockOnly) => {
|
|
99
|
+
const bo = blockOnly ? "1" : "0";
|
|
100
|
+
const parts = [
|
|
101
|
+
clientId ?? "",
|
|
102
|
+
userScope.numericIp === void 0 ? "" : userScope.numericIp.toString(),
|
|
103
|
+
userScope.numericIpMaskMin === void 0 ? "" : userScope.numericIpMaskMin.toString(),
|
|
104
|
+
userScope.numericIpMaskMax === void 0 ? "" : userScope.numericIpMaskMax.toString(),
|
|
105
|
+
userScope.userId ?? "",
|
|
106
|
+
userScope.ja4Hash ?? "",
|
|
107
|
+
userScope.headersHash ?? "",
|
|
108
|
+
userScope.userAgentHash ?? "",
|
|
109
|
+
userScope.headHash ?? "",
|
|
110
|
+
userScope.coords ?? "",
|
|
111
|
+
userScope.countryCode ?? "",
|
|
112
|
+
userScope.asn === void 0 ? "" : String(userScope.asn)
|
|
113
|
+
];
|
|
114
|
+
return `${bo}|${parts.join("|")}`;
|
|
115
|
+
};
|
|
116
|
+
exports.DEFAULT_VERDICT_CACHE_MAX_ENTRIES = DEFAULT_VERDICT_CACHE_MAX_ENTRIES;
|
|
117
|
+
exports.DEFAULT_VERDICT_CACHE_TTL_MS = DEFAULT_VERDICT_CACHE_TTL_MS;
|
|
118
|
+
exports.HardBlockVerdictCache = HardBlockVerdictCache;
|
|
119
|
+
exports.hardBlockCacheKey = hardBlockCacheKey;
|
|
@@ -115,6 +115,17 @@ async function startProviderApi(env, admin = false, port) {
|
|
|
115
115
|
...api.getExpressApiRuleRateLimits()
|
|
116
116
|
};
|
|
117
117
|
const adminPaths = Object.values(types.AdminApiPaths);
|
|
118
|
+
const rateLimitHandler = (path2) => (req, res, _next, options) => {
|
|
119
|
+
env.logger.warn(() => ({
|
|
120
|
+
msg: "Rate limit exceeded",
|
|
121
|
+
data: {
|
|
122
|
+
path: path2,
|
|
123
|
+
ip: req.ip,
|
|
124
|
+
siteKey: req.headers["prosopo-site-key"]
|
|
125
|
+
}
|
|
126
|
+
}));
|
|
127
|
+
res.status(options.statusCode).send(options.message);
|
|
128
|
+
};
|
|
118
129
|
for (const [path2, limit] of Object.entries(rateLimits)) {
|
|
119
130
|
const enumPath = path2;
|
|
120
131
|
if (adminPaths.includes(enumPath)) {
|
|
@@ -122,6 +133,7 @@ async function startProviderApi(env, admin = false, port) {
|
|
|
122
133
|
enumPath,
|
|
123
134
|
rateLimit({
|
|
124
135
|
...limit,
|
|
136
|
+
handler: rateLimitHandler(enumPath),
|
|
125
137
|
keyGenerator: (req) => {
|
|
126
138
|
const user = getUserFromJWT(req);
|
|
127
139
|
return user || req.ip || "unknown";
|
|
@@ -133,6 +145,7 @@ async function startProviderApi(env, admin = false, port) {
|
|
|
133
145
|
enumPath,
|
|
134
146
|
rateLimit({
|
|
135
147
|
...limit,
|
|
148
|
+
handler: rateLimitHandler(enumPath),
|
|
136
149
|
keyGenerator: (req) => {
|
|
137
150
|
const siteKey = req.headers["prosopo-site-key"];
|
|
138
151
|
return siteKey || req.ip || "unknown";
|
|
@@ -140,7 +153,10 @@ async function startProviderApi(env, admin = false, port) {
|
|
|
140
153
|
})
|
|
141
154
|
);
|
|
142
155
|
} else {
|
|
143
|
-
apiApp.use(
|
|
156
|
+
apiApp.use(
|
|
157
|
+
enumPath,
|
|
158
|
+
rateLimit({ ...limit, handler: rateLimitHandler(enumPath) })
|
|
159
|
+
);
|
|
144
160
|
}
|
|
145
161
|
}
|
|
146
162
|
}
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -63,6 +63,7 @@ exports.compareIPs = ipComparison.compareIPs;
|
|
|
63
63
|
exports.BlacklistRequestInspector = blacklistRequestInspector.BlacklistRequestInspector;
|
|
64
64
|
exports.getPrioritisedAccessRule = blacklistRequestInspector.getPrioritisedAccessRule;
|
|
65
65
|
exports.getRequestUserScope = blacklistRequestInspector.getRequestUserScope;
|
|
66
|
+
exports.getVerdictCache = blacklistRequestInspector.getVerdictCache;
|
|
66
67
|
exports.rankCandidateRules = blacklistRequestInspector.rankCandidateRules;
|
|
67
68
|
Object.defineProperty(exports, "FrictionlessReason", {
|
|
68
69
|
enumerable: true,
|
|
@@ -73,8 +73,8 @@ class FrictionlessManager extends captchaManager.CaptchaManager {
|
|
|
73
73
|
entropyCryptoFingerprint: params.entropyCryptoFingerprint,
|
|
74
74
|
entropyWallClockOffsetMs: params.entropyWallClockOffsetMs,
|
|
75
75
|
entropyMathRandomFirst: params.entropyMathRandomFirst,
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
tcpToChelloUs: params.tcpToChelloUs,
|
|
77
|
+
chelloToHandshakeUs: params.chelloToHandshakeUs
|
|
78
78
|
};
|
|
79
79
|
}
|
|
80
80
|
updateScore(score, scoreComponents) {
|
|
@@ -86,7 +86,7 @@ class FrictionlessManager extends captchaManager.CaptchaManager {
|
|
|
86
86
|
checkLangRules(acceptLanguage) {
|
|
87
87
|
return lang.checkLangRules(this.config, acceptLanguage);
|
|
88
88
|
}
|
|
89
|
-
async createSession(token, score, threshold, scoreComponents, ipAddress, captchaType, siteKey, solvedImagesCount, powDifficulty, userSitekeyIpHash, webView = false, iFrame = false, decryptedHeadHash = "", reason, blocked, deleted, ipInfo, headers, mode, simdReadings, entropyMathRandomFingerprint, entropyCryptoFingerprint, entropyWallClockOffsetMs, entropyMathRandomFirst, currentUrl,
|
|
89
|
+
async createSession(token, score, threshold, scoreComponents, ipAddress, captchaType, siteKey, solvedImagesCount, powDifficulty, userSitekeyIpHash, webView = false, iFrame = false, decryptedHeadHash = "", reason, blocked, deleted, ipInfo, headers, mode, simdReadings, entropyMathRandomFingerprint, entropyCryptoFingerprint, entropyWallClockOffsetMs, entropyMathRandomFirst, currentUrl, tcpToChelloUs, chelloToHandshakeUs) {
|
|
90
90
|
const sessionRecord = {
|
|
91
91
|
sessionId: `${getSessionIDPrefix(this.config.host)}-${uuid.v4()}`,
|
|
92
92
|
createdAt: /* @__PURE__ */ new Date(),
|
|
@@ -120,8 +120,8 @@ class FrictionlessManager extends captchaManager.CaptchaManager {
|
|
|
120
120
|
entropyCryptoFingerprint,
|
|
121
121
|
entropyWallClockOffsetMs,
|
|
122
122
|
entropyMathRandomFirst,
|
|
123
|
-
|
|
124
|
-
|
|
123
|
+
tcpToChelloUs,
|
|
124
|
+
chelloToHandshakeUs
|
|
125
125
|
};
|
|
126
126
|
await this.db.storeSessionRecord(sessionRecord);
|
|
127
127
|
if (this.writeQueue) {
|
|
@@ -203,8 +203,8 @@ class FrictionlessManager extends captchaManager.CaptchaManager {
|
|
|
203
203
|
effectiveParams.entropyWallClockOffsetMs,
|
|
204
204
|
effectiveParams.entropyMathRandomFirst,
|
|
205
205
|
effectiveParams.currentUrl,
|
|
206
|
-
effectiveParams.
|
|
207
|
-
effectiveParams.
|
|
206
|
+
effectiveParams.tcpToChelloUs,
|
|
207
|
+
effectiveParams.chelloToHandshakeUs
|
|
208
208
|
);
|
|
209
209
|
if (this.routingContext && this.usageCounters) {
|
|
210
210
|
this.usageCounters.incrManyAsync(
|
|
@@ -257,8 +257,8 @@ class FrictionlessManager extends captchaManager.CaptchaManager {
|
|
|
257
257
|
effectiveParams.entropyWallClockOffsetMs,
|
|
258
258
|
effectiveParams.entropyMathRandomFirst,
|
|
259
259
|
effectiveParams.currentUrl,
|
|
260
|
-
effectiveParams.
|
|
261
|
-
effectiveParams.
|
|
260
|
+
effectiveParams.tcpToChelloUs,
|
|
261
|
+
effectiveParams.chelloToHandshakeUs
|
|
262
262
|
);
|
|
263
263
|
}
|
|
264
264
|
scoreIncreaseAccessPolicy(accessPolicy, baseBotScore, botScore, scoreComponents) {
|
|
@@ -23,7 +23,7 @@ const isDatacenterAllowlisted = (ipInfo, allowlist) => {
|
|
|
23
23
|
);
|
|
24
24
|
return candidates.some((c) => normalisedAllowlist.includes(c));
|
|
25
25
|
};
|
|
26
|
-
const evaluateIpInfo = (ipInfo, trafficFilter,
|
|
26
|
+
const evaluateIpInfo = (ipInfo, trafficFilter, isDnsExtra = false) => {
|
|
27
27
|
if (!ipInfo || !ipInfo.isValid) {
|
|
28
28
|
return { isBlocked: false };
|
|
29
29
|
}
|
|
@@ -46,7 +46,8 @@ const evaluateIpInfo = (ipInfo, trafficFilter, options) => {
|
|
|
46
46
|
return { isBlocked: true, reason: types.ResultReason.ABUSER_BLOCKED };
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
-
|
|
49
|
+
const datacenterSuppressedByCategory = ipInfo.isVPN && !trafficFilter.blockVpn || ipInfo.isProxy && !trafficFilter.blockProxy || ipInfo.isTor && !trafficFilter.blockTor || ipInfo.isCrawler && !trafficFilter.blockCrawler;
|
|
50
|
+
if (trafficFilter.blockDatacenter && ipInfo.isDatacenter && ipInfo.providerType !== "isp" && !datacenterSuppressedByCategory && !isDatacenterAllowlisted(ipInfo, trafficFilter.datacenterNameAllowlist)) {
|
|
50
51
|
return { isBlocked: true, reason: types.ResultReason.DATACENTER_BLOCKED };
|
|
51
52
|
}
|
|
52
53
|
if (trafficFilter.blockMobile && ipInfo.isMobile) {
|
|
@@ -55,15 +56,13 @@ const evaluateIpInfo = (ipInfo, trafficFilter, options) => {
|
|
|
55
56
|
if (trafficFilter.blockSatellite && ipInfo.isSatellite) {
|
|
56
57
|
return { isBlocked: true, reason: types.ResultReason.SATELLITE_BLOCKED };
|
|
57
58
|
}
|
|
58
|
-
if (trafficFilter.blockCrawler && ipInfo.isCrawler) {
|
|
59
|
+
if (!isDnsExtra && trafficFilter.blockCrawler && ipInfo.isCrawler) {
|
|
59
60
|
return { isBlocked: true, reason: types.ResultReason.CRAWLER_BLOCKED };
|
|
60
61
|
}
|
|
61
62
|
return { isBlocked: false };
|
|
62
63
|
};
|
|
63
64
|
const checkTrafficFilter = (ipInfo, trafficFilter, extraIpInfos, dnsPathValid) => {
|
|
64
|
-
const primary = evaluateIpInfo(ipInfo, trafficFilter
|
|
65
|
-
suppressVpnDatacenterInteraction: true
|
|
66
|
-
});
|
|
65
|
+
const primary = evaluateIpInfo(ipInfo, trafficFilter);
|
|
67
66
|
if (primary.isBlocked) {
|
|
68
67
|
return primary;
|
|
69
68
|
}
|
|
@@ -71,9 +70,7 @@ const checkTrafficFilter = (ipInfo, trafficFilter, extraIpInfos, dnsPathValid) =
|
|
|
71
70
|
return { isBlocked: false };
|
|
72
71
|
}
|
|
73
72
|
for (const extra of extraIpInfos ?? []) {
|
|
74
|
-
const result = evaluateIpInfo(extra, trafficFilter,
|
|
75
|
-
suppressVpnDatacenterInteraction: false
|
|
76
|
-
});
|
|
73
|
+
const result = evaluateIpInfo(extra, trafficFilter, true);
|
|
77
74
|
if (result.isBlocked) {
|
|
78
75
|
return result;
|
|
79
76
|
}
|
package/dist/index.js
CHANGED
|
@@ -19,7 +19,7 @@ import { ignoreMiddleware } from "./api/ignoreMiddleware.js";
|
|
|
19
19
|
import { robotsMiddleware } from "./api/robotsMiddleware.js";
|
|
20
20
|
import { getCompositeIpAddress, getIpAddressFromComposite } from "./compositeIpAddress.js";
|
|
21
21
|
import { compareIPs } from "./services/ipComparison.js";
|
|
22
|
-
import { BlacklistRequestInspector, getPrioritisedAccessRule, getRequestUserScope, rankCandidateRules } from "./api/blacklistRequestInspector.js";
|
|
22
|
+
import { BlacklistRequestInspector, getPrioritisedAccessRule, getRequestUserScope, getVerdictCache, rankCandidateRules } from "./api/blacklistRequestInspector.js";
|
|
23
23
|
import "./tasks/frictionless/frictionlessTasks.js";
|
|
24
24
|
import { FrictionlessReason } from "@prosopo/types";
|
|
25
25
|
import { Tasks } from "./tasks/tasks.js";
|
|
@@ -48,6 +48,7 @@ export {
|
|
|
48
48
|
getPrioritisedAccessRule,
|
|
49
49
|
getRequestUserScope,
|
|
50
50
|
getUserFromJWT,
|
|
51
|
+
getVerdictCache,
|
|
51
52
|
handshakeTimingMiddleware,
|
|
52
53
|
headerCheckMiddleware,
|
|
53
54
|
ignoreMiddleware,
|
|
@@ -42,6 +42,7 @@ export declare class CaptchaManager {
|
|
|
42
42
|
};
|
|
43
43
|
getPrioritisedAccessPolicies(userAccessRulesStorage: AccessRulesStorage, clientId: string, userScope: UserScope | UserScopeRecord, options?: {
|
|
44
44
|
blockOnly?: boolean;
|
|
45
|
+
requestMemoHost?: object;
|
|
45
46
|
}): Promise<import("@prosopo/user-access-policy").AccessRule[]>;
|
|
46
47
|
getDetectorKeys(): Promise<string[]>;
|
|
47
48
|
decryptSimdReadings(encryptedData: string, decryptKeys: (string | undefined)[]): Promise<SimdReadingsResult | null>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"captchaManager.d.ts","sourceRoot":"","sources":["../../src/tasks/captchaManager.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"captchaManager.d.ts","sourceRoot":"","sources":["../../src/tasks/captchaManager.ts"],"names":[],"mappings":"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"}
|