@prosopo/procaptcha-frictionless 2.15.1 → 2.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build$colon$cjs.log +7 -6
- package/.turbo/turbo-build$colon$tsc.log +24 -24
- package/.turbo/turbo-build.log +13 -12
- package/CHANGELOG.md +54 -0
- package/dist/AuthenticatedBadge.d.ts +12 -0
- package/dist/AuthenticatedBadge.d.ts.map +1 -0
- package/dist/AuthenticatedBadge.js +75 -0
- package/dist/AuthenticatedBadge.js.map +1 -0
- package/dist/ProcaptchaFrictionless.d.ts.map +1 -1
- package/dist/ProcaptchaFrictionless.js +18 -2
- package/dist/ProcaptchaFrictionless.js.map +1 -1
- package/dist/cjs/AuthenticatedBadge.cjs +75 -0
- package/dist/cjs/ProcaptchaFrictionless.cjs +18 -2
- package/dist/cjs/customDetectBot.cjs +3 -1
- package/dist/cjs/detectorLoader.cjs +42 -13
- package/dist/customDetectBot.d.ts.map +1 -1
- package/dist/customDetectBot.js +3 -1
- package/dist/customDetectBot.js.map +1 -1
- package/dist/detectorLoader.d.ts +2 -1
- package/dist/detectorLoader.d.ts.map +1 -1
- package/dist/detectorLoader.js +42 -13
- package/dist/detectorLoader.js.map +1 -1
- package/dist/tests/detectorLoader.test.d.ts +2 -0
- package/dist/tests/detectorLoader.test.d.ts.map +1 -0
- package/dist/tests/detectorLoader.test.js +67 -0
- package/dist/tests/detectorLoader.test.js.map +1 -0
- package/package.json +8 -8
- package/src/AuthenticatedBadge.tsx +141 -0
- package/src/ProcaptchaFrictionless.tsx +27 -1
- package/src/customDetectBot.ts +2 -0
- package/src/detectorLoader.ts +52 -12
- package/src/tests/detectorLoader.test.ts +108 -0
- package/tsconfig.tsbuildinfo +1 -1
package/dist/customDetectBot.js
CHANGED
|
@@ -109,7 +109,8 @@ var customDetectBot = async (config, container, restartFn, retryContext) => {
|
|
|
109
109
|
status: captcha.status,
|
|
110
110
|
userAccount,
|
|
111
111
|
error: captcha.error,
|
|
112
|
-
hp: captcha.hp
|
|
112
|
+
hp: captcha.hp,
|
|
113
|
+
agent: captcha.agent
|
|
113
114
|
};
|
|
114
115
|
}
|
|
115
116
|
const detectionResult = await providerDetect(container, restartFn, () => ext.getAccount(config));
|
|
@@ -135,6 +136,7 @@ var customDetectBot = async (config, container, restartFn, retryContext) => {
|
|
|
135
136
|
userAccount,
|
|
136
137
|
error: captcha.error,
|
|
137
138
|
hp: captcha.hp,
|
|
139
|
+
agent: captcha.agent,
|
|
138
140
|
behaviorCollector1: detectionResult.mouseTracker,
|
|
139
141
|
behaviorCollector2: detectionResult.touchTracker,
|
|
140
142
|
behaviorCollector3: detectionResult.clickTracker,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"customDetectBot.js","sourceRoot":"","sources":["../src/customDetectBot.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EACN,eAAe,EACf,iCAAiC,EACjC,UAAU,GACV,MAAM,4BAA4B,CAAC;AAOpC,OAAO,EACN,wBAAwB,GAExB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEN,sBAAsB,GACtB,MAAM,uBAAuB,CAAC;AAO/B,MAAM,iBAAiB,GAAG,MAAM,CAAC;AAqBjC,MAAM,YAAY,GAAG,CAAC,IAAY,EAAsB,EAAE;IACzD,IAAI,CAAC;QACJ,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;QACxB,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM;YAAE,OAAO,SAAS,CAAC;QACvD,OAAO,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AACF,CAAC,CAAC;AAOF,MAAM,kBAAkB,GAAG,GAAa,EAAE;IACzC,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;QACvD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;IACxD,CAAC;IACD,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE;QACnB,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC;QAC7C,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,MAAM;YAAE,OAAO,SAAS,CAAC;QACnD,OAAO,GAAG,MAAM,GAAG,QAAQ,IAAI,EAAE,EAAE,CAAC;IACrC,CAAC,CAAC,EAAE,CAAC;IAGL,IAAI,MAAM,KAAK,MAAM,CAAC,GAAG,EAAE,CAAC;QAC3B,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;IACpD,CAAC;IAGD,IAAI,CAAC;QACJ,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,CAAC;QAC3C,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC9D,IAAI,SAAS;YAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IACnE,CAAC;IAAC,MAAM,CAAC;IAET,CAAC;IAID,IAAI,OAAO,QAAQ,KAAK,WAAW,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;QAC1D,MAAM,YAAY,GAAG,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACrD,IAAI,YAAY;YAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IACzE,CAAC;IAKD,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AAChD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAC/B,OAAmB,EACnB,EAAU,EACG,EAAE;IACf,IAAI,SAAqC,CAAC;IAC1C,MAAM,cAAc,GAAG,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;QACvD,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;YAC3B,MAAM,CAAC,IAAI,eAAe,CAAC,aAAa,CAAC,CAAC,CAAC;QAC5C,CAAC,EAAE,EAAE,CAAC,CAAC;IACR,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC;QACJ,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC;QAC7D,IAAI,SAAS,EAAE,CAAC;YACf,YAAY,CAAC,SAAS,CAAC,CAAC;QACzB,CAAC;QACD,OAAO,MAAM,CAAC;IACf,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAI,SAAS,EAAE,CAAC;YACf,YAAY,CAAC,SAAS,CAAC,CAAC;QACzB,CAAC;QACD,MAAM,KAAK,CAAC;IACb,CAAC;AACF,CAAC,CAAC;AAEF,MAAM,eAAe,GAAyB,KAAK,EAClD,MAAoC,EACpC,SAAkC,EAClC,SAAqB,EACrB,YAAyC,EACH,EAAE;IACxC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QAC7B,MAAM,IAAI,eAAe,CAAC,0BAA0B,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAgBlC,MAAM,eAAe,GAAG,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAerD,MAAM,cAAc,GAAG,CAAC,YAAY,IAAI,YAAY,CAAC,OAAO,IAAI,CAAC,CAAC;IAClE,MAAM,UAAU,GAAG,cAAc;QAChC,CAAC,CAAC,sBAAsB,CACtB,MAAM,CAAC,kBAAkB,EACzB,MAAM,EACN,MAAM,CAAC,OAAO,CAAC,OAAO,CACtB;QACF,CAAC,CAAC,SAAS,CAAC;IAKb,IAAI,gBAAgD,CAAC;IACrD,IAAI,UAAU,EAAE,CAAC;QAChB,IAAI,CAAC;YACJ,gBAAgB,GAAG,MAAM,UAAU,CAAC;QACrC,CAAC;QAAC,MAAM,CAAC;YACR,gBAAgB,GAAG,SAAS,CAAC;QAC9B,CAAC;IACF,CAAC;IAED,MAAM,QAAQ,GACb,gBAAgB,EAAE,QAAQ;QAC1B,CAAC,MAAM,iCAAiC,CACvC,MAAM,CAAC,kBAAkB,EACzB,MAAM,EACN,YAAY,CACZ,CAAC,CAAC;IAEJ,MAAM,WAAW,GAAG,IAAI,WAAW,CAClC,QAAQ,CAAC,QAAQ,CAAC,GAAG,EACrB,MAAM,CAAC,OAAO,CAAC,OAAO,CACtB,CAAC;IAOF,IAAI,iBAAqC,CAAC;IAC1C,IAAI,cAAwC,CAAC;IAC7C,IAAI,CAAC;QAGJ,MAAM,QAAQ,GACb,gBAAgB,EAAE,QAAQ;YAC1B,CAAC,MAAM,WAAW,CACjB,WAAW,CAAC,oBAAoB,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EACxD,iBAAiB,CACjB,CAAC,CAAC;QACJ,IAAI,QAAQ,CAAC,iBAAiB,IAAI,QAAQ,CAAC,cAAc,EAAE,CAAC;YAI3D,cAAc,GAAG,MAAM,wBAAwB,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;YACzE,iBAAiB,GAAG,QAAQ,CAAC,iBAAiB,CAAC;QAChD,CAAC;IACF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QAWd,OAAO,CAAC,KAAK,CACZ,oFAAoF,EACpF,GAAG,CACH,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC;IACvC,MAAM,GAAG,GAAG,IAAI,QAAQ,EAAE,CAAC;IAK3B,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;QAClC,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QACjD,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,iBAAiB,EAAE,GAC9D,kBAAkB,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,MAAM,WAAW,CAChC,WAAW,CAAC,sBAAsB,CACjC,SAAS,EACT,SAAS,EACT,MAAM,CAAC,OAAO,CAAC,OAAO,EACtB,WAAW,CAAC,OAAO,CAAC,OAAO,EAC3B,MAAM,CAAC,IAAI,EACX,SAAS,EACT,SAAS,EACT,WAAW,EACX,iBAAiB,CACjB,EACD,KAAK,CACL,CAAC;QACF,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACrB,IAAI,CAAC;gBACJ,KAAK,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE;oBAC3B,MAAM,EAAE,KAAK;oBACb,IAAI,EAAE,SAAS;oBACf,WAAW,EAAE,MAAM;oBACnB,SAAS,EAAE,IAAI;oBACf,KAAK,EAAE,UAAU;iBACjB,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YAC3B,CAAC;YAAC,MAAM,CAAC;YAET,CAAC;QACF,CAAC;QACD,OAAO;YACN,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,QAAQ,EAAE,QAAQ;YAClB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,WAAW,EAAE,WAAW;YACxB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,EAAE,EAAE,OAAO,CAAC,EAAE;
|
|
1
|
+
{"version":3,"file":"customDetectBot.js","sourceRoot":"","sources":["../src/customDetectBot.ts"],"names":[],"mappings":"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"}
|
package/dist/detectorLoader.d.ts
CHANGED
|
@@ -27,5 +27,6 @@ export type DetectorType = (container: HTMLElement | undefined, restart: () => v
|
|
|
27
27
|
getSimdReadings?: (timeoutMs?: number) => Promise<string | undefined>;
|
|
28
28
|
userAccount: Account;
|
|
29
29
|
}>;
|
|
30
|
-
export
|
|
30
|
+
export type ModuleImporter = (url: string) => Promise<unknown>;
|
|
31
|
+
export declare const DetectorLoaderFromScript: (script: string, importModule?: ModuleImporter) => Promise<DetectorType>;
|
|
31
32
|
//# sourceMappingURL=detectorLoader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detectorLoader.d.ts","sourceRoot":"","sources":["../src/detectorLoader.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACX,OAAO,EACP,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,MAAM,gBAAgB,CAAC;AAOxB,MAAM,MAAM,YAAY,GAAG,CAC1B,SAAS,EAAE,WAAW,GAAG,SAAS,EAClC,OAAO,EAAE,MAAM,IAAI,EACnB,gBAAgB,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,KACpC,OAAO,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE;QACd,KAAK,EAAE,MAAM,IAAI,CAAC;QAClB,IAAI,EAAE,MAAM,IAAI,CAAC;QACjB,OAAO,EAAE,MAAM,kBAAkB,EAAE,CAAC;QACpC,KAAK,EAAE,MAAM,IAAI,CAAC;KAClB,CAAC;IACF,YAAY,CAAC,EAAE;QACd,KAAK,EAAE,MAAM,IAAI,CAAC;QAClB,IAAI,EAAE,MAAM,IAAI,CAAC;QACjB,OAAO,EAAE,MAAM,eAAe,EAAE,CAAC;QACjC,KAAK,EAAE,MAAM,IAAI,CAAC;KAClB,CAAC;IACF,YAAY,CAAC,EAAE;QACd,KAAK,EAAE,MAAM,IAAI,CAAC;QAClB,IAAI,EAAE,MAAM,IAAI,CAAC;QACjB,OAAO,EAAE,MAAM,eAAe,EAAE,CAAC;QACjC,KAAK,EAAE,MAAM,IAAI,CAAC;KAClB,CAAC;IACF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qBAAqB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1D,kBAAkB,CAAC,EAAE,CAAC,cAAc,EAAE,cAAc,KAAK,oBAAoB,CAAC;IAC9E,eAAe,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACtE,WAAW,EAAE,OAAO,CAAC;CACrB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"detectorLoader.d.ts","sourceRoot":"","sources":["../src/detectorLoader.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACX,OAAO,EACP,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,MAAM,gBAAgB,CAAC;AAOxB,MAAM,MAAM,YAAY,GAAG,CAC1B,SAAS,EAAE,WAAW,GAAG,SAAS,EAClC,OAAO,EAAE,MAAM,IAAI,EACnB,gBAAgB,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,KACpC,OAAO,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE;QACd,KAAK,EAAE,MAAM,IAAI,CAAC;QAClB,IAAI,EAAE,MAAM,IAAI,CAAC;QACjB,OAAO,EAAE,MAAM,kBAAkB,EAAE,CAAC;QACpC,KAAK,EAAE,MAAM,IAAI,CAAC;KAClB,CAAC;IACF,YAAY,CAAC,EAAE;QACd,KAAK,EAAE,MAAM,IAAI,CAAC;QAClB,IAAI,EAAE,MAAM,IAAI,CAAC;QACjB,OAAO,EAAE,MAAM,eAAe,EAAE,CAAC;QACjC,KAAK,EAAE,MAAM,IAAI,CAAC;KAClB,CAAC;IACF,YAAY,CAAC,EAAE;QACd,KAAK,EAAE,MAAM,IAAI,CAAC;QAClB,IAAI,EAAE,MAAM,IAAI,CAAC;QACjB,OAAO,EAAE,MAAM,eAAe,EAAE,CAAC;QACjC,KAAK,EAAE,MAAM,IAAI,CAAC;KAClB,CAAC;IACF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qBAAqB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1D,kBAAkB,CAAC,EAAE,CAAC,cAAc,EAAE,cAAc,KAAK,oBAAoB,CAAC;IAC9E,eAAe,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACtE,WAAW,EAAE,OAAO,CAAC;CACrB,CAAC,CAAC;AAoBH,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAoB/D,eAAO,MAAM,wBAAwB,WAC5B,MAAM,iBACA,cAAc,KAC1B,OAAO,CAAC,YAAY,CAiBtB,CAAC"}
|
package/dist/detectorLoader.js
CHANGED
|
@@ -1,20 +1,49 @@
|
|
|
1
1
|
//#region src/detectorLoader.ts
|
|
2
|
+
var blobAttempt = (script) => {
|
|
3
|
+
const url = URL.createObjectURL(new Blob([script], { type: "text/javascript" }));
|
|
4
|
+
return {
|
|
5
|
+
url,
|
|
6
|
+
release: () => URL.revokeObjectURL(url)
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
var dataAttempt = (script) => ({
|
|
10
|
+
url: `data:text/javascript;charset=utf-8,${encodeURIComponent(script)}`,
|
|
11
|
+
release: () => void 0
|
|
12
|
+
});
|
|
13
|
+
var defaultImporter = (url) => import(
|
|
14
|
+
/* @vite-ignore */
|
|
15
|
+
/* webpackIgnore: true */
|
|
16
|
+
url
|
|
17
|
+
);
|
|
2
18
|
/**
|
|
3
|
-
* Loads a detector from a provider-served obfuscated ESM string (the
|
|
4
|
-
* pool bundle).
|
|
5
|
-
*
|
|
19
|
+
* Loads a detector from a provider-served obfuscated ESM string (the
|
|
20
|
+
* per-session pool bundle). The module is self-contained, so a dynamic
|
|
21
|
+
* `import()` yields its default export.
|
|
22
|
+
*
|
|
23
|
+
* A blob URL is tried first, then a `data:` URL. The two are gated by
|
|
24
|
+
* different CSP directives and sites commonly allow one without the other — a
|
|
25
|
+
* `script-src` of `*` matches neither, and a policy listing `data:` for
|
|
26
|
+
* scripts and `blob:` only for workers blocks the blob path outright. Without
|
|
27
|
+
* the fallback every session on such a site loses the detector, sends an empty
|
|
28
|
+
* token, and can never pass frictionlessly.
|
|
29
|
+
*
|
|
30
|
+
* A blocked attempt logs a CSP violation before the import rejects. That noise
|
|
31
|
+
* is the cost of recovering the session.
|
|
6
32
|
*/
|
|
7
|
-
var DetectorLoaderFromScript = async (script) => {
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
url
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
|
|
33
|
+
var DetectorLoaderFromScript = async (script, importModule = defaultImporter) => {
|
|
34
|
+
let lastError = /* @__PURE__ */ new Error("no loader attempt ran");
|
|
35
|
+
for (const build of [blobAttempt, dataAttempt]) {
|
|
36
|
+
let attempt;
|
|
37
|
+
try {
|
|
38
|
+
attempt = build(script);
|
|
39
|
+
return (await importModule(attempt.url)).default;
|
|
40
|
+
} catch (err) {
|
|
41
|
+
lastError = err;
|
|
42
|
+
} finally {
|
|
43
|
+
attempt?.release();
|
|
44
|
+
}
|
|
17
45
|
}
|
|
46
|
+
throw lastError;
|
|
18
47
|
};
|
|
19
48
|
//#endregion
|
|
20
49
|
export { DetectorLoaderFromScript };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detectorLoader.js","sourceRoot":"","sources":["../src/detectorLoader.ts"],"names":[],"mappings":"AAkEA,MAAM,
|
|
1
|
+
{"version":3,"file":"detectorLoader.js","sourceRoot":"","sources":["../src/detectorLoader.ts"],"names":[],"mappings":"AAkEA,MAAM,WAAW,GAAG,CAAC,MAAc,EAAiB,EAAE;IACrD,MAAM,GAAG,GAAG,GAAG,CAAC,eAAe,CAC9B,IAAI,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC,CAC/C,CAAC;IACF,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,GAAS,EAAE,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC;AAC/D,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,MAAc,EAAiB,EAAE,CAAC,CAAC;IACvD,GAAG,EAAE,sCAAsC,kBAAkB,CAAC,MAAM,CAAC,EAAE;IACvE,OAAO,EAAE,GAAS,EAAE,CAAC,SAAS;CAC9B,CAAC,CAAC;AAKH,MAAM,eAAe,GAAmB,CAAC,GAAG,EAAE,EAAE,CAC/C,MAAM,CAA8C,GAAG,CAAC,CAAC;AAiB1D,MAAM,CAAC,MAAM,wBAAwB,GAAG,KAAK,EAC5C,MAAc,EACd,eAA+B,eAAe,EACtB,EAAE;IAC1B,IAAI,SAAS,GAAY,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC5D,KAAK,MAAM,KAAK,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,EAAE,CAAC;QAChD,IAAI,OAAkC,CAAC;QACvC,IAAI,CAAC;YACJ,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;YACxB,MAAM,GAAG,GAAG,CAAC,MAAM,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAE3C,CAAC;YACF,OAAO,GAAG,CAAC,OAAO,CAAC;QACpB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,SAAS,GAAG,GAAG,CAAC;QACjB,CAAC;gBAAS,CAAC;YACV,OAAO,EAAE,OAAO,EAAE,CAAC;QACpB,CAAC;IACF,CAAC;IACD,MAAM,SAAS,CAAC;AACjB,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detectorLoader.test.d.ts","sourceRoot":"","sources":["../../src/tests/detectorLoader.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { DetectorLoaderFromScript, } from "../detectorLoader.js";
|
|
3
|
+
const SCRIPT = "export default () => ({ token: 'x' });";
|
|
4
|
+
const detector = (() => undefined);
|
|
5
|
+
describe("DetectorLoaderFromScript", () => {
|
|
6
|
+
const created = [];
|
|
7
|
+
const revoked = [];
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
created.length = 0;
|
|
10
|
+
revoked.length = 0;
|
|
11
|
+
let counter = 0;
|
|
12
|
+
URL.createObjectURL = vi.fn(() => {
|
|
13
|
+
const url = `blob:https://example.test/${counter++}`;
|
|
14
|
+
created.push(url);
|
|
15
|
+
return url;
|
|
16
|
+
});
|
|
17
|
+
URL.revokeObjectURL = vi.fn((url) => {
|
|
18
|
+
revoked.push(url);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
vi.restoreAllMocks();
|
|
23
|
+
});
|
|
24
|
+
it("uses a blob URL when the import succeeds", async () => {
|
|
25
|
+
const seen = [];
|
|
26
|
+
const importer = async (url) => {
|
|
27
|
+
seen.push(url);
|
|
28
|
+
return { default: detector };
|
|
29
|
+
};
|
|
30
|
+
await expect(DetectorLoaderFromScript(SCRIPT, importer)).resolves.toBe(detector);
|
|
31
|
+
expect(seen).toHaveLength(1);
|
|
32
|
+
expect(seen[0]).toMatch(/^blob:/);
|
|
33
|
+
expect(revoked).toEqual(created);
|
|
34
|
+
});
|
|
35
|
+
it("falls back to a data URL when the blob import is blocked by CSP", async () => {
|
|
36
|
+
const seen = [];
|
|
37
|
+
const importer = async (url) => {
|
|
38
|
+
seen.push(url);
|
|
39
|
+
if (url.startsWith("blob:")) {
|
|
40
|
+
throw new TypeError("Failed to fetch dynamically imported module");
|
|
41
|
+
}
|
|
42
|
+
return { default: detector };
|
|
43
|
+
};
|
|
44
|
+
await expect(DetectorLoaderFromScript(SCRIPT, importer)).resolves.toBe(detector);
|
|
45
|
+
expect(seen).toHaveLength(2);
|
|
46
|
+
expect(seen[0]).toMatch(/^blob:/);
|
|
47
|
+
expect(seen[1]).toMatch(/^data:text\/javascript;charset=utf-8,/);
|
|
48
|
+
expect(decodeURIComponent(seen[1]?.split(",")[1] ?? "")).toBe(SCRIPT);
|
|
49
|
+
});
|
|
50
|
+
it("revokes the blob URL even when its import fails", async () => {
|
|
51
|
+
const importer = async (url) => {
|
|
52
|
+
if (url.startsWith("blob:"))
|
|
53
|
+
throw new Error("blocked");
|
|
54
|
+
return { default: detector };
|
|
55
|
+
};
|
|
56
|
+
await DetectorLoaderFromScript(SCRIPT, importer);
|
|
57
|
+
expect(revoked).toEqual(created);
|
|
58
|
+
});
|
|
59
|
+
it("rethrows the last error when both schemes are blocked", async () => {
|
|
60
|
+
const importer = async (url) => {
|
|
61
|
+
throw new Error(`blocked: ${url.slice(0, 5)}`);
|
|
62
|
+
};
|
|
63
|
+
await expect(DetectorLoaderFromScript(SCRIPT, importer)).rejects.toThrow("blocked: data:");
|
|
64
|
+
expect(revoked).toEqual(created);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
//# sourceMappingURL=detectorLoader.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detectorLoader.test.js","sourceRoot":"","sources":["../../src/tests/detectorLoader.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prosopo/procaptcha-frictionless",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.16.1",
|
|
4
4
|
"author": "PROSOPO LIMITED <info@prosopo.io>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -30,20 +30,20 @@
|
|
|
30
30
|
},
|
|
31
31
|
"browserslist": ["> 0.5%, last 2 versions, not dead"],
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@prosopo/api": "4.1
|
|
33
|
+
"@prosopo/api": "4.2.1",
|
|
34
34
|
"@prosopo/common": "3.1.54",
|
|
35
35
|
"@prosopo/locale": "3.4.1",
|
|
36
|
-
"@prosopo/procaptcha-common": "2.13.
|
|
37
|
-
"@prosopo/procaptcha-pow": "2.12.
|
|
38
|
-
"@prosopo/procaptcha-puzzle": "2.12.
|
|
39
|
-
"@prosopo/procaptcha-react": "2.10.
|
|
40
|
-
"@prosopo/types": "5.
|
|
36
|
+
"@prosopo/procaptcha-common": "2.13.2",
|
|
37
|
+
"@prosopo/procaptcha-pow": "2.12.2",
|
|
38
|
+
"@prosopo/procaptcha-puzzle": "2.12.2",
|
|
39
|
+
"@prosopo/procaptcha-react": "2.10.3",
|
|
40
|
+
"@prosopo/types": "5.8.1",
|
|
41
41
|
"@prosopo/widget-skeleton": "2.8.7",
|
|
42
42
|
"dotenv": "16.4.5",
|
|
43
43
|
"react": "19.2.8"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@prosopo/config": "3.3.
|
|
46
|
+
"@prosopo/config": "3.3.15",
|
|
47
47
|
"@types/node": "22.10.2",
|
|
48
48
|
"@vitest/coverage-v8": "4.1.11",
|
|
49
49
|
"concurrently": "9.0.1",
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// Copyright 2021-2026 Prosopo (UK) Ltd.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
// Widget for the `authenticated` captcha outcome — no user-facing challenge,
|
|
16
|
+
// just a visible acknowledgement that Web Bot Auth verification succeeded.
|
|
17
|
+
// Mounts once, immediately encodes a ProcaptchaToken with the sessionId as
|
|
18
|
+
// its commitmentId (matching what /client/authenticated/verify decodes) and
|
|
19
|
+
// fires `onHuman`. The badge itself is purely presentational; the token
|
|
20
|
+
// submission happens in the mount effect.
|
|
21
|
+
//
|
|
22
|
+
// The token carries empty signature bags (`{provider: {}, user: {}}`) — the
|
|
23
|
+
// authenticated verify endpoint does not check the token's user or provider
|
|
24
|
+
// signatures because there was no captcha challenge to sign. Only the dApp
|
|
25
|
+
// server's signature on the timestamp is checked at verify time, and that
|
|
26
|
+
// is applied by the dApp on the way to /verify (not by the widget here).
|
|
27
|
+
|
|
28
|
+
import { getDefaultEvents } from "@prosopo/procaptcha-common";
|
|
29
|
+
import {
|
|
30
|
+
type Account,
|
|
31
|
+
ApiParams,
|
|
32
|
+
CaptchaType,
|
|
33
|
+
type ProcaptchaCallbacks,
|
|
34
|
+
type RandomProvider,
|
|
35
|
+
encodeProcaptchaOutput,
|
|
36
|
+
} from "@prosopo/types";
|
|
37
|
+
import { type FC, useEffect, useRef } from "react";
|
|
38
|
+
|
|
39
|
+
export type AuthenticatedBadgeProps = {
|
|
40
|
+
sessionId: string;
|
|
41
|
+
agent?: string;
|
|
42
|
+
dapp: string;
|
|
43
|
+
userAccount: Account;
|
|
44
|
+
provider: RandomProvider;
|
|
45
|
+
callbacks: ProcaptchaCallbacks;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const displayHost = (agent?: string): string => {
|
|
49
|
+
if (!agent) return "unknown";
|
|
50
|
+
try {
|
|
51
|
+
return new URL(agent).hostname;
|
|
52
|
+
} catch {
|
|
53
|
+
return agent;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const AuthenticatedBadge: FC<AuthenticatedBadgeProps> = ({
|
|
58
|
+
sessionId,
|
|
59
|
+
agent,
|
|
60
|
+
dapp,
|
|
61
|
+
userAccount,
|
|
62
|
+
provider,
|
|
63
|
+
callbacks,
|
|
64
|
+
}) => {
|
|
65
|
+
// One-shot: React 18 StrictMode double-invokes effects in development;
|
|
66
|
+
// this guard makes sure the token is emitted exactly once even under
|
|
67
|
+
// double-mount. Production doesn't double-invoke, so this is a
|
|
68
|
+
// belt-and-braces against local-dev confusion.
|
|
69
|
+
const emittedRef = useRef(false);
|
|
70
|
+
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
if (emittedRef.current) return;
|
|
73
|
+
emittedRef.current = true;
|
|
74
|
+
const events = getDefaultEvents(callbacks);
|
|
75
|
+
const token = encodeProcaptchaOutput({
|
|
76
|
+
[ApiParams.providerUrl]: provider.provider.url,
|
|
77
|
+
[ApiParams.user]: userAccount.account.address,
|
|
78
|
+
[ApiParams.dapp]: dapp,
|
|
79
|
+
// Verify endpoint reads commitmentId as the sessionId — reusing
|
|
80
|
+
// the existing slot avoids a token codec bump for this one flow.
|
|
81
|
+
[ApiParams.commitmentId]: sessionId,
|
|
82
|
+
[ApiParams.timestamp]: Date.now().toString(),
|
|
83
|
+
[ApiParams.signature]: {
|
|
84
|
+
[ApiParams.provider]: {},
|
|
85
|
+
[ApiParams.user]: {},
|
|
86
|
+
},
|
|
87
|
+
[ApiParams.captchaType]: CaptchaType.authenticated,
|
|
88
|
+
});
|
|
89
|
+
events.onHuman(token);
|
|
90
|
+
}, [sessionId, dapp, userAccount, provider, callbacks]);
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<div
|
|
94
|
+
style={{
|
|
95
|
+
display: "inline-flex",
|
|
96
|
+
alignItems: "center",
|
|
97
|
+
gap: 8,
|
|
98
|
+
padding: "8px 12px",
|
|
99
|
+
borderRadius: 6,
|
|
100
|
+
background: "#eef2ff",
|
|
101
|
+
border: "1px solid #c7d2fe",
|
|
102
|
+
color: "#3730a3",
|
|
103
|
+
fontFamily:
|
|
104
|
+
"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
|
|
105
|
+
fontSize: 13,
|
|
106
|
+
lineHeight: 1.4,
|
|
107
|
+
}}
|
|
108
|
+
// biome-ignore lint/a11y/useSemanticElements: doesn't make sense
|
|
109
|
+
role="status"
|
|
110
|
+
aria-label="Verified agent"
|
|
111
|
+
>
|
|
112
|
+
<svg
|
|
113
|
+
width="16"
|
|
114
|
+
height="16"
|
|
115
|
+
viewBox="0 0 24 24"
|
|
116
|
+
fill="none"
|
|
117
|
+
stroke="currentColor"
|
|
118
|
+
strokeWidth="2.5"
|
|
119
|
+
strokeLinecap="round"
|
|
120
|
+
strokeLinejoin="round"
|
|
121
|
+
aria-hidden="true"
|
|
122
|
+
>
|
|
123
|
+
<title>Verified</title>
|
|
124
|
+
<path d="M20 6L9 17l-5-5" />
|
|
125
|
+
</svg>
|
|
126
|
+
<span>
|
|
127
|
+
{agent ? (
|
|
128
|
+
<>
|
|
129
|
+
<strong>Verified agent</strong>: {displayHost(agent)}
|
|
130
|
+
</>
|
|
131
|
+
) : (
|
|
132
|
+
// No Signature-Agent URL on the response — the operator's Allow
|
|
133
|
+
// rule matched on a non-Web-Bot-Auth condition (IP CIDR, JA4,
|
|
134
|
+
// UA substring, ASN, country). Fall back to generic copy so
|
|
135
|
+
// the operator isn't misled about which qualifier fired.
|
|
136
|
+
<strong>Trusted request</strong>
|
|
137
|
+
)}
|
|
138
|
+
</span>
|
|
139
|
+
</div>
|
|
140
|
+
);
|
|
141
|
+
};
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
import { darkTheme, lightTheme } from "@prosopo/widget-skeleton";
|
|
34
34
|
import type { KeyboardEvent, MouseEvent, TouchEvent } from "react";
|
|
35
35
|
import { useEffect, useRef, useState } from "react";
|
|
36
|
+
import { AuthenticatedBadge } from "./AuthenticatedBadge.js";
|
|
36
37
|
import customDetectBot from "./customDetectBot.js";
|
|
37
38
|
import { evaluateFrictionlessResult } from "./frictionlessResultGuard.js";
|
|
38
39
|
import {
|
|
@@ -318,7 +319,31 @@ export const ProcaptchaFrictionless = ({
|
|
|
318
319
|
mountCountRef.current += 1;
|
|
319
320
|
const mountKey = mountCountRef.current;
|
|
320
321
|
|
|
321
|
-
if (captchaType === CaptchaType.
|
|
322
|
+
if (captchaType === CaptchaType.authenticated) {
|
|
323
|
+
// Web Bot Auth pre-verified pass-through. No challenge, no
|
|
324
|
+
// interaction — the badge component encodes and fires the token
|
|
325
|
+
// on mount. Skip the loader chain the other branches use because
|
|
326
|
+
// there is no captcha module to lazy-import here.
|
|
327
|
+
if (!frictionlessState.sessionId) {
|
|
328
|
+
events.onError(
|
|
329
|
+
new Error(
|
|
330
|
+
"authenticated captcha response missing sessionId — provider is misbehaving",
|
|
331
|
+
),
|
|
332
|
+
);
|
|
333
|
+
fallOverWithStyle();
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
setComponentToRender(
|
|
337
|
+
<AuthenticatedBadge
|
|
338
|
+
sessionId={frictionlessState.sessionId}
|
|
339
|
+
agent={frictionlessState.agent}
|
|
340
|
+
dapp={config.account.address ?? ""}
|
|
341
|
+
userAccount={frictionlessState.userAccount}
|
|
342
|
+
provider={frictionlessState.provider}
|
|
343
|
+
callbacks={callbacks}
|
|
344
|
+
/>,
|
|
345
|
+
);
|
|
346
|
+
} else if (captchaType === CaptchaType.image) {
|
|
322
347
|
const Procaptcha = await ProcaptchaLoader();
|
|
323
348
|
setComponentToRender(
|
|
324
349
|
<Procaptcha
|
|
@@ -417,6 +442,7 @@ export const ProcaptchaFrictionless = ({
|
|
|
417
442
|
encryptBehavioralData: result.encryptBehavioralData,
|
|
418
443
|
getSimdReadings: result.getSimdReadings,
|
|
419
444
|
hp: result.hp,
|
|
445
|
+
agent: result.agent,
|
|
420
446
|
};
|
|
421
447
|
|
|
422
448
|
await renderForCaptchaType(result.captchaType, frictionlessState);
|
package/src/customDetectBot.ts
CHANGED
|
@@ -297,6 +297,7 @@ const customDetectBot: BotDetectionFunction = async (
|
|
|
297
297
|
userAccount: userAccount,
|
|
298
298
|
error: captcha.error,
|
|
299
299
|
hp: captcha.hp,
|
|
300
|
+
agent: captcha.agent,
|
|
300
301
|
};
|
|
301
302
|
}
|
|
302
303
|
|
|
@@ -357,6 +358,7 @@ const customDetectBot: BotDetectionFunction = async (
|
|
|
357
358
|
userAccount: userAccount,
|
|
358
359
|
error: captcha.error,
|
|
359
360
|
hp: captcha.hp,
|
|
361
|
+
agent: captcha.agent,
|
|
360
362
|
// Map specific trackers to generic behavioral collectors
|
|
361
363
|
behaviorCollector1: detectionResult.mouseTracker,
|
|
362
364
|
behaviorCollector2: detectionResult.touchTracker,
|
package/src/detectorLoader.ts
CHANGED
|
@@ -59,22 +59,62 @@ export type DetectorType = (
|
|
|
59
59
|
userAccount: Account;
|
|
60
60
|
}>;
|
|
61
61
|
|
|
62
|
+
interface LoaderAttempt {
|
|
63
|
+
readonly url: string;
|
|
64
|
+
readonly release: () => void;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const blobAttempt = (script: string): LoaderAttempt => {
|
|
68
|
+
const url = URL.createObjectURL(
|
|
69
|
+
new Blob([script], { type: "text/javascript" }),
|
|
70
|
+
);
|
|
71
|
+
return { url, release: (): void => URL.revokeObjectURL(url) };
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const dataAttempt = (script: string): LoaderAttempt => ({
|
|
75
|
+
url: `data:text/javascript;charset=utf-8,${encodeURIComponent(script)}`,
|
|
76
|
+
release: (): void => undefined,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
/** Injection point for tests; real callers never pass this. */
|
|
80
|
+
export type ModuleImporter = (url: string) => Promise<unknown>;
|
|
81
|
+
|
|
82
|
+
const defaultImporter: ModuleImporter = (url) =>
|
|
83
|
+
import(/* @vite-ignore */ /* webpackIgnore: true */ url);
|
|
84
|
+
|
|
62
85
|
/**
|
|
63
|
-
* Loads a detector from a provider-served obfuscated ESM string (the
|
|
64
|
-
* pool bundle).
|
|
65
|
-
*
|
|
86
|
+
* Loads a detector from a provider-served obfuscated ESM string (the
|
|
87
|
+
* per-session pool bundle). The module is self-contained, so a dynamic
|
|
88
|
+
* `import()` yields its default export.
|
|
89
|
+
*
|
|
90
|
+
* A blob URL is tried first, then a `data:` URL. The two are gated by
|
|
91
|
+
* different CSP directives and sites commonly allow one without the other — a
|
|
92
|
+
* `script-src` of `*` matches neither, and a policy listing `data:` for
|
|
93
|
+
* scripts and `blob:` only for workers blocks the blob path outright. Without
|
|
94
|
+
* the fallback every session on such a site loses the detector, sends an empty
|
|
95
|
+
* token, and can never pass frictionlessly.
|
|
96
|
+
*
|
|
97
|
+
* A blocked attempt logs a CSP violation before the import rejects. That noise
|
|
98
|
+
* is the cost of recovering the session.
|
|
66
99
|
*/
|
|
67
100
|
export const DetectorLoaderFromScript = async (
|
|
68
101
|
script: string,
|
|
102
|
+
importModule: ModuleImporter = defaultImporter,
|
|
69
103
|
): Promise<DetectorType> => {
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
104
|
+
let lastError: unknown = new Error("no loader attempt ran");
|
|
105
|
+
for (const build of [blobAttempt, dataAttempt]) {
|
|
106
|
+
let attempt: LoaderAttempt | undefined;
|
|
107
|
+
try {
|
|
108
|
+
attempt = build(script);
|
|
109
|
+
const mod = (await importModule(attempt.url)) as {
|
|
110
|
+
default: DetectorType;
|
|
111
|
+
};
|
|
112
|
+
return mod.default;
|
|
113
|
+
} catch (err) {
|
|
114
|
+
lastError = err;
|
|
115
|
+
} finally {
|
|
116
|
+
attempt?.release();
|
|
117
|
+
}
|
|
79
118
|
}
|
|
119
|
+
throw lastError;
|
|
80
120
|
};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// Copyright 2021-2026 Prosopo (UK) Ltd.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
// @vitest-environment jsdom
|
|
16
|
+
|
|
17
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
18
|
+
import {
|
|
19
|
+
DetectorLoaderFromScript,
|
|
20
|
+
type DetectorType,
|
|
21
|
+
type ModuleImporter,
|
|
22
|
+
} from "../detectorLoader.js";
|
|
23
|
+
|
|
24
|
+
const SCRIPT = "export default () => ({ token: 'x' });";
|
|
25
|
+
|
|
26
|
+
const detector = (() => undefined) as unknown as DetectorType;
|
|
27
|
+
|
|
28
|
+
describe("DetectorLoaderFromScript", () => {
|
|
29
|
+
const created: string[] = [];
|
|
30
|
+
const revoked: string[] = [];
|
|
31
|
+
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
created.length = 0;
|
|
34
|
+
revoked.length = 0;
|
|
35
|
+
let counter = 0;
|
|
36
|
+
URL.createObjectURL = vi.fn((): string => {
|
|
37
|
+
const url = `blob:https://example.test/${counter++}`;
|
|
38
|
+
created.push(url);
|
|
39
|
+
return url;
|
|
40
|
+
});
|
|
41
|
+
URL.revokeObjectURL = vi.fn((url: string): void => {
|
|
42
|
+
revoked.push(url);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
afterEach(() => {
|
|
47
|
+
vi.restoreAllMocks();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("uses a blob URL when the import succeeds", async () => {
|
|
51
|
+
const seen: string[] = [];
|
|
52
|
+
const importer: ModuleImporter = async (url) => {
|
|
53
|
+
seen.push(url);
|
|
54
|
+
return { default: detector };
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
await expect(DetectorLoaderFromScript(SCRIPT, importer)).resolves.toBe(
|
|
58
|
+
detector,
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
expect(seen).toHaveLength(1);
|
|
62
|
+
expect(seen[0]).toMatch(/^blob:/);
|
|
63
|
+
expect(revoked).toEqual(created);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("falls back to a data URL when the blob import is blocked by CSP", async () => {
|
|
67
|
+
const seen: string[] = [];
|
|
68
|
+
const importer: ModuleImporter = async (url) => {
|
|
69
|
+
seen.push(url);
|
|
70
|
+
if (url.startsWith("blob:")) {
|
|
71
|
+
// What Chrome throws when script-src omits blob:
|
|
72
|
+
throw new TypeError("Failed to fetch dynamically imported module");
|
|
73
|
+
}
|
|
74
|
+
return { default: detector };
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
await expect(DetectorLoaderFromScript(SCRIPT, importer)).resolves.toBe(
|
|
78
|
+
detector,
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
expect(seen).toHaveLength(2);
|
|
82
|
+
expect(seen[0]).toMatch(/^blob:/);
|
|
83
|
+
expect(seen[1]).toMatch(/^data:text\/javascript;charset=utf-8,/);
|
|
84
|
+
expect(decodeURIComponent(seen[1]?.split(",")[1] ?? "")).toBe(SCRIPT);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("revokes the blob URL even when its import fails", async () => {
|
|
88
|
+
const importer: ModuleImporter = async (url) => {
|
|
89
|
+
if (url.startsWith("blob:")) throw new Error("blocked");
|
|
90
|
+
return { default: detector };
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
await DetectorLoaderFromScript(SCRIPT, importer);
|
|
94
|
+
|
|
95
|
+
expect(revoked).toEqual(created);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("rethrows the last error when both schemes are blocked", async () => {
|
|
99
|
+
const importer: ModuleImporter = async (url) => {
|
|
100
|
+
throw new Error(`blocked: ${url.slice(0, 5)}`);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
await expect(DetectorLoaderFromScript(SCRIPT, importer)).rejects.toThrow(
|
|
104
|
+
"blocked: data:",
|
|
105
|
+
);
|
|
106
|
+
expect(revoked).toEqual(created);
|
|
107
|
+
});
|
|
108
|
+
});
|