@prosopo/provider 5.8.1 → 5.10.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 +18 -13
- package/.turbo/turbo-build$colon$tsc.log +29 -26
- package/.turbo/turbo-build.log +22 -17
- package/CHANGELOG.md +153 -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 -3
- 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/healthzGeo.d.ts +54 -0
- package/dist/api/healthzGeo.d.ts.map +1 -0
- package/dist/api/healthzGeo.js +205 -0
- package/dist/api/healthzGeo.js.map +1 -0
- package/dist/api/metrics.d.ts +3 -0
- package/dist/api/metrics.d.ts.map +1 -1
- package/dist/api/metrics.js +11 -1
- package/dist/api/metrics.js.map +1 -1
- package/dist/api/public.d.ts.map +1 -1
- package/dist/api/public.js +13 -3
- package/dist/api/public.js.map +1 -1
- 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 -3
- package/dist/cjs/api/captcha/getImageCaptchaChallenge.cjs +3 -1
- package/dist/cjs/api/captcha/signedAssetsResolver.cjs +54 -0
- package/dist/cjs/api/healthzGeo.cjs +209 -0
- package/dist/cjs/api/metrics.cjs +11 -0
- package/dist/cjs/api/public.cjs +13 -2
- package/dist/cjs/api/verify.cjs +83 -0
- package/dist/cjs/tasks/detection/getBotScore.cjs +3 -1
- package/dist/cjs/tasks/frictionless/frictionlessTasks.cjs +95 -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 +6 -0
- package/dist/tasks/frictionless/frictionlessTasks.d.ts.map +1 -1
- package/dist/tasks/frictionless/frictionlessTasks.js +96 -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/trafficFilterHierarchy.integration.test.js +1 -0
- package/dist/tests/integration/trafficFilterHierarchy.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 +449 -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/healthzGeo.unit.test.d.ts +2 -0
- package/dist/tests/unit/api/healthzGeo.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/api/healthzGeo.unit.test.js +272 -0
- package/dist/tests/unit/api/healthzGeo.unit.test.js.map +1 -0
- package/dist/tests/unit/api/public.unit.test.js +132 -2
- package/dist/tests/unit/api/public.unit.test.js.map +1 -1
- package/dist/tests/unit/services/ipComparison.unit.test.js +2 -0
- package/dist/tests/unit/services/ipComparison.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/decryptPayload.unit.test.js +35 -0
- package/dist/tests/unit/tasks/frictionless/decryptPayload.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/tests/unit/testUtils/mockProviderEnv.d.ts.map +1 -1
- package/dist/tests/unit/testUtils/mockProviderEnv.js +1 -0
- package/dist/tests/unit/testUtils/mockProviderEnv.js.map +1 -1
- package/dist/tests/unit/util.ipDistance.unit.test.js +1 -0
- package/dist/tests/unit/util.ipDistance.unit.test.js.map +1 -1
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js.map +1 -1
- package/package.json +16 -14
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
let _prosopo_types = require("@prosopo/types");
|
|
2
|
+
let zod = require("zod");
|
|
3
|
+
//#region src/api/healthzGeo.ts
|
|
4
|
+
/**
|
|
5
|
+
* Geo steering for `/healthz`.
|
|
6
|
+
*
|
|
7
|
+
* `/healthz` tells a client which node to pin its captcha calls to. By default
|
|
8
|
+
* a node answers with its own name, so the pin is whatever the DNS layer
|
|
9
|
+
* picked. With steering enabled the node instead answers with the node the
|
|
10
|
+
* caller's country is mapped to, when that node is known to be up.
|
|
11
|
+
*
|
|
12
|
+
* Off by default. With the flag off nothing here runs: no lookup, no poller,
|
|
13
|
+
* no response header, no counter.
|
|
14
|
+
*
|
|
15
|
+
* Configuration (all read once, at first use):
|
|
16
|
+
*
|
|
17
|
+
* PROSOPO_HEALTHZ_GEO_STEERING
|
|
18
|
+
* "true" enables steering. Anything else, including unset, disables it.
|
|
19
|
+
*
|
|
20
|
+
* PROSOPO_HEALTHZ_GEO_ROUTES
|
|
21
|
+
* JSON object mapping ISO 3166-1 alpha-2 country code to hostname, e.g.
|
|
22
|
+
* `{"XX":"node1.example.com","YY":"node2.example.com"}`. Keys are
|
|
23
|
+
* case-insensitive. Countries absent from the map are not steered.
|
|
24
|
+
*
|
|
25
|
+
* The map is the candidate set: a host that must not receive traffic
|
|
26
|
+
* simply does not appear in it. Nothing here derives candidates from
|
|
27
|
+
* anywhere else, so the deployment that generates the map is the single
|
|
28
|
+
* place that decides which nodes are in rotation.
|
|
29
|
+
*
|
|
30
|
+
* PROSOPO_HEALTHZ_GEO_PROBE_INTERVAL_MS (default 30000)
|
|
31
|
+
* PROSOPO_HEALTHZ_GEO_PROBE_TIMEOUT_MS (default 2000)
|
|
32
|
+
* Background health-probe period and per-probe timeout.
|
|
33
|
+
*
|
|
34
|
+
* An invalid or unparseable route map disables steering rather than failing
|
|
35
|
+
* startup — the fallback is the node's own name, which is the default
|
|
36
|
+
* behaviour.
|
|
37
|
+
*/
|
|
38
|
+
var DEFAULT_PROBE_INTERVAL_MS = 3e4;
|
|
39
|
+
var DEFAULT_PROBE_TIMEOUT_MS = 2e3;
|
|
40
|
+
var MIN_PROBE_INTERVAL_MS = 1e3;
|
|
41
|
+
/** Hostname, not a URL: no scheme, no path, no port. */
|
|
42
|
+
var hostnameSchema = zod.z.string().min(1).max(253).regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i);
|
|
43
|
+
var routesSchema = zod.z.record(zod.z.string().regex(/^[a-z]{2}$/i), hostnameSchema);
|
|
44
|
+
var parsePositiveInt = (raw, fallback) => {
|
|
45
|
+
if (raw === void 0) return fallback;
|
|
46
|
+
const parsed = Number.parseInt(raw, 10);
|
|
47
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
48
|
+
};
|
|
49
|
+
var parseRoutes = (raw, logger) => {
|
|
50
|
+
if (!raw || raw.trim().length === 0) return /* @__PURE__ */ new Map();
|
|
51
|
+
try {
|
|
52
|
+
const parsed = routesSchema.parse(JSON.parse(raw));
|
|
53
|
+
return new Map(Object.entries(parsed).map(([country, host]) => [country.toUpperCase(), host]));
|
|
54
|
+
} catch (err) {
|
|
55
|
+
logger?.warn(() => ({
|
|
56
|
+
msg: "PROSOPO_HEALTHZ_GEO_ROUTES is not a valid country->host map; healthz geo steering stays off",
|
|
57
|
+
err
|
|
58
|
+
}));
|
|
59
|
+
return /* @__PURE__ */ new Map();
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
var readHealthzGeoConfig = (envVars = process.env, logger) => {
|
|
63
|
+
const routes = parseRoutes(envVars.PROSOPO_HEALTHZ_GEO_ROUTES, logger);
|
|
64
|
+
return {
|
|
65
|
+
enabled: envVars.PROSOPO_HEALTHZ_GEO_STEERING === "true" && routes.size > 0,
|
|
66
|
+
routes,
|
|
67
|
+
probeIntervalMs: Math.max(MIN_PROBE_INTERVAL_MS, parsePositiveInt(envVars.PROSOPO_HEALTHZ_GEO_PROBE_INTERVAL_MS, DEFAULT_PROBE_INTERVAL_MS)),
|
|
68
|
+
probeTimeoutMs: parsePositiveInt(envVars.PROSOPO_HEALTHZ_GEO_PROBE_TIMEOUT_MS, DEFAULT_PROBE_TIMEOUT_MS)
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
var fetchHealthzProbe = async (host, timeoutMs) => {
|
|
72
|
+
try {
|
|
73
|
+
return (await fetch(`https://${host}${_prosopo_types.PublicApiPaths.Healthz}`, {
|
|
74
|
+
method: "GET",
|
|
75
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
76
|
+
})).ok;
|
|
77
|
+
} catch {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Tracks whether each candidate host is answering, in the background.
|
|
83
|
+
*
|
|
84
|
+
* `/healthz` is served before the request pipeline that would otherwise
|
|
85
|
+
* observe a node's health, so nothing else here knows whether a candidate is
|
|
86
|
+
* reachable. Every host starts `false` and only becomes `true` on a successful
|
|
87
|
+
* probe, so a poller that has not run, cannot run, or is failing leaves every
|
|
88
|
+
* candidate down and steering off — degrading to the default behaviour by
|
|
89
|
+
* construction rather than by a fallback branch.
|
|
90
|
+
*
|
|
91
|
+
* The probe never touches the request path: `isUp()` reads a boolean.
|
|
92
|
+
*/
|
|
93
|
+
var TargetHealthMonitor = class {
|
|
94
|
+
constructor(options) {
|
|
95
|
+
this.up = /* @__PURE__ */ new Map();
|
|
96
|
+
this.hosts = [...new Set(options.hosts)];
|
|
97
|
+
this.intervalMs = options.intervalMs;
|
|
98
|
+
this.timeoutMs = options.timeoutMs;
|
|
99
|
+
this.probe = options.probe ?? fetchHealthzProbe;
|
|
100
|
+
this.logger = options.logger;
|
|
101
|
+
}
|
|
102
|
+
isUp(host) {
|
|
103
|
+
return this.up.get(host) === true;
|
|
104
|
+
}
|
|
105
|
+
start() {
|
|
106
|
+
if (this.timer !== void 0 || this.hosts.length === 0) return;
|
|
107
|
+
this.pollAll();
|
|
108
|
+
this.timer = setInterval(() => {
|
|
109
|
+
this.pollAll();
|
|
110
|
+
}, this.intervalMs);
|
|
111
|
+
this.timer.unref?.();
|
|
112
|
+
}
|
|
113
|
+
stop() {
|
|
114
|
+
if (this.timer !== void 0) {
|
|
115
|
+
clearInterval(this.timer);
|
|
116
|
+
this.timer = void 0;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/** One probe round over every candidate. Exposed so tests can await it. */
|
|
120
|
+
async pollAll() {
|
|
121
|
+
await Promise.all(this.hosts.map(async (host) => {
|
|
122
|
+
let healthy = false;
|
|
123
|
+
try {
|
|
124
|
+
healthy = await this.probe(host, this.timeoutMs);
|
|
125
|
+
} catch {
|
|
126
|
+
healthy = false;
|
|
127
|
+
}
|
|
128
|
+
const previous = this.up.get(host);
|
|
129
|
+
this.up.set(host, healthy);
|
|
130
|
+
if (previous !== healthy) this.logger?.info(() => ({
|
|
131
|
+
msg: "healthz geo target health changed",
|
|
132
|
+
data: {
|
|
133
|
+
host,
|
|
134
|
+
healthy
|
|
135
|
+
}
|
|
136
|
+
}));
|
|
137
|
+
}));
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* Picks the host `/healthz` should answer with. Pure apart from reading the
|
|
142
|
+
* monitor's booleans and the memory-mapped country lookup — it never awaits
|
|
143
|
+
* anything, so it cannot delay or fail a health check.
|
|
144
|
+
*/
|
|
145
|
+
var HealthzGeoRouter = class {
|
|
146
|
+
constructor(config, env, monitor) {
|
|
147
|
+
this.enabled = config.enabled;
|
|
148
|
+
this.routes = config.routes;
|
|
149
|
+
this.ipInfoService = env.ipInfoService;
|
|
150
|
+
this.monitor = monitor ?? new TargetHealthMonitor({
|
|
151
|
+
hosts: [...new Set(config.routes.values())],
|
|
152
|
+
intervalMs: config.probeIntervalMs,
|
|
153
|
+
timeoutMs: config.probeTimeoutMs,
|
|
154
|
+
logger: env.logger
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
start() {
|
|
158
|
+
if (this.enabled) this.monitor.start();
|
|
159
|
+
}
|
|
160
|
+
stop() {
|
|
161
|
+
this.monitor.stop();
|
|
162
|
+
}
|
|
163
|
+
resolveHost(clientIp, ownHost) {
|
|
164
|
+
if (!this.enabled) return {
|
|
165
|
+
host: ownHost,
|
|
166
|
+
outcome: "not_steered"
|
|
167
|
+
};
|
|
168
|
+
if (!clientIp) return {
|
|
169
|
+
host: ownHost,
|
|
170
|
+
outcome: "geo_unavailable"
|
|
171
|
+
};
|
|
172
|
+
if (!this.ipInfoService.isAvailable()) return {
|
|
173
|
+
host: ownHost,
|
|
174
|
+
outcome: "geo_unavailable"
|
|
175
|
+
};
|
|
176
|
+
const country = this.ipInfoService.country(clientIp);
|
|
177
|
+
if (!country) return {
|
|
178
|
+
host: ownHost,
|
|
179
|
+
outcome: "geo_unavailable"
|
|
180
|
+
};
|
|
181
|
+
const target = this.routes.get(country.toUpperCase());
|
|
182
|
+
if (target === void 0 || target === ownHost) return {
|
|
183
|
+
host: ownHost,
|
|
184
|
+
outcome: "not_steered"
|
|
185
|
+
};
|
|
186
|
+
if (!this.monitor.isUp(target)) return {
|
|
187
|
+
host: ownHost,
|
|
188
|
+
outcome: "target_down"
|
|
189
|
+
};
|
|
190
|
+
return {
|
|
191
|
+
host: target,
|
|
192
|
+
outcome: "steered"
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
var cachedRouter;
|
|
197
|
+
var getHealthzGeoRouter = (env) => {
|
|
198
|
+
if (!cachedRouter) {
|
|
199
|
+
cachedRouter = new HealthzGeoRouter(readHealthzGeoConfig(process.env, env.logger), env);
|
|
200
|
+
cachedRouter.start();
|
|
201
|
+
}
|
|
202
|
+
return cachedRouter;
|
|
203
|
+
};
|
|
204
|
+
//#endregion
|
|
205
|
+
exports.HealthzGeoRouter = HealthzGeoRouter;
|
|
206
|
+
exports.TargetHealthMonitor = TargetHealthMonitor;
|
|
207
|
+
exports.fetchHealthzProbe = fetchHealthzProbe;
|
|
208
|
+
exports.getHealthzGeoRouter = getHealthzGeoRouter;
|
|
209
|
+
exports.readHealthzGeoConfig = readHealthzGeoConfig;
|
package/dist/cjs/api/metrics.cjs
CHANGED
|
@@ -154,6 +154,12 @@ var buildMetrics = () => {
|
|
|
154
154
|
help: "1 when the given redis connection is ready, else 0",
|
|
155
155
|
labelNames: ["actor"],
|
|
156
156
|
registers: [registry]
|
|
157
|
+
}),
|
|
158
|
+
healthzGeoOutcomesTotal: new prom_client.Counter({
|
|
159
|
+
name: `${PREFIX}healthz_geo_outcomes_total`,
|
|
160
|
+
help: "Healthz geo steering outcomes (steered/not_steered/target_down/geo_unavailable)",
|
|
161
|
+
labelNames: ["outcome"],
|
|
162
|
+
registers: [registry]
|
|
157
163
|
})
|
|
158
164
|
};
|
|
159
165
|
};
|
|
@@ -202,6 +208,10 @@ var recordSpamEmail = (result) => {
|
|
|
202
208
|
if (!metricsEnabled()) return;
|
|
203
209
|
getMetrics().spamEmailTotal.inc({ result });
|
|
204
210
|
};
|
|
211
|
+
var recordHealthzGeoOutcome = (outcome) => {
|
|
212
|
+
if (!metricsEnabled()) return;
|
|
213
|
+
getMetrics().healthzGeoOutcomesTotal.inc({ outcome });
|
|
214
|
+
};
|
|
205
215
|
var setMaintenanceModeGauge = (on) => {
|
|
206
216
|
if (!metricsEnabled()) return;
|
|
207
217
|
getMetrics().maintenanceMode.set(on ? 1 : 0);
|
|
@@ -257,5 +267,6 @@ exports.recordCaptchaVerify = recordCaptchaVerify;
|
|
|
257
267
|
exports.recordDetectorTriggered = recordDetectorTriggered;
|
|
258
268
|
exports.recordDomainValidation = recordDomainValidation;
|
|
259
269
|
exports.recordFrictionlessDecision = recordFrictionlessDecision;
|
|
270
|
+
exports.recordHealthzGeoOutcome = recordHealthzGeoOutcome;
|
|
260
271
|
exports.recordSpamEmail = recordSpamEmail;
|
|
261
272
|
exports.setMaintenanceModeGauge = setMaintenanceModeGauge;
|
package/dist/cjs/api/public.cjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
|
|
2
2
|
const require_metrics = require("./metrics.cjs");
|
|
3
|
+
const require_healthzGeo = require("./healthzGeo.cjs");
|
|
3
4
|
let _prosopo_common = require("@prosopo/common");
|
|
4
5
|
let _prosopo_types = require("@prosopo/types");
|
|
5
6
|
let _prosopo_util = require("@prosopo/util");
|
|
@@ -14,11 +15,19 @@ express = require_runtime.__toESM(express, 1);
|
|
|
14
15
|
*/
|
|
15
16
|
function publicRouter(env) {
|
|
16
17
|
const router = express.default.Router();
|
|
18
|
+
const geo = require_healthzGeo.getHealthzGeoRouter(env);
|
|
17
19
|
router.get(_prosopo_types.PublicApiPaths.Healthz, (req, res) => {
|
|
18
|
-
const
|
|
20
|
+
const ownHost = env.config.host && env.config.host.length > 0 ? env.config.host : req.hostname;
|
|
21
|
+
if (!geo.enabled) return res.status(200).json({
|
|
22
|
+
ok: true,
|
|
23
|
+
host: ownHost
|
|
24
|
+
});
|
|
25
|
+
res.set("Cache-Control", "no-store, private");
|
|
26
|
+
const decision = geo.resolveHost(req.ip, ownHost);
|
|
27
|
+
require_metrics.recordHealthzGeoOutcome(decision.outcome);
|
|
19
28
|
return res.status(200).json({
|
|
20
29
|
ok: true,
|
|
21
|
-
host
|
|
30
|
+
host: decision.host
|
|
22
31
|
});
|
|
23
32
|
});
|
|
24
33
|
if (require_metrics.metricsEnabled()) router.get(_prosopo_types.PublicApiPaths.Metrics, require_metrics.metricsHandler(env));
|
|
@@ -30,9 +39,11 @@ function publicRouter(env) {
|
|
|
30
39
|
const db = env.getDb();
|
|
31
40
|
const redisConnection = db.getRedisConnection();
|
|
32
41
|
const redisAccessRulesConnection = db.getRedisAccessRulesConnection();
|
|
42
|
+
const host = env.config.host && env.config.host.length > 0 ? env.config.host : req.hostname;
|
|
33
43
|
const response = {
|
|
34
44
|
version: _prosopo_util.version,
|
|
35
45
|
message: "Provider online",
|
|
46
|
+
host,
|
|
36
47
|
redis: [{
|
|
37
48
|
actor: "General",
|
|
38
49
|
isReady: redisConnection.isReady(),
|
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");
|
|
@@ -79,6 +81,7 @@ var FrictionlessManager = class extends require_captchaManager.CaptchaManager {
|
|
|
79
81
|
entropyMathRandomFirst: params.entropyMathRandomFirst,
|
|
80
82
|
g: params.g,
|
|
81
83
|
i: params.i,
|
|
84
|
+
b: params.b,
|
|
82
85
|
tcpToChelloUs: params.tcpToChelloUs,
|
|
83
86
|
chelloToHandshakeUs: params.chelloToHandshakeUs,
|
|
84
87
|
synNs: params.synNs,
|
|
@@ -172,6 +175,91 @@ var FrictionlessManager = class extends require_captchaManager.CaptchaManager {
|
|
|
172
175
|
}
|
|
173
176
|
return sessionRecord;
|
|
174
177
|
}
|
|
178
|
+
/**
|
|
179
|
+
* Dedicated issuance path for Web Bot Auth verified requests. The signature
|
|
180
|
+
* verification already carried the trust decision; there is no captcha to
|
|
181
|
+
* solve, no bot score to compute, no routing to run. The session is minted
|
|
182
|
+
* with `captchaType: authenticated`, `agent: true`, `webBotAuthAgent` set to
|
|
183
|
+
* the verified Signature-Agent URL, and `ipAddress` frozen for the verify-
|
|
184
|
+
* time IP-binding check. Consumed only by `/client/authenticated/verify`.
|
|
185
|
+
*/
|
|
186
|
+
async createAuthenticatedSession(token, ipAddress, webBotAuthAgent, siteKey, userSitekeyIpHash, headers, ipInfo, clientSessionId) {
|
|
187
|
+
const sessionRecord = {
|
|
188
|
+
sessionId: `${getSessionIDPrefix(this.config.host)}-${(0, uuid.v4)()}`,
|
|
189
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
190
|
+
token,
|
|
191
|
+
score: 0,
|
|
192
|
+
threshold: 0,
|
|
193
|
+
scoreComponents: { baseScore: 0 },
|
|
194
|
+
ipAddress,
|
|
195
|
+
captchaType: _prosopo_types.CaptchaType.authenticated,
|
|
196
|
+
userSitekeyIpHash,
|
|
197
|
+
webView: false,
|
|
198
|
+
iFrame: false,
|
|
199
|
+
decryptedHeadHash: "",
|
|
200
|
+
siteKey,
|
|
201
|
+
serverChecked: false,
|
|
202
|
+
agent: true,
|
|
203
|
+
webBotAuthAgent,
|
|
204
|
+
...ipInfo && { ipInfo },
|
|
205
|
+
...headers && { headers },
|
|
206
|
+
...clientSessionId && { clientMetaData: { clientSessionId } }
|
|
207
|
+
};
|
|
208
|
+
await this.db.storeSessionRecord(sessionRecord);
|
|
209
|
+
if (this.writeQueue) {
|
|
210
|
+
const cacheData = sessionRecord;
|
|
211
|
+
const cachePromises = [this.writeQueue.cacheSession(sessionRecord.sessionId, cacheData)];
|
|
212
|
+
if (userSitekeyIpHash) cachePromises.push(this.writeQueue.cacheSessionByHash(userSitekeyIpHash, sessionRecord.sessionId));
|
|
213
|
+
await Promise.all(cachePromises).catch(() => {});
|
|
214
|
+
}
|
|
215
|
+
return sessionRecord;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Verify an authenticated (Web Bot Auth) session. Called from
|
|
219
|
+
* `/client/authenticated/verify` after the operator forwards their
|
|
220
|
+
* dApp-signed token. Enforces the four properties that make replay
|
|
221
|
+
* infeasible:
|
|
222
|
+
* 1. session exists and was minted with captchaType=authenticated
|
|
223
|
+
* (so ordinary captcha tokens can't be redeemed here)
|
|
224
|
+
* 2. session hasn't been consumed (serverChecked === false)
|
|
225
|
+
* 3. operator forwarded the client IP (`ip` is required — silently
|
|
226
|
+
* dropping the check would nullify the whole binding)
|
|
227
|
+
* 4. the forwarded IP matches the IP the session was issued to
|
|
228
|
+
*
|
|
229
|
+
* Marks serverChecked=true on success so subsequent verifies fail loudly.
|
|
230
|
+
*/
|
|
231
|
+
async verifyAuthenticatedSession(sessionId, ip, clientSessionId) {
|
|
232
|
+
if (!ip) return {
|
|
233
|
+
verified: false,
|
|
234
|
+
status: "API.AUTHENTICATED_IP_REQUIRED"
|
|
235
|
+
};
|
|
236
|
+
const session = await this.db.getSessionRecordBySessionId(sessionId);
|
|
237
|
+
if (!session) return {
|
|
238
|
+
verified: false,
|
|
239
|
+
status: "API.USER_NOT_VERIFIED_NO_SOLUTION"
|
|
240
|
+
};
|
|
241
|
+
if (session.captchaType !== _prosopo_types.CaptchaType.authenticated) return {
|
|
242
|
+
verified: false,
|
|
243
|
+
status: "API.INCORRECT_CAPTCHA_TYPE"
|
|
244
|
+
};
|
|
245
|
+
if (session.serverChecked) return {
|
|
246
|
+
verified: false,
|
|
247
|
+
status: "API.USER_ALREADY_VERIFIED"
|
|
248
|
+
};
|
|
249
|
+
if (!require_ipMatch.ipMatchesSession(ip, session.ipAddress)) return {
|
|
250
|
+
verified: false,
|
|
251
|
+
status: "API.AUTHENTICATED_IP_MISMATCH"
|
|
252
|
+
};
|
|
253
|
+
if (require_clientMetaData.isClientSessionMismatch(clientSessionId, session.clientMetaData?.clientSessionId)) return {
|
|
254
|
+
verified: false,
|
|
255
|
+
status: "API.CLIENT_SESSION_MISMATCH"
|
|
256
|
+
};
|
|
257
|
+
await this.db.updateSessionRecord(sessionId, { serverChecked: true });
|
|
258
|
+
return {
|
|
259
|
+
verified: true,
|
|
260
|
+
status: "API.USER_VERIFIED"
|
|
261
|
+
};
|
|
262
|
+
}
|
|
175
263
|
async sendImageCaptcha(params) {
|
|
176
264
|
return this.sendCaptcha(_prosopo_types.CaptchaType.image, params);
|
|
177
265
|
}
|
|
@@ -198,8 +286,10 @@ var FrictionlessManager = class extends require_captchaManager.CaptchaManager {
|
|
|
198
286
|
const imageRoundsBounds = this.routingContext ?? {};
|
|
199
287
|
const finalSolvedImagesCount = finalCaptchaType === _prosopo_types.CaptchaType.image ? requestedSolvedImagesCount !== void 0 ? (0, _prosopo_types.clampImageRounds)(requestedSolvedImagesCount, imageRoundsBounds) : requestedSolvedImagesCount : void 0;
|
|
200
288
|
const finalPowDifficulty = finalCaptchaType === _prosopo_types.CaptchaType.pow ? routed.powDifficulty ?? effectiveParams.powDifficulty : void 0;
|
|
289
|
+
const finalReason = routed.reason ?? effectiveParams.reason;
|
|
201
290
|
const finalPuzzleOverrides = finalCaptchaType === _prosopo_types.CaptchaType.puzzle ? (() => {
|
|
202
|
-
const
|
|
291
|
+
const maxLevel = this.routingContext?.puzzleMaxDifficulty ?? _prosopo_types.puzzleMaxDifficultyDefault;
|
|
292
|
+
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
293
|
const difficulty = level > 0 ? require_puzzleDifficulty.samplePuzzleDifficulty(level, _prosopo_puzzle_assets.DEFAULT_RENDER_SETTINGS.holeDarken) : void 0;
|
|
204
294
|
const tolerance = routed.puzzleTolerance ?? difficulty?.tolerance;
|
|
205
295
|
const puzzle = routed.puzzle || difficulty ? {
|
|
@@ -211,7 +301,6 @@ var FrictionlessManager = class extends require_captchaManager.CaptchaManager {
|
|
|
211
301
|
...puzzle !== void 0 && { puzzle }
|
|
212
302
|
};
|
|
213
303
|
})() : {};
|
|
214
|
-
const finalReason = routed.reason ?? effectiveParams.reason;
|
|
215
304
|
const blocked = finalCaptchaType === _prosopo_types.CaptchaType.image ? effectiveParams.blocked : void 0;
|
|
216
305
|
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
306
|
synNs: effectiveParams.synNs,
|
|
@@ -346,6 +435,7 @@ var FrictionlessManager = class extends require_captchaManager.CaptchaManager {
|
|
|
346
435
|
let entropyMathRandomFirst;
|
|
347
436
|
let g;
|
|
348
437
|
let ii;
|
|
438
|
+
let bb;
|
|
349
439
|
let sw;
|
|
350
440
|
let md;
|
|
351
441
|
let bn;
|
|
@@ -371,6 +461,7 @@ var FrictionlessManager = class extends require_captchaManager.CaptchaManager {
|
|
|
371
461
|
const em = decrypted.entropyMathRandomFirst;
|
|
372
462
|
const gv = decrypted.g;
|
|
373
463
|
const iv = decrypted.i;
|
|
464
|
+
const bv = decrypted.b;
|
|
374
465
|
const swv = decrypted.sw;
|
|
375
466
|
const mdv = decrypted.md;
|
|
376
467
|
const bnv = decrypted.bn;
|
|
@@ -411,6 +502,7 @@ var FrictionlessManager = class extends require_captchaManager.CaptchaManager {
|
|
|
411
502
|
entropyMathRandomFirst = em;
|
|
412
503
|
g = gv;
|
|
413
504
|
ii = iv;
|
|
505
|
+
bb = bv;
|
|
414
506
|
sw = swv;
|
|
415
507
|
md = mdv;
|
|
416
508
|
bn = bnv;
|
|
@@ -469,6 +561,7 @@ var FrictionlessManager = class extends require_captchaManager.CaptchaManager {
|
|
|
469
561
|
entropyMathRandomFirst,
|
|
470
562
|
g,
|
|
471
563
|
i: ii,
|
|
564
|
+
b: bb,
|
|
472
565
|
sw,
|
|
473
566
|
md,
|
|
474
567
|
bn,
|
|
@@ -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
|