@prosopo/procaptcha-frictionless 2.12.8 → 2.12.11
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 +3 -3
- package/.turbo/turbo-build$colon$tsc.log +25 -25
- package/.turbo/turbo-build.log +4 -4
- package/CHANGELOG.md +52 -0
- package/dist/cjs/customDetectBot.cjs +32 -7
- package/dist/customDetectBot.d.ts.map +1 -1
- package/dist/customDetectBot.js +32 -7
- package/dist/customDetectBot.js.map +1 -1
- package/package.json +9 -9
- package/src/customDetectBot.ts +69 -14
- package/src/tests/customDetectBotSimd.test.ts +1 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/procaptcha-frictionless@2.12.
|
|
2
|
+
> @prosopo/procaptcha-frictionless@2.12.11 build:cjs
|
|
3
3
|
> NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV
|
|
4
4
|
|
|
5
5
|
ViteCommonJSConfig: .
|
|
@@ -61,6 +61,6 @@ rendering chunks...
|
|
|
61
61
|
[2mdist/cjs/[22m[36mindex.cjs [39m[1m[2m0.24 kB[22m[1m[22m
|
|
62
62
|
[2mdist/cjs/[22m[36msessionInvalidatedRecovery.cjs [39m[1m[2m0.85 kB[22m[1m[22m
|
|
63
63
|
[2mdist/cjs/[22m[36mdetectorLoader.cjs [39m[1m[2m1.37 kB[22m[1m[22m
|
|
64
|
-
[2mdist/cjs/[22m[36mcustomDetectBot.cjs [39m[1m[
|
|
64
|
+
[2mdist/cjs/[22m[36mcustomDetectBot.cjs [39m[1m[2m4.26 kB[22m[1m[22m
|
|
65
65
|
[2mdist/cjs/[22m[36mProcaptchaFrictionless.cjs [39m[1m[2m9.11 kB[22m[1m[22m
|
|
66
|
-
[32m✓ built in
|
|
66
|
+
[32m✓ built in 86ms[39m
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/procaptcha-frictionless@2.12.
|
|
2
|
+
> @prosopo/procaptcha-frictionless@2.12.11 build:tsc
|
|
3
3
|
> tsc --build --verbose
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
10:35:14 AM - Projects in this build:
|
|
6
6
|
* ../../dev/config/tsconfig.json
|
|
7
7
|
* ../locale/tsconfig.json
|
|
8
8
|
* ../util/tsconfig.json
|
|
@@ -26,49 +26,49 @@
|
|
|
26
26
|
* ../procaptcha-react/tsconfig.json
|
|
27
27
|
* tsconfig.json
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
10:35:14 AM - Project '../../dev/config/tsconfig.json' is up to date because newest input '../../dev/config/src/webpack/webpack.config.ts' is older than output '../../dev/config/tsconfig.tsbuildinfo'
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
10:35:14 AM - Project '../locale/tsconfig.json' is up to date because newest input '../locale/src/translationKey.ts' is older than output '../locale/tsconfig.tsbuildinfo'
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
10:35:14 AM - Project '../util/tsconfig.json' is up to date because newest input '../util/src/url.ts' is older than output '../util/tsconfig.tsbuildinfo'
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
10:35:14 AM - Project '../util-crypto/tsconfig.json' is up to date because newest input '../util-crypto/src/types.ts' is older than output '../util-crypto/tsconfig.tsbuildinfo'
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
10:35:14 AM - Project '../types/tsconfig.json' is up to date because newest input '../types/src/provider/api.ts' is older than output '../types/tsconfig.tsbuildinfo'
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
10:35:14 AM - Project '../detector/tsconfig.json' is up to date because newest input '../detector/src/index.js' is older than output '../detector/tsconfig.tsbuildinfo'
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
10:35:14 AM - Project '../api/tsconfig.json' is up to date because newest input '../api/src/index.ts' is older than output '../api/tsconfig.tsbuildinfo'
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
10:35:14 AM - Project '../logger/tsconfig.json' is up to date because newest input '../logger/src/index.ts' is older than output '../logger/tsconfig.tsbuildinfo'
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
10:35:14 AM - Project '../common/tsconfig.json' is up to date because newest input '../common/src/error.ts' is older than output '../common/tsconfig.tsbuildinfo'
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
10:35:14 AM - Project '../fingerprintjs/tsconfig.json' is up to date because newest input '../fingerprintjs/src/utils/browser.ts' is older than output '../fingerprintjs/tsconfig.tsbuildinfo'
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
10:35:14 AM - Project '../fingerprint/tsconfig.json' is up to date because newest input '../fingerprint/src/index.ts' is older than output '../fingerprint/tsconfig.tsbuildinfo'
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
10:35:14 AM - Project '../load-balancer/tsconfig.json' is up to date because newest input '../load-balancer/src/balancer.ts' is older than output '../load-balancer/tsconfig.tsbuildinfo'
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
10:35:15 AM - Project '../widget-skeleton/tsconfig.json' is up to date because newest input '../widget-skeleton/src/constants.ts' is older than output '../widget-skeleton/tsconfig.tsbuildinfo'
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
10:35:15 AM - Project '../keyring/tsconfig.json' is up to date because newest input '../keyring/src/index.ts' is older than output '../keyring/tsconfig.tsbuildinfo'
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
10:35:15 AM - Project '../account/tsconfig.json' is up to date because newest input '../account/src/workers/cryptoWorker.ts' is older than output '../account/tsconfig.tsbuildinfo'
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
10:35:15 AM - Project '../procaptcha-common/tsconfig.json' is up to date because newest input '../procaptcha-common/src/tests/defaultEvents.test.ts' is older than output '../procaptcha-common/tsconfig.tsbuildinfo'
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
10:35:15 AM - Project '../procaptcha-pow/tsconfig.json' is up to date because newest input '../procaptcha-pow/src/index.ts' is older than output '../procaptcha-pow/tsconfig.tsbuildinfo'
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
10:35:15 AM - Project '../procaptcha-puzzle/tsconfig.json' is up to date because newest input '../procaptcha-puzzle/src/index.ts' is older than output '../procaptcha-puzzle/tsconfig.tsbuildinfo'
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
10:35:15 AM - Project '../datasets/tsconfig.json' is up to date because newest input '../datasets/src/index.ts' is older than output '../datasets/tsconfig.tsbuildinfo'
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
10:35:15 AM - Project '../procaptcha/tsconfig.json' is up to date because newest input '../procaptcha/src/index.ts' is older than output '../procaptcha/tsconfig.tsbuildinfo'
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
10:35:15 AM - Project '../procaptcha-react/tsconfig.json' is up to date because newest input '../procaptcha-react/src/index.ts' is older than output '../procaptcha-react/tsconfig.tsbuildinfo'
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
10:35:15 AM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
10:35:15 AM - Building project '/home/runner/work/captcha/captcha/packages/procaptcha-frictionless/tsconfig.json'...
|
|
74
74
|
|
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/procaptcha-frictionless@2.12.
|
|
2
|
+
> @prosopo/procaptcha-frictionless@2.12.11 build
|
|
3
3
|
> npm run build:cross-env -- --mode ${NODE_ENV:-development}
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
> @prosopo/procaptcha-frictionless@2.12.
|
|
6
|
+
> @prosopo/procaptcha-frictionless@2.12.11 build:cross-env
|
|
7
7
|
> vite build --config vite.esm.config.ts --mode production
|
|
8
8
|
|
|
9
9
|
ViteEsmConfig: .
|
|
@@ -64,6 +64,6 @@ rendering chunks...
|
|
|
64
64
|
[2mdist/[22m[36mindex.js [39m[1m[2m0.11 kB[22m[1m[22m
|
|
65
65
|
[2mdist/[22m[36mdetectorLoader.js [39m[1m[2m0.11 kB[22m[1m[22m
|
|
66
66
|
[2mdist/[22m[36msessionInvalidatedRecovery.js [39m[1m[2m0.71 kB[22m[1m[22m
|
|
67
|
-
[2mdist/[22m[36mcustomDetectBot.js [39m[1m[
|
|
67
|
+
[2mdist/[22m[36mcustomDetectBot.js [39m[1m[2m4.08 kB[22m[1m[22m
|
|
68
68
|
[2mdist/[22m[36mProcaptchaFrictionless.js [39m[1m[2m7.67 kB[22m[1m[22m
|
|
69
|
-
[32m✓ built in
|
|
69
|
+
[32m✓ built in 146ms[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,57 @@
|
|
|
1
1
|
# @prosopo/procaptcha-frictionless
|
|
2
2
|
|
|
3
|
+
## 2.12.11
|
|
4
|
+
### Patch Changes
|
|
5
|
+
|
|
6
|
+
- 85e8857: Record both the top-frame URL and the widget's own iframe URL on frictionless sessions.
|
|
7
|
+
|
|
8
|
+
Previously the client only sent one field (`currentUrl`), which for embedded widgets resolved to the top-frame URL — so we lost visibility into which iframe endpoint the session was actually loaded through. Now the client sends both:
|
|
9
|
+
|
|
10
|
+
- `currentUrl`: the top-frame URL (same resolution rules as before — same-origin iframes read `window.top.location.href` directly; cross-origin iframes fall back to `document.referrer`).
|
|
11
|
+
- `iframeUrl`: the widget's own frame URL when embedded. Undefined when the widget IS the top frame (nothing to distinguish).
|
|
12
|
+
|
|
13
|
+
Both fields are sanitised client- and server-side (origin + path only; query string, fragment and any embedded credentials stripped). The provider persists both on the `Session` record and re-uses them on post-PoW escalation sessions. Only `currentUrl` is gated in the frictionless decision machine (unchanged — missing `currentUrl` still forces an image captcha); `iframeUrl` is recorded for analytics.
|
|
14
|
+
|
|
15
|
+
Both fields are also surfaced to the decision machines as raw signals: `RoutingMachineRawSignals` gains an optional `iframeUrl` populated from the freshly decrypted frictionless payload on the `route` phase, from the persisted Session record on the `postPow` phase, and from the cached Session in the dedup replay path — matching how `currentUrl` is already threaded through.
|
|
16
|
+
|
|
17
|
+
Additionally, sessions carry a new computed boolean `isProtect`, set at session-creation time when the widget iframe was served from `protect.<tenant>` and embedded in a page on the same tenant (subdomain-of matching, dot-boundary safe — see `isProtectDeployment` in `@prosopo/util`). Persisted only when true (same pattern as `isEscalation`) and backed by a sparse `{isProtect, createdAt}` index so analytics can cheaply retrieve Protect sessions without re-parsing URLs. Post-PoW escalation sessions inherit the flag from the origin session.
|
|
18
|
+
- Updated dependencies [85e8857]
|
|
19
|
+
- @prosopo/api@3.5.15
|
|
20
|
+
- @prosopo/types@4.9.8
|
|
21
|
+
- @prosopo/procaptcha-pow@2.10.15
|
|
22
|
+
- @prosopo/procaptcha-puzzle@2.10.30
|
|
23
|
+
- @prosopo/common@3.1.44
|
|
24
|
+
- @prosopo/detector@3.5.9
|
|
25
|
+
- @prosopo/procaptcha-common@2.11.9
|
|
26
|
+
- @prosopo/procaptcha-react@2.9.88
|
|
27
|
+
|
|
28
|
+
## 2.12.10
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- Updated dependencies [8bde5df]
|
|
32
|
+
- @prosopo/types@4.9.7
|
|
33
|
+
- @prosopo/api@3.5.14
|
|
34
|
+
- @prosopo/detector@3.5.8
|
|
35
|
+
- @prosopo/procaptcha-common@2.11.8
|
|
36
|
+
- @prosopo/procaptcha-pow@2.10.14
|
|
37
|
+
- @prosopo/procaptcha-puzzle@2.10.29
|
|
38
|
+
- @prosopo/procaptcha-react@2.9.87
|
|
39
|
+
|
|
40
|
+
## 2.12.9
|
|
41
|
+
### Patch Changes
|
|
42
|
+
|
|
43
|
+
- 35d2784: Report the top-frame URL as `currentUrl` when the widget runs inside an iframe.
|
|
44
|
+
|
|
45
|
+
Previously the frictionless client always sent `window.location.origin + pathname`, which is the iframe's own URL — so every session loaded through Protect's site-wide iframe (`protect.<tenant>.live/...`) reported the same widget endpoint regardless of which page the user was actually on. Downstream detectors (HEAD_HASH_OUTLIER's proxy-pool signal in particular) then saw diverse-geography traffic on one URL+UA fingerprint and treated our own iframe as a bot cluster.
|
|
46
|
+
|
|
47
|
+
Resolution order for `currentUrl`:
|
|
48
|
+
1. Top window → local `location.href` (widget is the top frame).
|
|
49
|
+
2. Same-origin iframe → `window.top.location.href`.
|
|
50
|
+
3. Cross-origin iframe → `document.referrer` (browser fills it subject to Referrer-Policy).
|
|
51
|
+
4. Fallback → the iframe's own `location.href` so the field is never empty.
|
|
52
|
+
|
|
53
|
+
Origin+path sanitisation is preserved across all paths — the query string, fragment and any embedded credentials are still stripped before the URL leaves the browser.
|
|
54
|
+
|
|
3
55
|
## 2.12.8
|
|
4
56
|
### Patch Changes
|
|
5
57
|
|
|
@@ -4,15 +4,38 @@ const api = require("@prosopo/api");
|
|
|
4
4
|
const common = require("@prosopo/common");
|
|
5
5
|
const procaptchaCommon = require("@prosopo/procaptcha-common");
|
|
6
6
|
const detectorLoader = require("./detectorLoader.cjs");
|
|
7
|
-
const
|
|
8
|
-
|
|
7
|
+
const sanitiseHref = (href) => {
|
|
8
|
+
try {
|
|
9
|
+
const u = new URL(href);
|
|
10
|
+
if (!u.origin || u.origin === "null") return void 0;
|
|
11
|
+
return `${u.origin}${u.pathname || ""}`;
|
|
12
|
+
} catch {
|
|
9
13
|
return void 0;
|
|
10
14
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
};
|
|
16
|
+
const getCurrentPageUrls = () => {
|
|
17
|
+
if (typeof window === "undefined" || !window.location) {
|
|
18
|
+
return { currentUrl: void 0, iframeUrl: void 0 };
|
|
19
|
+
}
|
|
20
|
+
const local = (() => {
|
|
21
|
+
const { origin, pathname } = window.location;
|
|
22
|
+
if (!origin || origin === "null") return void 0;
|
|
23
|
+
return `${origin}${pathname || ""}`;
|
|
24
|
+
})();
|
|
25
|
+
if (window === window.top) {
|
|
26
|
+
return { currentUrl: local, iframeUrl: void 0 };
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const topHref = window.top?.location?.href;
|
|
30
|
+
const sanitised = topHref ? sanitiseHref(topHref) : void 0;
|
|
31
|
+
if (sanitised) return { currentUrl: sanitised, iframeUrl: local };
|
|
32
|
+
} catch {
|
|
33
|
+
}
|
|
34
|
+
if (typeof document !== "undefined" && document.referrer) {
|
|
35
|
+
const fromReferrer = sanitiseHref(document.referrer);
|
|
36
|
+
if (fromReferrer) return { currentUrl: fromReferrer, iframeUrl: local };
|
|
14
37
|
}
|
|
15
|
-
return
|
|
38
|
+
return { currentUrl: local, iframeUrl: local };
|
|
16
39
|
};
|
|
17
40
|
const withTimeout = async (promise, ms) => {
|
|
18
41
|
let timeoutId;
|
|
@@ -60,6 +83,7 @@ const customDetectBot = async (config, container, restartFn, retryContext) => {
|
|
|
60
83
|
provider.provider.url,
|
|
61
84
|
config.account.address
|
|
62
85
|
);
|
|
86
|
+
const { currentUrl, iframeUrl } = getCurrentPageUrls();
|
|
63
87
|
const captchaPromise = providerApi.getFrictionlessCaptcha(
|
|
64
88
|
detectionResult.token,
|
|
65
89
|
detectionResult.encryptHeadHash,
|
|
@@ -67,7 +91,8 @@ const customDetectBot = async (config, container, restartFn, retryContext) => {
|
|
|
67
91
|
userAccount.account.address,
|
|
68
92
|
config.mode,
|
|
69
93
|
void 0,
|
|
70
|
-
|
|
94
|
+
currentUrl,
|
|
95
|
+
iframeUrl
|
|
71
96
|
);
|
|
72
97
|
if (detectionResult.getSimdReadings) {
|
|
73
98
|
void detectionResult.getSimdReadings(6e4).catch(() => void 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"customDetectBot.d.ts","sourceRoot":"","sources":["../src/customDetectBot.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EACX,oBAAoB,EAGpB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"customDetectBot.d.ts","sourceRoot":"","sources":["../src/customDetectBot.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EACX,oBAAoB,EAGpB,MAAM,gBAAgB,CAAC;AA2ExB,eAAO,MAAM,WAAW,GAAU,CAAC,WACzB,OAAO,CAAC,CAAC,CAAC,MACf,MAAM,KACR,OAAO,CAAC,CAAC,CAoBX,CAAC;AAEF,QAAA,MAAM,eAAe,EAAE,oBA0GtB,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
package/dist/customDetectBot.js
CHANGED
|
@@ -2,15 +2,38 @@ import { ProviderApi } from "@prosopo/api";
|
|
|
2
2
|
import { ProsopoEnvError } from "@prosopo/common";
|
|
3
3
|
import { ExtensionLoader, getProcaptchaRandomActiveProvider, pickIpMode } from "@prosopo/procaptcha-common";
|
|
4
4
|
import { DetectorLoader } from "./detectorLoader.js";
|
|
5
|
-
const
|
|
6
|
-
|
|
5
|
+
const sanitiseHref = (href) => {
|
|
6
|
+
try {
|
|
7
|
+
const u = new URL(href);
|
|
8
|
+
if (!u.origin || u.origin === "null") return void 0;
|
|
9
|
+
return `${u.origin}${u.pathname || ""}`;
|
|
10
|
+
} catch {
|
|
7
11
|
return void 0;
|
|
8
12
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
13
|
+
};
|
|
14
|
+
const getCurrentPageUrls = () => {
|
|
15
|
+
if (typeof window === "undefined" || !window.location) {
|
|
16
|
+
return { currentUrl: void 0, iframeUrl: void 0 };
|
|
17
|
+
}
|
|
18
|
+
const local = (() => {
|
|
19
|
+
const { origin, pathname } = window.location;
|
|
20
|
+
if (!origin || origin === "null") return void 0;
|
|
21
|
+
return `${origin}${pathname || ""}`;
|
|
22
|
+
})();
|
|
23
|
+
if (window === window.top) {
|
|
24
|
+
return { currentUrl: local, iframeUrl: void 0 };
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const topHref = window.top?.location?.href;
|
|
28
|
+
const sanitised = topHref ? sanitiseHref(topHref) : void 0;
|
|
29
|
+
if (sanitised) return { currentUrl: sanitised, iframeUrl: local };
|
|
30
|
+
} catch {
|
|
31
|
+
}
|
|
32
|
+
if (typeof document !== "undefined" && document.referrer) {
|
|
33
|
+
const fromReferrer = sanitiseHref(document.referrer);
|
|
34
|
+
if (fromReferrer) return { currentUrl: fromReferrer, iframeUrl: local };
|
|
12
35
|
}
|
|
13
|
-
return
|
|
36
|
+
return { currentUrl: local, iframeUrl: local };
|
|
14
37
|
};
|
|
15
38
|
const withTimeout = async (promise, ms) => {
|
|
16
39
|
let timeoutId;
|
|
@@ -58,6 +81,7 @@ const customDetectBot = async (config, container, restartFn, retryContext) => {
|
|
|
58
81
|
provider.provider.url,
|
|
59
82
|
config.account.address
|
|
60
83
|
);
|
|
84
|
+
const { currentUrl, iframeUrl } = getCurrentPageUrls();
|
|
61
85
|
const captchaPromise = providerApi.getFrictionlessCaptcha(
|
|
62
86
|
detectionResult.token,
|
|
63
87
|
detectionResult.encryptHeadHash,
|
|
@@ -65,7 +89,8 @@ const customDetectBot = async (config, container, restartFn, retryContext) => {
|
|
|
65
89
|
userAccount.account.address,
|
|
66
90
|
config.mode,
|
|
67
91
|
void 0,
|
|
68
|
-
|
|
92
|
+
currentUrl,
|
|
93
|
+
iframeUrl
|
|
69
94
|
);
|
|
70
95
|
if (detectionResult.getSimdReadings) {
|
|
71
96
|
void detectionResult.getSimdReadings(6e4).catch(() => void 0);
|
|
@@ -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,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"customDetectBot.js","sourceRoot":"","sources":["../src/customDetectBot.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.12.
|
|
3
|
+
"version": "2.12.11",
|
|
4
4
|
"author": "PROSOPO LIMITED <info@prosopo.io>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -30,15 +30,15 @@
|
|
|
30
30
|
},
|
|
31
31
|
"browserslist": ["> 0.5%, last 2 versions, not dead"],
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@prosopo/api": "3.5.
|
|
34
|
-
"@prosopo/common": "3.1.
|
|
35
|
-
"@prosopo/detector": "3.5.
|
|
33
|
+
"@prosopo/api": "3.5.15",
|
|
34
|
+
"@prosopo/common": "3.1.44",
|
|
35
|
+
"@prosopo/detector": "3.5.9",
|
|
36
36
|
"@prosopo/locale": "3.2.6",
|
|
37
|
-
"@prosopo/procaptcha-common": "2.11.
|
|
38
|
-
"@prosopo/procaptcha-pow": "2.10.
|
|
39
|
-
"@prosopo/procaptcha-puzzle": "2.10.
|
|
40
|
-
"@prosopo/procaptcha-react": "2.9.
|
|
41
|
-
"@prosopo/types": "4.9.
|
|
37
|
+
"@prosopo/procaptcha-common": "2.11.9",
|
|
38
|
+
"@prosopo/procaptcha-pow": "2.10.15",
|
|
39
|
+
"@prosopo/procaptcha-puzzle": "2.10.30",
|
|
40
|
+
"@prosopo/procaptcha-react": "2.9.88",
|
|
41
|
+
"@prosopo/types": "4.9.8",
|
|
42
42
|
"@prosopo/widget-skeleton": "2.8.4",
|
|
43
43
|
"dotenv": "16.4.5",
|
|
44
44
|
"react": "18.3.1"
|
package/src/customDetectBot.ts
CHANGED
|
@@ -27,22 +27,75 @@ import type {
|
|
|
27
27
|
import type { BotDetectionFunctionResult } from "@prosopo/types";
|
|
28
28
|
import { DetectorLoader } from "./detectorLoader.js";
|
|
29
29
|
|
|
30
|
-
// The page the widget is rendered on, reduced to origin + path.
|
|
31
|
-
// built from `origin` + `pathname` (never `href`) so the query
|
|
32
|
-
// fragment, and any embedded `user:pass@` credentials never leave the
|
|
33
|
-
// — sites routinely carry tokens / session ids / reset codes in those
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
|
|
38
|
-
|
|
30
|
+
// The page(s) the widget is rendered on, reduced to origin + path.
|
|
31
|
+
// Deliberately built from `origin` + `pathname` (never `href`) so the query
|
|
32
|
+
// string, fragment, and any embedded `user:pass@` credentials never leave the
|
|
33
|
+
// browser — sites routinely carry tokens / session ids / reset codes in those
|
|
34
|
+
// parts.
|
|
35
|
+
//
|
|
36
|
+
// Returns two fields:
|
|
37
|
+
// - `currentUrl`: the top-frame URL as best we can determine it. Same-origin
|
|
38
|
+
// iframes read it directly; cross-origin iframes fall back to
|
|
39
|
+
// `document.referrer`, which the browser fills with the embedding page URL
|
|
40
|
+
// subject to Referrer-Policy. When neither is available the field falls
|
|
41
|
+
// back to the local (iframe) URL so the provider still sees a value.
|
|
42
|
+
// - `iframeUrl`: the widget's own frame URL when we're embedded. Undefined
|
|
43
|
+
// when the widget IS the top frame — nothing to distinguish. Emitted so
|
|
44
|
+
// downstream analytics can separate "Protect's site-wide iframe endpoint"
|
|
45
|
+
// from "the page the user was actually on".
|
|
46
|
+
//
|
|
47
|
+
// Both fields are undefined in non-browser contexts (SSR / tests) or for
|
|
48
|
+
// opaque origins.
|
|
49
|
+
const sanitiseHref = (href: string): string | undefined => {
|
|
50
|
+
try {
|
|
51
|
+
const u = new URL(href);
|
|
52
|
+
if (!u.origin || u.origin === "null") return undefined;
|
|
53
|
+
return `${u.origin}${u.pathname || ""}`;
|
|
54
|
+
} catch {
|
|
39
55
|
return undefined;
|
|
40
56
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
type PageUrls = {
|
|
60
|
+
currentUrl: string | undefined;
|
|
61
|
+
iframeUrl: string | undefined;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const getCurrentPageUrls = (): PageUrls => {
|
|
65
|
+
if (typeof window === "undefined" || !window.location) {
|
|
66
|
+
return { currentUrl: undefined, iframeUrl: undefined };
|
|
67
|
+
}
|
|
68
|
+
const local = (() => {
|
|
69
|
+
const { origin, pathname } = window.location;
|
|
70
|
+
if (!origin || origin === "null") return undefined;
|
|
71
|
+
return `${origin}${pathname || ""}`;
|
|
72
|
+
})();
|
|
73
|
+
|
|
74
|
+
// Top window — no iframe distinction, report the local URL only.
|
|
75
|
+
if (window === window.top) {
|
|
76
|
+
return { currentUrl: local, iframeUrl: undefined };
|
|
44
77
|
}
|
|
45
|
-
|
|
78
|
+
|
|
79
|
+
// Same-origin iframe — read the top URL directly.
|
|
80
|
+
try {
|
|
81
|
+
const topHref = window.top?.location?.href;
|
|
82
|
+
const sanitised = topHref ? sanitiseHref(topHref) : undefined;
|
|
83
|
+
if (sanitised) return { currentUrl: sanitised, iframeUrl: local };
|
|
84
|
+
} catch {
|
|
85
|
+
/* cross-origin — fall through */
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Cross-origin iframe — the embedding page URL comes via referrer,
|
|
89
|
+
// subject to the parent's Referrer-Policy header.
|
|
90
|
+
if (typeof document !== "undefined" && document.referrer) {
|
|
91
|
+
const fromReferrer = sanitiseHref(document.referrer);
|
|
92
|
+
if (fromReferrer) return { currentUrl: fromReferrer, iframeUrl: local };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Referrer unavailable — fall back to the iframe URL for `currentUrl` so
|
|
96
|
+
// the provider still sees a value, and echo it as `iframeUrl` so
|
|
97
|
+
// downstream can tell the top frame was not observed.
|
|
98
|
+
return { currentUrl: local, iframeUrl: local };
|
|
46
99
|
};
|
|
47
100
|
|
|
48
101
|
export const withTimeout = async <T>(
|
|
@@ -125,6 +178,7 @@ const customDetectBot: BotDetectionFunction = async (
|
|
|
125
178
|
// lets it complete in the worker thread while the network round-trip
|
|
126
179
|
// burns. Readings still attach on the challenge GET and on solution
|
|
127
180
|
// submit (first-hop-wins server-side).
|
|
181
|
+
const { currentUrl, iframeUrl } = getCurrentPageUrls();
|
|
128
182
|
const captchaPromise = providerApi.getFrictionlessCaptcha(
|
|
129
183
|
detectionResult.token,
|
|
130
184
|
detectionResult.encryptHeadHash,
|
|
@@ -132,7 +186,8 @@ const customDetectBot: BotDetectionFunction = async (
|
|
|
132
186
|
userAccount.account.address,
|
|
133
187
|
config.mode,
|
|
134
188
|
undefined,
|
|
135
|
-
|
|
189
|
+
currentUrl,
|
|
190
|
+
iframeUrl,
|
|
136
191
|
);
|
|
137
192
|
if (detectionResult.getSimdReadings) {
|
|
138
193
|
// Fire-and-forget: triggers the memoised prefetch inside the catcher
|
|
@@ -93,7 +93,7 @@ describe("customDetectBot SIMD deferral", () => {
|
|
|
93
93
|
|
|
94
94
|
expect(mocks.getFrictionlessCaptcha).toHaveBeenCalledTimes(1);
|
|
95
95
|
const args = mocks.getFrictionlessCaptcha.mock.calls[0];
|
|
96
|
-
// args: token, headHash, dappAccount, userAccount, mode, simdReadings, currentUrl
|
|
96
|
+
// args: token, headHash, dappAccount, userAccount, mode, simdReadings, currentUrl, iframeUrl
|
|
97
97
|
expect(args?.[5]).toBeUndefined();
|
|
98
98
|
});
|
|
99
99
|
|