@prosopo/procaptcha-bundle 4.1.61 → 4.2.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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @prosopo/procaptcha-bundle@4.1.61 build:cjs
2
+ > @prosopo/procaptcha-bundle@4.2.1 build:cjs
3
3
  > NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV
4
4
 
5
5
  ViteCommonJSConfig: .
@@ -57,7 +57,7 @@ ViteCommonJSConfig: .
57
57
  vite v8.1.5 building ssr environment for production...
58
58
  Bundle build started
59
59
  
60
- 10 modules transformed.
60
+ 11 modules transformed.
61
61
  rendering chunks...
62
62
  computing gzip size...
63
63
  dist/cjs/util/widgetThemeResolver.cjs 0.57 kB │ gzip: 0.29 kB
@@ -66,11 +66,12 @@ dist/cjs/util/config.cjs 0.66 kB │ gzip: 0.33 kB
66
66
  dist/cjs/util/captcha/components/bundleCaptcha.cjs 0.82 kB │ gzip: 0.39 kB
67
67
  dist/cjs/util/configCreator.cjs 0.88 kB │ gzip: 0.46 kB
68
68
  dist/cjs/_virtual/_rolldown/runtime.cjs 1.00 kB │ gzip: 0.50 kB
69
+ dist/cjs/util/clientSession.cjs 1.08 kB │ gzip: 0.56 kB
69
70
  dist/cjs/util/language.cjs 1.08 kB │ gzip: 0.45 kB
70
- dist/cjs/util/captcha/captchaRenderer.cjs 2.26 kB │ gzip: 0.78 kB
71
+ dist/cjs/util/captcha/captchaRenderer.cjs 2.40 kB │ gzip: 0.80 kB
71
72
  dist/cjs/util/widgetFactory.cjs 2.73 kB │ gzip: 0.89 kB
72
73
  dist/cjs/index.cjs 9.20 kB │ gzip: 3.22 kB
73
74
 
74
75
  [MIXED_EXPORTS] Entry module "src/index.ts" is using named (including "default", "execute", "remove", "render", "reset") and default exports together. Consumers of your bundle will have to use `..default` to access the default export, which may not be what you want. Use `output.exports: "named"` to disable this warning.
75
76
  
76
- ✓ built in 52ms
77
+ ✓ built in 44ms
@@ -1,8 +1,8 @@
1
1
 
2
- > @prosopo/procaptcha-bundle@4.1.61 build:tsc
2
+ > @prosopo/procaptcha-bundle@4.2.1 build:tsc
3
3
  > tsc --build --verbose
4
4
 
5
- 12:32:51 PM - Projects in this build:
5
+ 6:42:56 PM - Projects in this build:
6
6
  * ../../dev/config/tsconfig.json
7
7
  * ../util/tsconfig.json
8
8
  * ../logger/tsconfig.json
@@ -27,51 +27,51 @@
27
27
  * ../procaptcha-frictionless/tsconfig.json
28
28
  * tsconfig.json
29
29
 
30
- 12:32:51 PM - 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
+ 6:42:56 PM - 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'
31
31
 
32
- 12:32:51 PM - Project '../util/tsconfig.json' is up to date because newest input '../util/src/url.ts' is older than output '../util/tsconfig.tsbuildinfo'
32
+ 6:42:56 PM - Project '../util/tsconfig.json' is up to date because newest input '../util/src/url.ts' is older than output '../util/tsconfig.tsbuildinfo'
33
33
 
34
- 12:32:51 PM - Project '../logger/tsconfig.json' is up to date because newest input '../logger/src/tests/loggerBrowser.unit.test.ts' is older than output '../logger/tsconfig.tsbuildinfo'
34
+ 6:42:56 PM - Project '../logger/tsconfig.json' is up to date because newest input '../logger/src/index.ts' is older than output '../logger/tsconfig.tsbuildinfo'
35
35
 
36
- 12:32:51 PM - Project '../dotenv/tsconfig.json' is up to date because newest input '../dotenv/src/env.ts' is older than output '../dotenv/tsconfig.tsbuildinfo'
36
+ 6:42:56 PM - Project '../dotenv/tsconfig.json' is up to date because newest input '../dotenv/src/env.ts' is older than output '../dotenv/tsconfig.tsbuildinfo'
37
37
 
38
- 12:32:51 PM - Project '../locale/tsconfig.json' is up to date because newest input '../locale/src/translationKey.ts' is older than output '../locale/tsconfig.tsbuildinfo'
38
+ 6:42:56 PM - Project '../locale/tsconfig.json' is up to date because newest input '../locale/src/translationKey.ts' is older than output '../locale/tsconfig.tsbuildinfo'
39
39
 
40
- 12:32:51 PM - 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'
40
+ 6:42:56 PM - 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'
41
41
 
42
- 12:32:51 PM - Project '../types/tsconfig.json' is up to date because newest input '../types/src/types.test-d.ts' is older than output '../types/tsconfig.tsbuildinfo'
42
+ 6:42:56 PM - Project '../types/tsconfig.json' is up to date because newest input '../types/src/types.test-d.ts' is older than output '../types/tsconfig.tsbuildinfo'
43
43
 
44
- 12:32:51 PM - Project '../api/tsconfig.json' is up to date because newest input '../api/src/index.ts' is older than output '../api/tsconfig.tsbuildinfo'
44
+ 6:42:56 PM - Project '../api/tsconfig.json' is up to date because newest input '../api/src/index.ts' is older than output '../api/tsconfig.tsbuildinfo'
45
45
 
46
- 12:32:51 PM - Project '../common/tsconfig.json' is up to date because newest input '../common/src/tests/utils/objectUtils.unit.test.ts' is older than output '../common/tsconfig.tsbuildinfo'
46
+ 6:42:56 PM - Project '../common/tsconfig.json' is up to date because newest input '../common/src/error.ts' is older than output '../common/tsconfig.tsbuildinfo'
47
47
 
48
- 12:32:51 PM - Project '../fingerprintjs/tsconfig.json' is up to date because newest input '../fingerprintjs/src/utils/browser.ts' is older than output '../fingerprintjs/tsconfig.tsbuildinfo'
48
+ 6:42:56 PM - Project '../fingerprintjs/tsconfig.json' is up to date because newest input '../fingerprintjs/src/utils/browser.ts' is older than output '../fingerprintjs/tsconfig.tsbuildinfo'
49
49
 
50
- 12:32:51 PM - Project '../fingerprint/tsconfig.json' is up to date because newest input '../fingerprint/src/index.ts' is older than output '../fingerprint/tsconfig.tsbuildinfo'
50
+ 6:42:56 PM - Project '../fingerprint/tsconfig.json' is up to date because newest input '../fingerprint/src/index.ts' is older than output '../fingerprint/tsconfig.tsbuildinfo'
51
51
 
52
- 12:32:51 PM - Project '../load-balancer/tsconfig.json' is up to date because newest input '../load-balancer/src/tests/providers.unit.test.ts' is older than output '../load-balancer/tsconfig.tsbuildinfo'
52
+ 6:42:56 PM - Project '../load-balancer/tsconfig.json' is up to date because newest input '../load-balancer/src/index.ts' is older than output '../load-balancer/tsconfig.tsbuildinfo'
53
53
 
54
- 12:32:51 PM - Project '../widget-skeleton/tsconfig.json' is up to date because newest input '../widget-skeleton/src/webComponent/createWidget.ts' is older than output '../widget-skeleton/tsconfig.tsbuildinfo'
54
+ 6:42:56 PM - Project '../widget-skeleton/tsconfig.json' is up to date because newest input '../widget-skeleton/src/theme.ts' is older than output '../widget-skeleton/tsconfig.tsbuildinfo'
55
55
 
56
- 12:32:51 PM - Project '../keyring/tsconfig.json' is up to date because newest input '../keyring/src/pair/decode.ts' is older than output '../keyring/tsconfig.tsbuildinfo'
56
+ 6:42:57 PM - Project '../keyring/tsconfig.json' is up to date because newest input '../keyring/src/keyring/keyring.test.ts' is older than output '../keyring/tsconfig.tsbuildinfo'
57
57
 
58
- 12:32:51 PM - Project '../account/tsconfig.json' is up to date because newest input '../account/src/custom.d.ts' is older than output '../account/tsconfig.tsbuildinfo'
58
+ 6:42:57 PM - Project '../account/tsconfig.json' is up to date because newest input '../account/src/index.ts' is older than output '../account/tsconfig.tsbuildinfo'
59
59
 
60
- 12:32:51 PM - 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
+ 6:42:57 PM - Project '../procaptcha-common/tsconfig.json' is up to date because newest input '../procaptcha-common/src/clientMetaData.ts' is older than output '../procaptcha-common/tsconfig.tsbuildinfo'
61
61
 
62
- 12:32:51 PM - 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
+ 6:42:57 PM - 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'
63
63
 
64
- 12:32:51 PM - Project '../procaptcha-puzzle/tsconfig.json' is up to date because newest input '../procaptcha-puzzle/src/tests/managerHarness.ts' is older than output '../procaptcha-puzzle/tsconfig.tsbuildinfo'
64
+ 6:42:57 PM - Project '../procaptcha-puzzle/tsconfig.json' is up to date because newest input '../procaptcha-puzzle/src/tests/managerHarness.ts' is older than output '../procaptcha-puzzle/tsconfig.tsbuildinfo'
65
65
 
66
- 12:32:51 PM - Project '../datasets/tsconfig.json' is up to date because newest input '../datasets/src/tests/dataset.unit.test.ts' is older than output '../datasets/tsconfig.tsbuildinfo'
66
+ 6:42:57 PM - Project '../datasets/tsconfig.json' is up to date because newest input '../datasets/src/tests/mocks/data/captchas.ts' is older than output '../datasets/tsconfig.tsbuildinfo'
67
67
 
68
- 12:32:51 PM - Project '../procaptcha/tsconfig.json' is up to date because newest input '../procaptcha/src/modules/ProsopoCaptchaApi.ts' is older than output '../procaptcha/tsconfig.tsbuildinfo'
68
+ 6:42:57 PM - Project '../procaptcha/tsconfig.json' is up to date because newest input '../procaptcha/src/modules/Manager.ts' is older than output '../procaptcha/tsconfig.tsbuildinfo'
69
69
 
70
- 12:32:51 PM - 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
+ 6:42:57 PM - Project '../procaptcha-react/tsconfig.json' is up to date because newest input '../procaptcha-react/src/tests/captchaComponent.unit.test.tsx' is older than output '../procaptcha-react/tsconfig.tsbuildinfo'
71
71
 
72
- 12:32:51 PM - Project '../procaptcha-frictionless/tsconfig.json' is up to date because newest input '../procaptcha-frictionless/src/ProcaptchaFrictionless.tsx' is older than output '../procaptcha-frictionless/tsconfig.tsbuildinfo'
72
+ 6:42:57 PM - Project '../procaptcha-frictionless/tsconfig.json' is up to date because newest input '../procaptcha-frictionless/src/ProcaptchaFrictionless.tsx' is older than output '../procaptcha-frictionless/tsconfig.tsbuildinfo'
73
73
 
74
- 12:32:51 PM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
74
+ 6:42:57 PM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
75
75
 
76
- 12:32:51 PM - Building project '/home/runner/work/captcha/captcha/packages/procaptcha-bundle/tsconfig.json'...
76
+ 6:42:57 PM - Building project '/home/runner/work/captcha/captcha/packages/procaptcha-bundle/tsconfig.json'...
77
77
 
@@ -1,9 +1,9 @@
1
1
 
2
- > @prosopo/procaptcha-bundle@4.1.61 build
2
+ > @prosopo/procaptcha-bundle@4.2.1 build
3
3
  > npm run build:cross-env -- --mode ${NODE_ENV:-development}
4
4
 
5
5
 
6
- > @prosopo/procaptcha-bundle@4.1.61 build:cross-env
6
+ > @prosopo/procaptcha-bundle@4.2.1 build:cross-env
7
7
  > vite build --config vite.esm.config.ts --mode production
8
8
 
9
9
  ViteEsmConfig: .
@@ -61,7 +61,7 @@ ViteEsmConfig: .
61
61
  vite v8.1.5 building ssr environment for production...
62
62
  Bundle build started
63
63
  
64
- 10 modules transformed.
64
+ 11 modules transformed.
65
65
  rendering chunks...
66
66
  computing gzip size...
67
67
  dist/_virtual/_rolldown/runtime.js 0.04 kB │ gzip: 0.06 kB
@@ -71,8 +71,9 @@ dist/util/config.js 0.62 kB │ gzip: 0.33 kB
71
71
  dist/util/captcha/components/bundleCaptcha.js 0.68 kB │ gzip: 0.35 kB
72
72
  dist/util/configCreator.js 0.86 kB │ gzip: 0.45 kB
73
73
  dist/util/language.js 1.01 kB │ gzip: 0.44 kB
74
- dist/util/captcha/captchaRenderer.js 1.93 kB │ gzip: 0.70 kB
74
+ dist/util/clientSession.js 1.03 kB │ gzip: 0.55 kB
75
+ dist/util/captcha/captchaRenderer.js 2.04 kB │ gzip: 0.72 kB
75
76
  dist/util/widgetFactory.js 2.52 kB │ gzip: 0.85 kB
76
77
  dist/index.js 8.85 kB │ gzip: 3.14 kB
77
78
 
78
- ✓ built in 60ms
79
+ ✓ built in 59ms
package/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # @prosopo/procaptcha-bundle
2
2
 
3
+ ## 4.2.1
4
+ ### Patch Changes
5
+
6
+ - Updated dependencies [eb34de6]
7
+ - @prosopo/types@5.5.0
8
+ - @prosopo/procaptcha-common@2.12.1
9
+ - @prosopo/procaptcha-frictionless@2.13.19
10
+
11
+ ## 4.2.0
12
+ ### Minor Changes
13
+
14
+ - 4b1cb19: Correlate a site-supplied session id across render and verify.
15
+
16
+ A site can now hand the widget its own session identifier — Protect's JTI, or any per-user session id it already holds — and have the provider confirm at verify time that the token was earned in that same session. Render it with `data-sessionid="..."` or `renderOptions.sessionId`, resolved the same way `mode` and `language` already are, so implicit, explicit and invisible-button renders all pick it up. Pass the same value as the new trailing `clientSessionId` argument to `ProsopoServer.isVerified`.
17
+
18
+ The widget attaches it to the solution as `clientMetaData.clientSessionId`. It is persisted on the captcha record (PoW, puzzle and image alike) and mirrored to a new top-level `clientMetaData` key on the session record — an object rather than a flat field, because more render-time metadata is expected to land there. It survives the PoW→image/puzzle escalation handoff, since the escalated widget is mounted with the same config.
19
+
20
+ At verify, when the value is supplied and the solve does not carry exactly that value — including carrying none at all, which is what a token minted outside the site's session looks like — the token is disapproved with the new `ResultReason.CLIENT_SESSION_MISMATCH` (`API.CLIENT_SESSION_MISMATCH`, translated in all 31 locales), recorded on both the captcha record and the session.
21
+
22
+ Omitting the id preserves existing behaviour, so this is opt-in and backward compatible. The verify request field is `clientSessionId` rather than `sessionId` because `VerificationResponse.sessionId` already means the provider's own frictionless session; same-named request and response fields meaning different things would be a trap for integrators.
23
+
24
+ ### Patch Changes
25
+
26
+ - Updated dependencies [4b1cb19]
27
+ - @prosopo/types@5.4.0
28
+ - @prosopo/locale@3.4.0
29
+ - @prosopo/procaptcha-common@2.12.0
30
+ - @prosopo/procaptcha-frictionless@2.13.18
31
+
3
32
  ## 4.1.61
4
33
  ### Patch Changes
5
34
 
@@ -1,5 +1,6 @@
1
1
  const require_runtime = require("../../_virtual/_rolldown/runtime.cjs");
2
2
  const require_language = require("../language.cjs");
3
+ const require_clientSession = require("../clientSession.cjs");
3
4
  const require_configCreator = require("../configCreator.cjs");
4
5
  const require_timeout = require("../timeout.cjs");
5
6
  const require_bundleCaptcha = require("./components/bundleCaptcha.cjs");
@@ -27,6 +28,7 @@ var CaptchaRenderer = class {
27
28
  readAndValidateSettings(element, config, renderOptions) {
28
29
  require_timeout.setValidChallengeLength(renderOptions, element, config);
29
30
  require_language.setLanguage(renderOptions, element, config);
31
+ require_clientSession.setClientSessionId(renderOptions, element, config);
30
32
  }
31
33
  makeEmotionCache(cacheKey, container) {
32
34
  return (0, _emotion_cache.default)({
@@ -0,0 +1,28 @@
1
+ let _prosopo_types = require("@prosopo/types");
2
+ //#region src/util/clientSession.ts
3
+ /**
4
+ * Resolves the site's own session identifier for this widget, from either:
5
+ * 1. renderOptions.sessionId
6
+ * 2. the element's data-sessionid attribute
7
+ *
8
+ * The widget forwards the resolved value to the provider as
9
+ * `clientMetaData.clientSessionId` when the solution is submitted; the dapp
10
+ * server passes the same value to its verify call and the provider rejects the
11
+ * token if the two disagree. Left undefined when the site doesn't use sessions,
12
+ * in which case no correlation is performed.
13
+ *
14
+ * @param renderOptions
15
+ * @param element
16
+ * @param config
17
+ */
18
+ var setClientSessionId = (renderOptions, element, config) => {
19
+ const sessionId = renderOptions?.sessionId || element.getAttribute("data-sessionid");
20
+ if (!sessionId) return;
21
+ if (sessionId.length > _prosopo_types.INPUT_LIMITS.ID) {
22
+ console.error(`Ignoring session id longer than ${_prosopo_types.INPUT_LIMITS.ID} characters`);
23
+ return;
24
+ }
25
+ config.clientSessionId = sessionId;
26
+ };
27
+ //#endregion
28
+ exports.setClientSessionId = setClientSessionId;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=clientSession.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientSession.test.d.ts","sourceRoot":"","sources":["../../../src/tests/util/clientSession.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,61 @@
1
+ import { INPUT_LIMITS, ProcaptchaConfigSchema, } from "@prosopo/types";
2
+ import { JSDOM } from "jsdom";
3
+ import { beforeEach, describe, expect, it, vi } from "vitest";
4
+ import { setClientSessionId } from "../../util/clientSession.js";
5
+ const SITE_KEY = "5site";
6
+ const makeConfig = () => ProcaptchaConfigSchema.parse({ account: { address: SITE_KEY } });
7
+ const makeElement = (attributes = {}) => {
8
+ const dom = new JSDOM("<!DOCTYPE html><html><body></body></html>");
9
+ const element = dom.window.document.createElement("div");
10
+ for (const [name, value] of Object.entries(attributes)) {
11
+ element.setAttribute(name, value);
12
+ }
13
+ return element;
14
+ };
15
+ const renderOptions = (overrides = {}) => ({ siteKey: SITE_KEY, ...overrides });
16
+ describe("setClientSessionId", () => {
17
+ beforeEach(() => {
18
+ vi.restoreAllMocks();
19
+ });
20
+ it("leaves the config untouched when the site uses no sessions", () => {
21
+ const config = makeConfig();
22
+ setClientSessionId(renderOptions(), makeElement(), config);
23
+ expect(config.clientSessionId).toBeUndefined();
24
+ });
25
+ it("reads the session id from the render options", () => {
26
+ const config = makeConfig();
27
+ setClientSessionId(renderOptions({ sessionId: "jti-from-options" }), makeElement(), config);
28
+ expect(config.clientSessionId).toBe("jti-from-options");
29
+ });
30
+ it("falls back to the data-sessionid attribute", () => {
31
+ const config = makeConfig();
32
+ setClientSessionId(renderOptions(), makeElement({ "data-sessionid": "jti-from-attribute" }), config);
33
+ expect(config.clientSessionId).toBe("jti-from-attribute");
34
+ });
35
+ it("prefers the render option over the attribute", () => {
36
+ const config = makeConfig();
37
+ setClientSessionId(renderOptions({ sessionId: "jti-from-options" }), makeElement({ "data-sessionid": "jti-from-attribute" }), config);
38
+ expect(config.clientSessionId).toBe("jti-from-options");
39
+ });
40
+ it("works when renderOptions are absent entirely (implicit render)", () => {
41
+ const config = makeConfig();
42
+ setClientSessionId(undefined, makeElement({ "data-sessionid": "jti-implicit" }), config);
43
+ expect(config.clientSessionId).toBe("jti-implicit");
44
+ });
45
+ it("drops an oversized session id the provider would reject", () => {
46
+ const error = vi
47
+ .spyOn(console, "error")
48
+ .mockImplementation(() => undefined);
49
+ const config = makeConfig();
50
+ setClientSessionId(renderOptions({ sessionId: "x".repeat(INPUT_LIMITS.ID + 1) }), makeElement(), config);
51
+ expect(config.clientSessionId).toBeUndefined();
52
+ expect(error).toHaveBeenCalled();
53
+ });
54
+ it("keeps a session id exactly at the limit", () => {
55
+ const config = makeConfig();
56
+ const atLimit = "x".repeat(INPUT_LIMITS.ID);
57
+ setClientSessionId(renderOptions({ sessionId: atLimit }), makeElement(), config);
58
+ expect(config.clientSessionId).toBe(atLimit);
59
+ });
60
+ });
61
+ //# sourceMappingURL=clientSession.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientSession.test.js","sourceRoot":"","sources":["../../../src/tests/util/clientSession.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"captchaRenderer.d.ts","sourceRoot":"","sources":["../../../src/util/captcha/captchaRenderer.tsx"],"names":[],"mappings":"AAcA,OAAoB,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEhE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EACX,SAAS,EACT,4BAA4B,EAC5B,uBAAuB,EACvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EAAE,KAAK,IAAI,EAAc,MAAM,kBAAkB,CAAC;AAMzD,UAAU,cAAc;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;CACxB;AAED,cAAM,eAAe;IACb,aAAa,CACnB,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAE,WAAW,EACtB,aAAa,EAAE,uBAAuB,EACtC,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,KAAK,EACX,SAAS,EAAE,OAAO,EAClB,eAAe,EAAE,WAAW,EAC5B,aAAa,CAAC,EAAE,OAAO,GACrB,IAAI;IAyCP,SAAS,CAAC,uBAAuB,CAChC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,4BAA4B,EACpC,aAAa,EAAE,uBAAuB,GACpC,IAAI;IAKP,SAAS,CAAC,gBAAgB,CACzB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,WAAW,GACpB,YAAY;IAQf,SAAS,CAAC,eAAe,CACxB,SAAS,EAAE,WAAW,EACtB,gBAAgB,EAAE,MAAM,GACtB,IAAI;IAMP,SAAS,CAAC,sBAAsB,CAC/B,SAAS,EAAE,IAAI,EACf,YAAY,EAAE,YAAY,EAC1B,gBAAgB,EAAE,SAAS,GACzB,IAAI;CAKP;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"captchaRenderer.d.ts","sourceRoot":"","sources":["../../../src/util/captcha/captchaRenderer.tsx"],"names":[],"mappings":"AAcA,OAAoB,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEhE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EACX,SAAS,EACT,4BAA4B,EAC5B,uBAAuB,EACvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EAAE,KAAK,IAAI,EAAc,MAAM,kBAAkB,CAAC;AAOzD,UAAU,cAAc;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;CACxB;AAED,cAAM,eAAe;IACb,aAAa,CACnB,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAE,WAAW,EACtB,aAAa,EAAE,uBAAuB,EACtC,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,KAAK,EACX,SAAS,EAAE,OAAO,EAClB,eAAe,EAAE,WAAW,EAC5B,aAAa,CAAC,EAAE,OAAO,GACrB,IAAI;IAyCP,SAAS,CAAC,uBAAuB,CAChC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,4BAA4B,EACpC,aAAa,EAAE,uBAAuB,GACpC,IAAI;IAMP,SAAS,CAAC,gBAAgB,CACzB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,WAAW,GACpB,YAAY;IAQf,SAAS,CAAC,eAAe,CACxB,SAAS,EAAE,WAAW,EACtB,gBAAgB,EAAE,MAAM,GACtB,IAAI;IAMP,SAAS,CAAC,sBAAsB,CAC/B,SAAS,EAAE,IAAI,EACf,YAAY,EAAE,YAAY,EAC1B,gBAAgB,EAAE,SAAS,GACzB,IAAI;CAKP;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import "../../_virtual/_rolldown/runtime.js";
2
2
  import { setLanguage } from "../language.js";
3
+ import { setClientSessionId } from "../clientSession.js";
3
4
  import { createConfig } from "../configCreator.js";
4
5
  import { setValidChallengeLength } from "../timeout.js";
5
6
  import { BundleCaptcha } from "./components/bundleCaptcha.js";
@@ -26,6 +27,7 @@ var CaptchaRenderer = class {
26
27
  readAndValidateSettings(element, config, renderOptions) {
27
28
  setValidChallengeLength(renderOptions, element, config);
28
29
  setLanguage(renderOptions, element, config);
30
+ setClientSessionId(renderOptions, element, config);
29
31
  }
30
32
  makeEmotionCache(cacheKey, container) {
31
33
  return createCache({
@@ -1 +1 @@
1
- {"version":3,"file":"captchaRenderer.js","sourceRoot":"","sources":["../../../src/util/captcha/captchaRenderer.tsx"],"names":[],"mappings":";AAcA,OAAO,WAAkC,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAQ/C,OAAO,EAAa,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAQ9D,MAAM,eAAe;IACb,aAAa,CACnB,QAAwB,EACxB,SAAsB,EACtB,aAAsC,EACtC,SAAoB,EACpB,MAAe,EACf,IAAW,EACX,SAAkB,EAClB,eAA4B,EAC5B,aAAuB;QAEvB,MAAM,MAAM,GAAG,YAAY,CAC1B,aAAa,CAAC,OAAO,EACrB,aAAa,CAAC,KAAK,EACnB,aAAa,CAAC,QAAQ,EACtB,MAAM,EACN,SAAS,EACT,aAAa,CAAC,kBAAkB,EAChC,aAAa,CAAC,IAAI,EAClB,aAAa,CAAC,IAAI,CAClB,CAAC;QACF,IAAI,CAAC,uBAAuB,CAC3B,aAAa,IAAI,SAAS,EAC1B,MAAM,EACN,aAAa,CACb,CAAC;QAEF,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CACrC,SAAS,EACT,QAAQ,CAAC,gBAAgB,CACzB,CAAC;QAEF,MAAM,YAAY,GAAG,IAAI,CAAC,gBAAgB,CACzC,QAAQ,CAAC,eAAe,EACxB,SAAS,CACT,CAAC;QAEF,MAAM,gBAAgB,GAAG,CACxB,KAAC,aAAa,IACb,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,eAAe,GACzB,CACF,CAAC;QAEF,IAAI,CAAC,sBAAsB,CAAC,SAAS,EAAE,YAAY,EAAE,gBAAgB,CAAC,CAAC;QAEvE,OAAO,SAAS,CAAC;IAClB,CAAC;IAES,uBAAuB,CAChC,OAAgB,EAChB,MAAoC,EACpC,aAAsC;QAEtC,uBAAuB,CAAC,aAAa,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QACxD,WAAW,CAAC,aAAa,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC7C,CAAC;IAES,gBAAgB,CACzB,QAAgB,EAChB,SAAsB;QAEtB,OAAO,WAAW,CAAC;YAClB,GAAG,EAAE,QAAQ;YACb,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,SAAS;SACpB,CAAC,CAAC;IACJ,CAAC;IAES,eAAe,CACxB,SAAsB,EACtB,gBAAwB;QAExB,OAAO,UAAU,CAAC,SAAS,EAAE;YAC5B,gBAAgB,EAAE,gBAAgB;SAClC,CAAC,CAAC;IACJ,CAAC;IAES,sBAAsB,CAC/B,SAAe,EACf,YAA0B,EAC1B,gBAA2B;QAE3B,SAAS,CAAC,MAAM,CACf,KAAC,aAAa,IAAC,KAAK,EAAE,YAAY,YAAG,gBAAgB,GAAiB,CACtE,CAAC;IACH,CAAC;CACD;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"captchaRenderer.js","sourceRoot":"","sources":["../../../src/util/captcha/captchaRenderer.tsx"],"names":[],"mappings":";AAcA,OAAO,WAAkC,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAQ/C,OAAO,EAAa,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAQ9D,MAAM,eAAe;IACb,aAAa,CACnB,QAAwB,EACxB,SAAsB,EACtB,aAAsC,EACtC,SAAoB,EACpB,MAAe,EACf,IAAW,EACX,SAAkB,EAClB,eAA4B,EAC5B,aAAuB;QAEvB,MAAM,MAAM,GAAG,YAAY,CAC1B,aAAa,CAAC,OAAO,EACrB,aAAa,CAAC,KAAK,EACnB,aAAa,CAAC,QAAQ,EACtB,MAAM,EACN,SAAS,EACT,aAAa,CAAC,kBAAkB,EAChC,aAAa,CAAC,IAAI,EAClB,aAAa,CAAC,IAAI,CAClB,CAAC;QACF,IAAI,CAAC,uBAAuB,CAC3B,aAAa,IAAI,SAAS,EAC1B,MAAM,EACN,aAAa,CACb,CAAC;QAEF,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CACrC,SAAS,EACT,QAAQ,CAAC,gBAAgB,CACzB,CAAC;QAEF,MAAM,YAAY,GAAG,IAAI,CAAC,gBAAgB,CACzC,QAAQ,CAAC,eAAe,EACxB,SAAS,CACT,CAAC;QAEF,MAAM,gBAAgB,GAAG,CACxB,KAAC,aAAa,IACb,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,eAAe,GACzB,CACF,CAAC;QAEF,IAAI,CAAC,sBAAsB,CAAC,SAAS,EAAE,YAAY,EAAE,gBAAgB,CAAC,CAAC;QAEvE,OAAO,SAAS,CAAC;IAClB,CAAC;IAES,uBAAuB,CAChC,OAAgB,EAChB,MAAoC,EACpC,aAAsC;QAEtC,uBAAuB,CAAC,aAAa,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QACxD,WAAW,CAAC,aAAa,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QAC5C,kBAAkB,CAAC,aAAa,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IACpD,CAAC;IAES,gBAAgB,CACzB,QAAgB,EAChB,SAAsB;QAEtB,OAAO,WAAW,CAAC;YAClB,GAAG,EAAE,QAAQ;YACb,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,SAAS;SACpB,CAAC,CAAC;IACJ,CAAC;IAES,eAAe,CACxB,SAAsB,EACtB,gBAAwB;QAExB,OAAO,UAAU,CAAC,SAAS,EAAE;YAC5B,gBAAgB,EAAE,gBAAgB;SAClC,CAAC,CAAC;IACJ,CAAC;IAES,sBAAsB,CAC/B,SAAe,EACf,YAA0B,EAC1B,gBAA2B;QAE3B,SAAS,CAAC,MAAM,CACf,KAAC,aAAa,IAAC,KAAK,EAAE,YAAY,YAAG,gBAAgB,GAAiB,CACtE,CAAC;IACH,CAAC;CACD;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ProcaptchaClientConfigOutput, ProcaptchaRenderOptions } from "@prosopo/types";
2
+ export declare const setClientSessionId: (renderOptions: ProcaptchaRenderOptions | undefined, element: Element, config: ProcaptchaClientConfigOutput) => void;
3
+ //# sourceMappingURL=clientSession.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientSession.d.ts","sourceRoot":"","sources":["../../src/util/clientSession.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACX,4BAA4B,EAC5B,uBAAuB,EACvB,MAAM,gBAAgB,CAAC;AAiBxB,eAAO,MAAM,kBAAkB,kBACf,uBAAuB,GAAG,SAAS,WACzC,OAAO,UACR,4BAA4B,KAClC,IAmBF,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { INPUT_LIMITS } from "@prosopo/types";
2
+ //#region src/util/clientSession.ts
3
+ /**
4
+ * Resolves the site's own session identifier for this widget, from either:
5
+ * 1. renderOptions.sessionId
6
+ * 2. the element's data-sessionid attribute
7
+ *
8
+ * The widget forwards the resolved value to the provider as
9
+ * `clientMetaData.clientSessionId` when the solution is submitted; the dapp
10
+ * server passes the same value to its verify call and the provider rejects the
11
+ * token if the two disagree. Left undefined when the site doesn't use sessions,
12
+ * in which case no correlation is performed.
13
+ *
14
+ * @param renderOptions
15
+ * @param element
16
+ * @param config
17
+ */
18
+ var setClientSessionId = (renderOptions, element, config) => {
19
+ const sessionId = renderOptions?.sessionId || element.getAttribute("data-sessionid");
20
+ if (!sessionId) return;
21
+ if (sessionId.length > INPUT_LIMITS.ID) {
22
+ console.error(`Ignoring session id longer than ${INPUT_LIMITS.ID} characters`);
23
+ return;
24
+ }
25
+ config.clientSessionId = sessionId;
26
+ };
27
+ //#endregion
28
+ export { setClientSessionId };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientSession.js","sourceRoot":"","sources":["../../src/util/clientSession.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAqB9C,MAAM,CAAC,MAAM,kBAAkB,GAAG,CACjC,aAAkD,EAClD,OAAgB,EAChB,MAAoC,EAC7B,EAAE;IACT,MAAM,SAAS,GACd,aAAa,EAAE,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC;IAEpE,IAAI,CAAC,SAAS,EAAE,CAAC;QAChB,OAAO;IACR,CAAC;IAKD,IAAI,SAAS,CAAC,MAAM,GAAG,YAAY,CAAC,EAAE,EAAE,CAAC;QACxC,OAAO,CAAC,KAAK,CACZ,mCAAmC,YAAY,CAAC,EAAE,aAAa,CAC/D,CAAC;QACF,OAAO;IACR,CAAC;IAED,MAAM,CAAC,eAAe,GAAG,SAAS,CAAC;AACpC,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prosopo/procaptcha-bundle",
3
- "version": "4.1.61",
3
+ "version": "4.2.1",
4
4
  "author": "PROSOPO LIMITED <info@prosopo.io>",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/index.js",
@@ -40,10 +40,10 @@
40
40
  "browserslist": ["> 0.5%, last 2 versions, not dead"],
41
41
  "dependencies": {
42
42
  "@prosopo/dotenv": "3.0.53",
43
- "@prosopo/locale": "3.3.1",
44
- "@prosopo/procaptcha-common": "2.11.35",
45
- "@prosopo/procaptcha-frictionless": "2.13.17",
46
- "@prosopo/types": "5.3.0",
43
+ "@prosopo/locale": "3.4.0",
44
+ "@prosopo/procaptcha-common": "2.12.1",
45
+ "@prosopo/procaptcha-frictionless": "2.13.19",
46
+ "@prosopo/types": "5.5.0",
47
47
  "@prosopo/util": "3.3.7",
48
48
  "@prosopo/widget-skeleton": "2.8.6",
49
49
  "dotenv": "16.4.5",
@@ -0,0 +1,118 @@
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
+ import {
16
+ INPUT_LIMITS,
17
+ type ProcaptchaClientConfigOutput,
18
+ ProcaptchaConfigSchema,
19
+ type ProcaptchaRenderOptions,
20
+ } from "@prosopo/types";
21
+ import { JSDOM } from "jsdom";
22
+ import { beforeEach, describe, expect, it, vi } from "vitest";
23
+ import { setClientSessionId } from "../../util/clientSession.js";
24
+
25
+ const SITE_KEY = "5site";
26
+
27
+ const makeConfig = (): ProcaptchaClientConfigOutput =>
28
+ ProcaptchaConfigSchema.parse({ account: { address: SITE_KEY } });
29
+
30
+ const makeElement = (attributes: Record<string, string> = {}): Element => {
31
+ const dom = new JSDOM("<!DOCTYPE html><html><body></body></html>");
32
+ const element = dom.window.document.createElement("div");
33
+ for (const [name, value] of Object.entries(attributes)) {
34
+ element.setAttribute(name, value);
35
+ }
36
+ return element;
37
+ };
38
+
39
+ const renderOptions = (
40
+ overrides: Partial<ProcaptchaRenderOptions> = {},
41
+ ): ProcaptchaRenderOptions => ({ siteKey: SITE_KEY, ...overrides });
42
+
43
+ describe("setClientSessionId", () => {
44
+ beforeEach(() => {
45
+ vi.restoreAllMocks();
46
+ });
47
+
48
+ it("leaves the config untouched when the site uses no sessions", () => {
49
+ const config = makeConfig();
50
+ setClientSessionId(renderOptions(), makeElement(), config);
51
+ expect(config.clientSessionId).toBeUndefined();
52
+ });
53
+
54
+ it("reads the session id from the render options", () => {
55
+ const config = makeConfig();
56
+ setClientSessionId(
57
+ renderOptions({ sessionId: "jti-from-options" }),
58
+ makeElement(),
59
+ config,
60
+ );
61
+ expect(config.clientSessionId).toBe("jti-from-options");
62
+ });
63
+
64
+ it("falls back to the data-sessionid attribute", () => {
65
+ const config = makeConfig();
66
+ setClientSessionId(
67
+ renderOptions(),
68
+ makeElement({ "data-sessionid": "jti-from-attribute" }),
69
+ config,
70
+ );
71
+ expect(config.clientSessionId).toBe("jti-from-attribute");
72
+ });
73
+
74
+ it("prefers the render option over the attribute", () => {
75
+ const config = makeConfig();
76
+ setClientSessionId(
77
+ renderOptions({ sessionId: "jti-from-options" }),
78
+ makeElement({ "data-sessionid": "jti-from-attribute" }),
79
+ config,
80
+ );
81
+ expect(config.clientSessionId).toBe("jti-from-options");
82
+ });
83
+
84
+ it("works when renderOptions are absent entirely (implicit render)", () => {
85
+ const config = makeConfig();
86
+ setClientSessionId(
87
+ undefined,
88
+ makeElement({ "data-sessionid": "jti-implicit" }),
89
+ config,
90
+ );
91
+ expect(config.clientSessionId).toBe("jti-implicit");
92
+ });
93
+
94
+ it("drops an oversized session id the provider would reject", () => {
95
+ const error = vi
96
+ .spyOn(console, "error")
97
+ .mockImplementation(() => undefined);
98
+ const config = makeConfig();
99
+ setClientSessionId(
100
+ renderOptions({ sessionId: "x".repeat(INPUT_LIMITS.ID + 1) }),
101
+ makeElement(),
102
+ config,
103
+ );
104
+ expect(config.clientSessionId).toBeUndefined();
105
+ expect(error).toHaveBeenCalled();
106
+ });
107
+
108
+ it("keeps a session id exactly at the limit", () => {
109
+ const config = makeConfig();
110
+ const atLimit = "x".repeat(INPUT_LIMITS.ID);
111
+ setClientSessionId(
112
+ renderOptions({ sessionId: atLimit }),
113
+ makeElement(),
114
+ config,
115
+ );
116
+ expect(config.clientSessionId).toBe(atLimit);
117
+ });
118
+ });
@@ -22,6 +22,7 @@ import type {
22
22
  } from "@prosopo/types";
23
23
  import type { ReactNode } from "react";
24
24
  import { type Root, createRoot } from "react-dom/client";
25
+ import { setClientSessionId } from "../clientSession.js";
25
26
  import { createConfig } from "../configCreator.js";
26
27
  import { setLanguage } from "../language.js";
27
28
  import { setValidChallengeLength } from "../timeout.js";
@@ -92,6 +93,7 @@ class CaptchaRenderer {
92
93
  ): void {
93
94
  setValidChallengeLength(renderOptions, element, config);
94
95
  setLanguage(renderOptions, element, config);
96
+ setClientSessionId(renderOptions, element, config);
95
97
  }
96
98
 
97
99
  protected makeEmotionCache(
@@ -0,0 +1,59 @@
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
+ import { INPUT_LIMITS } from "@prosopo/types";
16
+ import type {
17
+ ProcaptchaClientConfigOutput,
18
+ ProcaptchaRenderOptions,
19
+ } from "@prosopo/types";
20
+
21
+ /**
22
+ * Resolves the site's own session identifier for this widget, from either:
23
+ * 1. renderOptions.sessionId
24
+ * 2. the element's data-sessionid attribute
25
+ *
26
+ * The widget forwards the resolved value to the provider as
27
+ * `clientMetaData.clientSessionId` when the solution is submitted; the dapp
28
+ * server passes the same value to its verify call and the provider rejects the
29
+ * token if the two disagree. Left undefined when the site doesn't use sessions,
30
+ * in which case no correlation is performed.
31
+ *
32
+ * @param renderOptions
33
+ * @param element
34
+ * @param config
35
+ */
36
+ export const setClientSessionId = (
37
+ renderOptions: ProcaptchaRenderOptions | undefined,
38
+ element: Element,
39
+ config: ProcaptchaClientConfigOutput,
40
+ ): void => {
41
+ const sessionId =
42
+ renderOptions?.sessionId || element.getAttribute("data-sessionid");
43
+
44
+ if (!sessionId) {
45
+ return;
46
+ }
47
+
48
+ // The provider bounds this field at INPUT_LIMITS.ID and would reject the
49
+ // whole solution body if it were longer, so drop an oversized value here
50
+ // rather than failing the solve over metadata.
51
+ if (sessionId.length > INPUT_LIMITS.ID) {
52
+ console.error(
53
+ `Ignoring session id longer than ${INPUT_LIMITS.ID} characters`,
54
+ );
55
+ return;
56
+ }
57
+
58
+ config.clientSessionId = sessionId;
59
+ };