@prosopo/procaptcha-frictionless 2.13.7 → 2.13.9
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 +6 -5
- package/.turbo/turbo-build$colon$tsc.log +24 -24
- package/.turbo/turbo-build.log +6 -5
- package/CHANGELOG.md +69 -0
- package/dist/ProcaptchaFrictionless.d.ts.map +1 -1
- package/dist/ProcaptchaFrictionless.js +6 -4
- package/dist/ProcaptchaFrictionless.js.map +1 -1
- package/dist/cjs/ProcaptchaFrictionless.cjs +6 -4
- package/dist/cjs/frictionlessResultGuard.cjs +35 -0
- package/dist/frictionlessResultGuard.d.ts +18 -0
- package/dist/frictionlessResultGuard.d.ts.map +1 -0
- package/dist/frictionlessResultGuard.js +34 -0
- package/dist/frictionlessResultGuard.js.map +1 -0
- package/dist/tests/frictionlessResultGuard.test.d.ts +2 -0
- package/dist/tests/frictionlessResultGuard.test.d.ts.map +1 -0
- package/dist/tests/frictionlessResultGuard.test.js +53 -0
- package/dist/tests/frictionlessResultGuard.test.js.map +1 -0
- package/package.json +8 -8
- package/src/ProcaptchaFrictionless.tsx +6 -4
- package/src/frictionlessResultGuard.ts +64 -0
- package/src/tests/frictionlessResultGuard.test.ts +104 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,104 @@
|
|
|
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 { describe, expect, it } from "vitest";
|
|
16
|
+
import {
|
|
17
|
+
MISSING_CAPTCHA_TYPE_MESSAGE,
|
|
18
|
+
evaluateFrictionlessResult,
|
|
19
|
+
} from "../frictionlessResultGuard.js";
|
|
20
|
+
|
|
21
|
+
// This guard exists so a `/frictionless` response with no `captchaType`
|
|
22
|
+
// (the shape emitted by request-time short-circuits — access-policy
|
|
23
|
+
// hard-block, decision-machine autoBan, domain / header middleware
|
|
24
|
+
// rejections — whose `{ error: "..." }` bare-string bodies slip past
|
|
25
|
+
// `error.message` inspection) cannot fall through into
|
|
26
|
+
// `renderForCaptchaType(undefined, ...)` and mount ProcaptchaPow with an
|
|
27
|
+
// undefined sessionId, which the provider then rejects as
|
|
28
|
+
// API.INCORRECT_CAPTCHA_TYPE for a frictionless sitekey.
|
|
29
|
+
|
|
30
|
+
describe("evaluateFrictionlessResult", () => {
|
|
31
|
+
it("passes a well-formed response with a captchaType", () => {
|
|
32
|
+
expect(
|
|
33
|
+
evaluateFrictionlessResult({
|
|
34
|
+
captchaType: "pow",
|
|
35
|
+
}),
|
|
36
|
+
).toEqual({ kind: "pass" });
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("passes when a captchaType is present even if error is a bare undefined", () => {
|
|
40
|
+
expect(
|
|
41
|
+
evaluateFrictionlessResult({
|
|
42
|
+
captchaType: "image",
|
|
43
|
+
error: undefined,
|
|
44
|
+
}),
|
|
45
|
+
).toEqual({ kind: "pass" });
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("returns a structured error when the server emits `{ error: { message } }`", () => {
|
|
49
|
+
expect(
|
|
50
|
+
evaluateFrictionlessResult({
|
|
51
|
+
captchaType: "pow",
|
|
52
|
+
error: { message: "Boom", key: "API.SOMETHING" },
|
|
53
|
+
}),
|
|
54
|
+
).toEqual({ kind: "error", message: "Boom", key: "API.SOMETHING" });
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("omits key from the outcome when the server error carries no key", () => {
|
|
58
|
+
const outcome = evaluateFrictionlessResult({
|
|
59
|
+
captchaType: "pow",
|
|
60
|
+
error: { message: "Boom" },
|
|
61
|
+
});
|
|
62
|
+
expect(outcome.kind).toBe("error");
|
|
63
|
+
if (outcome.kind !== "error") throw new Error("expected error outcome");
|
|
64
|
+
expect(outcome.message).toBe("Boom");
|
|
65
|
+
expect("key" in outcome).toBe(false);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("halts when captchaType is missing (bare-string 401 body shape from access-policy / autoBan / middleware)", () => {
|
|
69
|
+
// Access-policy hard-block / decision-machine autoBan / domain
|
|
70
|
+
// middleware all return `{"error":"Unauthorized"}` — a bare
|
|
71
|
+
// string, not `{message}`, so `error.message` is undefined and
|
|
72
|
+
// would slip past the earlier error check. HttpClientBase does
|
|
73
|
+
// not throw on 4xx JSON so the widget receives this as a
|
|
74
|
+
// valid-looking result.
|
|
75
|
+
expect(
|
|
76
|
+
evaluateFrictionlessResult({
|
|
77
|
+
// Simulating the JSON parse: `error` came in as a string on
|
|
78
|
+
// the wire but is not the object shape the guard reads.
|
|
79
|
+
error: undefined,
|
|
80
|
+
}),
|
|
81
|
+
).toEqual({ kind: "error", message: MISSING_CAPTCHA_TYPE_MESSAGE });
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("halts when both captchaType and error are absent (opaque parse failure)", () => {
|
|
85
|
+
expect(evaluateFrictionlessResult({})).toEqual({
|
|
86
|
+
kind: "error",
|
|
87
|
+
message: MISSING_CAPTCHA_TYPE_MESSAGE,
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("prefers the structured error over the missing-captchaType message when both apply", () => {
|
|
92
|
+
// If the server ever emits BOTH a structured error and no captchaType,
|
|
93
|
+
// the structured error is the more informative signal.
|
|
94
|
+
expect(
|
|
95
|
+
evaluateFrictionlessResult({
|
|
96
|
+
error: { message: "Server error", key: "API.SERVER_ERROR" },
|
|
97
|
+
}),
|
|
98
|
+
).toEqual({
|
|
99
|
+
kind: "error",
|
|
100
|
+
message: "Server error",
|
|
101
|
+
key: "API.SERVER_ERROR",
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
});
|