@prosopo/better-auth-procaptcha-plugin 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build$colon$cjs.log +32 -0
- package/.turbo/turbo-build$colon$esm.log +33 -0
- package/.turbo/turbo-build$colon$tsc.log +23 -0
- package/.turbo/turbo-build$colon$types.log +1 -0
- package/CHANGELOG.md +12 -0
- package/LICENSE +201 -0
- package/dist/cjs/client.cjs +32 -0
- package/dist/cjs/constants.cjs +22 -0
- package/dist/cjs/index.cjs +80 -0
- package/dist/cjs/path.cjs +41 -0
- package/dist/cjs/siteverify.cjs +68 -0
- package/dist/esm/_virtual/_rolldown/runtime.js +2 -0
- package/dist/esm/client.js +31 -0
- package/dist/esm/constants.js +18 -0
- package/dist/esm/index.js +75 -0
- package/dist/esm/path.js +40 -0
- package/dist/esm/siteverify.js +68 -0
- package/dist/tsc/client.d.ts +19 -0
- package/dist/tsc/client.d.ts.map +1 -0
- package/dist/tsc/client.js +39 -0
- package/dist/tsc/client.js.map +1 -0
- package/dist/tsc/constants.d.ts +12 -0
- package/dist/tsc/constants.d.ts.map +1 -0
- package/dist/tsc/constants.js +16 -0
- package/dist/tsc/constants.js.map +1 -0
- package/dist/tsc/index.d.ts +28 -0
- package/dist/tsc/index.d.ts.map +1 -0
- package/dist/tsc/index.js +94 -0
- package/dist/tsc/index.js.map +1 -0
- package/dist/tsc/path.d.ts +4 -0
- package/dist/tsc/path.d.ts.map +1 -0
- package/dist/tsc/path.js +59 -0
- package/dist/tsc/path.js.map +1 -0
- package/dist/tsc/siteverify.d.ts +40 -0
- package/dist/tsc/siteverify.d.ts.map +1 -0
- package/dist/tsc/siteverify.js +80 -0
- package/dist/tsc/siteverify.js.map +1 -0
- package/dist/tsc/tests/client.unit.test.d.ts +2 -0
- package/dist/tsc/tests/client.unit.test.d.ts.map +1 -0
- package/dist/tsc/tests/client.unit.test.js +56 -0
- package/dist/tsc/tests/client.unit.test.js.map +1 -0
- package/dist/tsc/tests/path.unit.test.d.ts +2 -0
- package/dist/tsc/tests/path.unit.test.d.ts.map +1 -0
- package/dist/tsc/tests/path.unit.test.js +53 -0
- package/dist/tsc/tests/path.unit.test.js.map +1 -0
- package/dist/tsc/tests/procaptcha.unit.test.d.ts +2 -0
- package/dist/tsc/tests/procaptcha.unit.test.d.ts.map +1 -0
- package/dist/tsc/tests/procaptcha.unit.test.js +158 -0
- package/dist/tsc/tests/procaptcha.unit.test.js.map +1 -0
- package/dist/tsc/tests/siteVerifyMock.d.ts +17 -0
- package/dist/tsc/tests/siteVerifyMock.d.ts.map +1 -0
- package/dist/tsc/tests/siteVerifyMock.js +43 -0
- package/dist/tsc/tests/siteVerifyMock.js.map +1 -0
- package/dist/tsc/tests/siteverify.unit.test.d.ts +2 -0
- package/dist/tsc/tests/siteverify.unit.test.d.ts.map +1 -0
- package/dist/tsc/tests/siteverify.unit.test.js +50 -0
- package/dist/tsc/tests/siteverify.unit.test.js.map +1 -0
- package/dist/types/client.d.ts +19 -0
- package/dist/types/client.d.ts.map +1 -0
- package/dist/types/constants.d.ts +12 -0
- package/dist/types/constants.d.ts.map +1 -0
- package/dist/types/index.d.ts +28 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/path.d.ts +4 -0
- package/dist/types/path.d.ts.map +1 -0
- package/dist/types/siteverify.d.ts +40 -0
- package/dist/types/siteverify.d.ts.map +1 -0
- package/dist/types/tests/client.unit.test.d.ts +2 -0
- package/dist/types/tests/client.unit.test.d.ts.map +1 -0
- package/dist/types/tests/path.unit.test.d.ts +2 -0
- package/dist/types/tests/path.unit.test.d.ts.map +1 -0
- package/dist/types/tests/procaptcha.unit.test.d.ts +2 -0
- package/dist/types/tests/procaptcha.unit.test.d.ts.map +1 -0
- package/dist/types/tests/siteVerifyMock.d.ts +17 -0
- package/dist/types/tests/siteVerifyMock.d.ts.map +1 -0
- package/dist/types/tests/siteverify.unit.test.d.ts +2 -0
- package/dist/types/tests/siteverify.unit.test.d.ts.map +1 -0
- package/package.json +68 -3
- package/readme.md +145 -0
- package/vite.cjs.config.ts +24 -0
- package/vite.esm.config.ts +23 -0
- package/vite.test.config.ts +19 -0
- package/README.md +0 -3
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import "./_virtual/_rolldown/runtime.js";
|
|
2
|
+
import { DEFAULT_ENDPOINTS, PROCAPTCHA_ERROR_CODES, PROCAPTCHA_HEADER, PROCAPTCHA_SITEVERIFY_URL } from "./constants.js";
|
|
3
|
+
import { createPathMatcher, normalizeAuthPath } from "./path.js";
|
|
4
|
+
import { verifyProcaptchaToken } from "./siteverify.js";
|
|
5
|
+
import { getIP } from "better-auth/api";
|
|
6
|
+
//#region src/index.ts
|
|
7
|
+
var errorResponse = (code, status) => ({ response: Response.json({
|
|
8
|
+
code,
|
|
9
|
+
message: PROCAPTCHA_ERROR_CODES[code].message
|
|
10
|
+
}, { status }) });
|
|
11
|
+
var resolveClientIP = (request, options) => getIP(request, {
|
|
12
|
+
...options,
|
|
13
|
+
advanced: {
|
|
14
|
+
...options.advanced,
|
|
15
|
+
ipAddress: {
|
|
16
|
+
...options.advanced?.ipAddress,
|
|
17
|
+
ipv6Subnet: 128
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}) ?? void 0;
|
|
21
|
+
var readEmailDomain = async (request) => {
|
|
22
|
+
if (!request.headers.get("content-type")?.includes("application/json")) return;
|
|
23
|
+
try {
|
|
24
|
+
const body = await request.clone().json();
|
|
25
|
+
if (typeof body !== "object" || body === null || !("email" in body)) return;
|
|
26
|
+
const { email } = body;
|
|
27
|
+
if (typeof email !== "string") return;
|
|
28
|
+
const domain = email.slice(email.lastIndexOf("@") + 1).trim();
|
|
29
|
+
return email.includes("@") && domain ? domain.toLowerCase() : void 0;
|
|
30
|
+
} catch {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
var procaptcha = (options) => {
|
|
35
|
+
const isProtected = createPathMatcher(options.endpoints?.length ? options.endpoints : DEFAULT_ENDPOINTS);
|
|
36
|
+
const headerName = options.headerName ?? "x-captcha-response";
|
|
37
|
+
return {
|
|
38
|
+
id: "procaptcha",
|
|
39
|
+
$ERROR_CODES: PROCAPTCHA_ERROR_CODES,
|
|
40
|
+
onRequest: async (request, ctx) => {
|
|
41
|
+
const path = normalizeAuthPath(new URL(request.url).pathname, ctx.options.basePath ?? "/api/auth");
|
|
42
|
+
if (!isProtected(path)) return;
|
|
43
|
+
if (!options.secretKey) {
|
|
44
|
+
ctx.logger.error("Procaptcha: secretKey is not configured");
|
|
45
|
+
return errorResponse("PROCAPTCHA_UNKNOWN_ERROR", 500);
|
|
46
|
+
}
|
|
47
|
+
const token = request.headers.get(headerName);
|
|
48
|
+
if (!token) return errorResponse("PROCAPTCHA_MISSING_RESPONSE", 400);
|
|
49
|
+
const ip = options.sendIP === false ? void 0 : resolveClientIP(request, ctx.options);
|
|
50
|
+
const email = options.sendEmailDomain ? await readEmailDomain(request) : void 0;
|
|
51
|
+
const result = await verifyProcaptchaToken({
|
|
52
|
+
secretKey: options.secretKey,
|
|
53
|
+
token,
|
|
54
|
+
...ip ? { ip } : {},
|
|
55
|
+
...email ? { email } : {},
|
|
56
|
+
siteVerifyURL: options.siteVerifyURL ?? "https://api.prosopo.io/siteverify",
|
|
57
|
+
timeoutMs: options.timeoutMs ?? 1e4,
|
|
58
|
+
...options.fetch ? { fetch: options.fetch } : {}
|
|
59
|
+
});
|
|
60
|
+
if (result.outcome === "error") {
|
|
61
|
+
ctx.logger.error("Procaptcha siteverify failed", {
|
|
62
|
+
status: result.status,
|
|
63
|
+
key: result.key,
|
|
64
|
+
message: result.message
|
|
65
|
+
});
|
|
66
|
+
return result.transient ? errorResponse("PROCAPTCHA_SERVICE_UNAVAILABLE", 503) : errorResponse("PROCAPTCHA_UNKNOWN_ERROR", 500);
|
|
67
|
+
}
|
|
68
|
+
if (result.outcome === "rejected") return errorResponse("PROCAPTCHA_VERIFICATION_FAILED", 403);
|
|
69
|
+
if (options.maxScore !== void 0 && result.score !== void 0 && result.score > options.maxScore) return errorResponse("PROCAPTCHA_VERIFICATION_FAILED", 403);
|
|
70
|
+
},
|
|
71
|
+
options
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
//#endregion
|
|
75
|
+
export { DEFAULT_ENDPOINTS, PROCAPTCHA_ERROR_CODES, PROCAPTCHA_HEADER, PROCAPTCHA_SITEVERIFY_URL, procaptcha, verifyProcaptchaToken };
|
package/dist/esm/path.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
//#region src/path.ts
|
|
2
|
+
var normalizeAuthPath = (pathname, basePath) => {
|
|
3
|
+
const collapsed = `/${basePath && pathname.startsWith(basePath) ? pathname.slice(basePath.length) : pathname}`.replace(/\/{2,}/g, "/");
|
|
4
|
+
return collapsed.length > 1 ? collapsed.replace(/\/$/, "") : collapsed;
|
|
5
|
+
};
|
|
6
|
+
var matchesSegment = (pattern, segment) => {
|
|
7
|
+
const parts = pattern.split("*");
|
|
8
|
+
if (parts.length === 1) return pattern === segment;
|
|
9
|
+
const first = parts[0] ?? "";
|
|
10
|
+
const last = parts[parts.length - 1] ?? "";
|
|
11
|
+
if (segment.length < first.length + last.length || !segment.startsWith(first) || !segment.endsWith(last)) return false;
|
|
12
|
+
let cursor = first.length;
|
|
13
|
+
const end = segment.length - last.length;
|
|
14
|
+
for (const part of parts.slice(1, -1)) {
|
|
15
|
+
const found = segment.indexOf(part, cursor);
|
|
16
|
+
if (found === -1 || found + part.length > end) return false;
|
|
17
|
+
cursor = found + part.length;
|
|
18
|
+
}
|
|
19
|
+
return true;
|
|
20
|
+
};
|
|
21
|
+
var matchesSegments = (patterns, segments) => {
|
|
22
|
+
const [pattern, ...restPatterns] = patterns;
|
|
23
|
+
if (pattern === void 0) return segments.length === 0;
|
|
24
|
+
if (pattern === "**") {
|
|
25
|
+
for (let skip = 0; skip <= segments.length; skip++) if (matchesSegments(restPatterns, segments.slice(skip))) return true;
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
const [segment, ...restSegments] = segments;
|
|
29
|
+
return segment !== void 0 && matchesSegment(pattern, segment) && matchesSegments(restPatterns, restSegments);
|
|
30
|
+
};
|
|
31
|
+
var createPathMatcher = (endpoints) => {
|
|
32
|
+
const matchers = endpoints.map((endpoint) => {
|
|
33
|
+
if (!endpoint.includes("*")) return (path) => path === endpoint;
|
|
34
|
+
const patterns = endpoint.split("/");
|
|
35
|
+
return (path) => matchesSegments(patterns, path.split("/"));
|
|
36
|
+
});
|
|
37
|
+
return (path) => matchers.some((matches) => matches(path));
|
|
38
|
+
};
|
|
39
|
+
//#endregion
|
|
40
|
+
export { createPathMatcher, normalizeAuthPath };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { DEFAULT_TIMEOUT_MS, PROCAPTCHA_SITEVERIFY_URL } from "./constants.js";
|
|
2
|
+
//#region src/siteverify.ts
|
|
3
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4
|
+
var isSiteVerifyResponse = (value) => isRecord(value) && typeof value.status === "string" && typeof value.verified === "boolean" && (value.score === void 0 || typeof value.score === "number") && (value.reason === void 0 || typeof value.reason === "string");
|
|
5
|
+
var isSiteVerifyErrorResponse = (value) => isRecord(value) && isRecord(value.error) && typeof value.error.key === "string";
|
|
6
|
+
var readJson = async (response) => {
|
|
7
|
+
try {
|
|
8
|
+
return await response.json();
|
|
9
|
+
} catch {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
var isTransientStatus = (status) => status === 429 || status >= 500;
|
|
14
|
+
var verifyProcaptchaToken = async ({ secretKey, token, ip, email, siteVerifyURL = PROCAPTCHA_SITEVERIFY_URL, timeoutMs = DEFAULT_TIMEOUT_MS, fetch: fetchImpl = fetch }) => {
|
|
15
|
+
const body = {
|
|
16
|
+
secret: secretKey,
|
|
17
|
+
token,
|
|
18
|
+
...ip ? { ip } : {},
|
|
19
|
+
...email ? { email } : {}
|
|
20
|
+
};
|
|
21
|
+
let response;
|
|
22
|
+
try {
|
|
23
|
+
response = await fetchImpl(siteVerifyURL, {
|
|
24
|
+
method: "POST",
|
|
25
|
+
headers: {
|
|
26
|
+
"Content-Type": "application/json",
|
|
27
|
+
Accept: "application/json"
|
|
28
|
+
},
|
|
29
|
+
body: JSON.stringify(body),
|
|
30
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
31
|
+
});
|
|
32
|
+
} catch (error) {
|
|
33
|
+
return {
|
|
34
|
+
outcome: "error",
|
|
35
|
+
transient: true,
|
|
36
|
+
message: error instanceof Error ? error.message : String(error)
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const payload = await readJson(response);
|
|
40
|
+
if (!response.ok) {
|
|
41
|
+
const errorBody = isSiteVerifyErrorResponse(payload) ? payload.error : void 0;
|
|
42
|
+
return {
|
|
43
|
+
outcome: "error",
|
|
44
|
+
transient: isTransientStatus(response.status),
|
|
45
|
+
status: response.status,
|
|
46
|
+
...errorBody ? { key: errorBody.key } : {},
|
|
47
|
+
message: typeof errorBody?.message === "string" ? errorBody.message : `siteverify responded with HTTP ${response.status}`
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (!isSiteVerifyResponse(payload)) return {
|
|
51
|
+
outcome: "error",
|
|
52
|
+
transient: true,
|
|
53
|
+
status: response.status,
|
|
54
|
+
message: "siteverify returned an unexpected response body"
|
|
55
|
+
};
|
|
56
|
+
const score = payload.score === void 0 ? {} : { score: payload.score };
|
|
57
|
+
if (!payload.verified) return {
|
|
58
|
+
outcome: "rejected",
|
|
59
|
+
...payload.reason ? { reason: payload.reason } : {},
|
|
60
|
+
...score
|
|
61
|
+
};
|
|
62
|
+
return {
|
|
63
|
+
outcome: "verified",
|
|
64
|
+
...score
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
//#endregion
|
|
68
|
+
export { verifyProcaptchaToken };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { procaptcha } from "./index.js";
|
|
2
|
+
export interface ProcaptchaClientOptions {
|
|
3
|
+
getToken?: () => string | undefined | Promise<string | undefined>;
|
|
4
|
+
endpoints?: readonly string[];
|
|
5
|
+
headerName?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const procaptchaHeaders: (token: string, headerName?: string) => Record<string, string>;
|
|
8
|
+
export declare const procaptchaClient: (options?: ProcaptchaClientOptions) => {
|
|
9
|
+
id: "procaptcha";
|
|
10
|
+
$InferServerPlugin: ReturnType<typeof procaptcha>;
|
|
11
|
+
fetchPlugins: {
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
hooks: {
|
|
15
|
+
onRequest: <T extends Record<string, any>>(context: import("better-auth/client").RequestContext<T>) => Promise<import("better-auth/client").RequestContext<T>>;
|
|
16
|
+
};
|
|
17
|
+
}[];
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7C,MAAM,WAAW,uBAAuB;IAMvC,QAAQ,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAElE,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAE9B,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,iBAAiB,UACtB,MAAM,eACD,MAAM,KAChB,MAAM,CAAC,MAAM,EAAE,MAAM,CAA8B,CAAC;AAQvD,eAAO,MAAM,gBAAgB,aAAa,uBAAuB;;wBASrC,UAAU,CAAC,OAAO,UAAU,CAAC;;;;;;;;CAyBxD,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { DEFAULT_ENDPOINTS, PROCAPTCHA_HEADER } from "./constants.js";
|
|
2
|
+
import { createPathMatcher, normalizeAuthPath } from "./path.js";
|
|
3
|
+
export const procaptchaHeaders = (token, headerName = PROCAPTCHA_HEADER) => ({ [headerName]: token });
|
|
4
|
+
const authPathOf = (url, baseURL) => {
|
|
5
|
+
const requestURL = new URL(url, "http://localhost");
|
|
6
|
+
const basePath = baseURL ? new URL(baseURL, requestURL).pathname : "";
|
|
7
|
+
return normalizeAuthPath(requestURL.pathname, basePath);
|
|
8
|
+
};
|
|
9
|
+
export const procaptchaClient = (options = {}) => {
|
|
10
|
+
const { getToken } = options;
|
|
11
|
+
const headerName = options.headerName ?? PROCAPTCHA_HEADER;
|
|
12
|
+
const isProtected = createPathMatcher(options.endpoints?.length ? options.endpoints : DEFAULT_ENDPOINTS);
|
|
13
|
+
return {
|
|
14
|
+
id: "procaptcha",
|
|
15
|
+
$InferServerPlugin: {},
|
|
16
|
+
fetchPlugins: getToken
|
|
17
|
+
? [
|
|
18
|
+
{
|
|
19
|
+
id: "procaptcha",
|
|
20
|
+
name: "procaptcha",
|
|
21
|
+
hooks: {
|
|
22
|
+
onRequest: async (context) => {
|
|
23
|
+
if (context.headers.has(headerName) ||
|
|
24
|
+
!isProtected(authPathOf(context.url, context.baseURL))) {
|
|
25
|
+
return context;
|
|
26
|
+
}
|
|
27
|
+
const token = await getToken();
|
|
28
|
+
if (token) {
|
|
29
|
+
context.headers.set(headerName, token);
|
|
30
|
+
}
|
|
31
|
+
return context;
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
]
|
|
36
|
+
: [],
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEtE,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAejE,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAChC,KAAa,EACb,aAAqB,iBAAiB,EACb,EAAE,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AAEvD,MAAM,UAAU,GAAG,CAAC,GAAiB,EAAE,OAA2B,EAAU,EAAE;IAC7E,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IACtE,OAAO,iBAAiB,CAAC,UAAU,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AACzD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,UAAmC,EAAE,EAAE,EAAE;IACzE,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IAC7B,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,iBAAiB,CAAC;IAC3D,MAAM,WAAW,GAAG,iBAAiB,CACpC,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,CACjE,CAAC;IAEF,OAAO;QACN,EAAE,EAAE,YAAY;QAChB,kBAAkB,EAAE,EAAmC;QACvD,YAAY,EAAE,QAAQ;YACrB,CAAC,CAAC;gBACA;oBACC,EAAE,EAAE,YAAY;oBAChB,IAAI,EAAE,YAAY;oBAClB,KAAK,EAAE;wBACN,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;4BAC5B,IACC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;gCAC/B,CAAC,WAAW,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,EACrD,CAAC;gCACF,OAAO,OAAO,CAAC;4BAChB,CAAC;4BACD,MAAM,KAAK,GAAG,MAAM,QAAQ,EAAE,CAAC;4BAC/B,IAAI,KAAK,EAAE,CAAC;gCACX,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;4BACxC,CAAC;4BACD,OAAO,OAAO,CAAC;wBAChB,CAAC;qBACD;iBACD;aACD;YACF,CAAC,CAAC,EAAE;KAC4B,CAAC;AACpC,CAAC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const PROCAPTCHA_SITEVERIFY_URL = "https://api.prosopo.io/siteverify";
|
|
2
|
+
export declare const PROCAPTCHA_HEADER = "x-captcha-response";
|
|
3
|
+
export declare const DEFAULT_ENDPOINTS: readonly string[];
|
|
4
|
+
export declare const DEFAULT_TIMEOUT_MS = 10000;
|
|
5
|
+
export declare const PROCAPTCHA_ERROR_CODES: {
|
|
6
|
+
PROCAPTCHA_MISSING_RESPONSE: import("better-auth").RawError<"PROCAPTCHA_MISSING_RESPONSE">;
|
|
7
|
+
PROCAPTCHA_VERIFICATION_FAILED: import("better-auth").RawError<"PROCAPTCHA_VERIFICATION_FAILED">;
|
|
8
|
+
PROCAPTCHA_SERVICE_UNAVAILABLE: import("better-auth").RawError<"PROCAPTCHA_SERVICE_UNAVAILABLE">;
|
|
9
|
+
PROCAPTCHA_UNKNOWN_ERROR: import("better-auth").RawError<"PROCAPTCHA_UNKNOWN_ERROR">;
|
|
10
|
+
};
|
|
11
|
+
export type ProcaptchaErrorCode = keyof typeof PROCAPTCHA_ERROR_CODES;
|
|
12
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,yBAAyB,sCAAsC,CAAC;AAE7E,eAAO,MAAM,iBAAiB,uBAAuB,CAAC;AAEtD,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAI9C,CAAC;AAEF,eAAO,MAAM,kBAAkB,QAAS,CAAC;AAEzC,eAAO,MAAM,sBAAsB;;;;;CAKjC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,MAAM,OAAO,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineErrorCodes } from "better-auth";
|
|
2
|
+
export const PROCAPTCHA_SITEVERIFY_URL = "https://api.prosopo.io/siteverify";
|
|
3
|
+
export const PROCAPTCHA_HEADER = "x-captcha-response";
|
|
4
|
+
export const DEFAULT_ENDPOINTS = [
|
|
5
|
+
"/sign-up/email",
|
|
6
|
+
"/sign-in/email",
|
|
7
|
+
"/request-password-reset",
|
|
8
|
+
];
|
|
9
|
+
export const DEFAULT_TIMEOUT_MS = 10_000;
|
|
10
|
+
export const PROCAPTCHA_ERROR_CODES = defineErrorCodes({
|
|
11
|
+
PROCAPTCHA_MISSING_RESPONSE: "Missing Procaptcha response",
|
|
12
|
+
PROCAPTCHA_VERIFICATION_FAILED: "Procaptcha verification failed",
|
|
13
|
+
PROCAPTCHA_SERVICE_UNAVAILABLE: "Procaptcha service unavailable",
|
|
14
|
+
PROCAPTCHA_UNKNOWN_ERROR: "Something went wrong",
|
|
15
|
+
});
|
|
16
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,CAAC,MAAM,yBAAyB,GAAG,mCAAmC,CAAC;AAE7E,MAAM,CAAC,MAAM,iBAAiB,GAAG,oBAAoB,CAAC;AAEtD,MAAM,CAAC,MAAM,iBAAiB,GAAsB;IACnD,gBAAgB;IAChB,gBAAgB;IAChB,yBAAyB;CACzB,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAEzC,MAAM,CAAC,MAAM,sBAAsB,GAAG,gBAAgB,CAAC;IACtD,2BAA2B,EAAE,6BAA6B;IAC1D,8BAA8B,EAAE,gCAAgC;IAChE,8BAA8B,EAAE,gCAAgC;IAChE,wBAAwB,EAAE,sBAAsB;CAChD,CAAC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { AuthContext } from "better-auth";
|
|
2
|
+
export { DEFAULT_ENDPOINTS, PROCAPTCHA_ERROR_CODES, PROCAPTCHA_HEADER, PROCAPTCHA_SITEVERIFY_URL, type ProcaptchaErrorCode, } from "./constants.js";
|
|
3
|
+
export { verifyProcaptchaToken, type SiteVerifyErrorResponse, type SiteVerifyRequestBody, type SiteVerifyResponse, type VerifyResult, type VerifyTokenParams, } from "./siteverify.js";
|
|
4
|
+
export interface ProcaptchaOptions {
|
|
5
|
+
secretKey: string;
|
|
6
|
+
endpoints?: readonly string[];
|
|
7
|
+
siteVerifyURL?: string;
|
|
8
|
+
headerName?: string;
|
|
9
|
+
sendIP?: boolean;
|
|
10
|
+
sendEmailDomain?: boolean;
|
|
11
|
+
maxScore?: number;
|
|
12
|
+
timeoutMs?: number;
|
|
13
|
+
fetch?: typeof fetch;
|
|
14
|
+
}
|
|
15
|
+
export declare const procaptcha: (options: ProcaptchaOptions) => {
|
|
16
|
+
id: "procaptcha";
|
|
17
|
+
$ERROR_CODES: {
|
|
18
|
+
PROCAPTCHA_MISSING_RESPONSE: import("better-auth").RawError<"PROCAPTCHA_MISSING_RESPONSE">;
|
|
19
|
+
PROCAPTCHA_VERIFICATION_FAILED: import("better-auth").RawError<"PROCAPTCHA_VERIFICATION_FAILED">;
|
|
20
|
+
PROCAPTCHA_SERVICE_UNAVAILABLE: import("better-auth").RawError<"PROCAPTCHA_SERVICE_UNAVAILABLE">;
|
|
21
|
+
PROCAPTCHA_UNKNOWN_ERROR: import("better-auth").RawError<"PROCAPTCHA_UNKNOWN_ERROR">;
|
|
22
|
+
};
|
|
23
|
+
onRequest: (request: Request, ctx: AuthContext) => Promise<{
|
|
24
|
+
response: Response;
|
|
25
|
+
} | undefined>;
|
|
26
|
+
options: ProcaptchaOptions;
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACX,WAAW,EAGX,MAAM,aAAa,CAAC;AAarB,OAAO,EACN,iBAAiB,EACjB,sBAAsB,EACtB,iBAAiB,EACjB,yBAAyB,EACzB,KAAK,mBAAmB,GACxB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACN,qBAAqB,EACrB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,KAAK,iBAAiB,GACtB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,iBAAiB;IAEjC,SAAS,EAAE,MAAM,CAAC;IAOlB,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAE9B,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,UAAU,CAAC,EAAE,MAAM,CAAC;IAOpB,MAAM,CAAC,EAAE,OAAO,CAAC;IAOjB,eAAe,CAAC,EAAE,OAAO,CAAC;IAM1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACrB;AA8CD,eAAO,MAAM,UAAU,YAAa,iBAAiB;;;;;;;;yBAUzC,OAAO,OACX,WAAW,KACd,OAAO,CAAC;QAAE,QAAQ,EAAE,QAAQ,CAAA;KAAE,GAAG,SAAS,CAAC;;CAgE/C,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { getIP } from "better-auth/api";
|
|
2
|
+
import { DEFAULT_ENDPOINTS, DEFAULT_TIMEOUT_MS, PROCAPTCHA_ERROR_CODES, PROCAPTCHA_HEADER, PROCAPTCHA_SITEVERIFY_URL, } from "./constants.js";
|
|
3
|
+
import { createPathMatcher, normalizeAuthPath } from "./path.js";
|
|
4
|
+
import { verifyProcaptchaToken } from "./siteverify.js";
|
|
5
|
+
export { DEFAULT_ENDPOINTS, PROCAPTCHA_ERROR_CODES, PROCAPTCHA_HEADER, PROCAPTCHA_SITEVERIFY_URL, } from "./constants.js";
|
|
6
|
+
export { verifyProcaptchaToken, } from "./siteverify.js";
|
|
7
|
+
const errorResponse = (code, status) => ({
|
|
8
|
+
response: Response.json({ code, message: PROCAPTCHA_ERROR_CODES[code].message }, { status }),
|
|
9
|
+
});
|
|
10
|
+
const resolveClientIP = (request, options) => getIP(request, {
|
|
11
|
+
...options,
|
|
12
|
+
advanced: {
|
|
13
|
+
...options.advanced,
|
|
14
|
+
ipAddress: { ...options.advanced?.ipAddress, ipv6Subnet: 128 },
|
|
15
|
+
},
|
|
16
|
+
}) ?? undefined;
|
|
17
|
+
const readEmailDomain = async (request) => {
|
|
18
|
+
if (!request.headers.get("content-type")?.includes("application/json")) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const body = await request.clone().json();
|
|
23
|
+
if (typeof body !== "object" || body === null || !("email" in body)) {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
const { email } = body;
|
|
27
|
+
if (typeof email !== "string") {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
const domain = email.slice(email.lastIndexOf("@") + 1).trim();
|
|
31
|
+
return email.includes("@") && domain ? domain.toLowerCase() : undefined;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
export const procaptcha = (options) => {
|
|
38
|
+
const isProtected = createPathMatcher(options.endpoints?.length ? options.endpoints : DEFAULT_ENDPOINTS);
|
|
39
|
+
const headerName = options.headerName ?? PROCAPTCHA_HEADER;
|
|
40
|
+
return {
|
|
41
|
+
id: "procaptcha",
|
|
42
|
+
$ERROR_CODES: PROCAPTCHA_ERROR_CODES,
|
|
43
|
+
onRequest: async (request, ctx) => {
|
|
44
|
+
const path = normalizeAuthPath(new URL(request.url).pathname, ctx.options.basePath ?? "/api/auth");
|
|
45
|
+
if (!isProtected(path)) {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
if (!options.secretKey) {
|
|
49
|
+
ctx.logger.error("Procaptcha: secretKey is not configured");
|
|
50
|
+
return errorResponse("PROCAPTCHA_UNKNOWN_ERROR", 500);
|
|
51
|
+
}
|
|
52
|
+
const token = request.headers.get(headerName);
|
|
53
|
+
if (!token) {
|
|
54
|
+
return errorResponse("PROCAPTCHA_MISSING_RESPONSE", 400);
|
|
55
|
+
}
|
|
56
|
+
const ip = options.sendIP === false
|
|
57
|
+
? undefined
|
|
58
|
+
: resolveClientIP(request, ctx.options);
|
|
59
|
+
const email = options.sendEmailDomain
|
|
60
|
+
? await readEmailDomain(request)
|
|
61
|
+
: undefined;
|
|
62
|
+
const result = await verifyProcaptchaToken({
|
|
63
|
+
secretKey: options.secretKey,
|
|
64
|
+
token,
|
|
65
|
+
...(ip ? { ip } : {}),
|
|
66
|
+
...(email ? { email } : {}),
|
|
67
|
+
siteVerifyURL: options.siteVerifyURL ?? PROCAPTCHA_SITEVERIFY_URL,
|
|
68
|
+
timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
69
|
+
...(options.fetch ? { fetch: options.fetch } : {}),
|
|
70
|
+
});
|
|
71
|
+
if (result.outcome === "error") {
|
|
72
|
+
ctx.logger.error("Procaptcha siteverify failed", {
|
|
73
|
+
status: result.status,
|
|
74
|
+
key: result.key,
|
|
75
|
+
message: result.message,
|
|
76
|
+
});
|
|
77
|
+
return result.transient
|
|
78
|
+
? errorResponse("PROCAPTCHA_SERVICE_UNAVAILABLE", 503)
|
|
79
|
+
: errorResponse("PROCAPTCHA_UNKNOWN_ERROR", 500);
|
|
80
|
+
}
|
|
81
|
+
if (result.outcome === "rejected") {
|
|
82
|
+
return errorResponse("PROCAPTCHA_VERIFICATION_FAILED", 403);
|
|
83
|
+
}
|
|
84
|
+
if (options.maxScore !== undefined &&
|
|
85
|
+
result.score !== undefined &&
|
|
86
|
+
result.score > options.maxScore) {
|
|
87
|
+
return errorResponse("PROCAPTCHA_VERIFICATION_FAILED", 403);
|
|
88
|
+
}
|
|
89
|
+
return undefined;
|
|
90
|
+
},
|
|
91
|
+
options,
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/path.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,iBAAiB,aACnB,MAAM,YACN,MAAM,KACd,MAOF,CAAC;AAoDF,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;AAEpD,eAAO,MAAM,iBAAiB,cAClB,SAAS,MAAM,EAAE,KAC1B,WAUF,CAAC"}
|
package/dist/tsc/path.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export const normalizeAuthPath = (pathname, basePath) => {
|
|
2
|
+
const relative = basePath && pathname.startsWith(basePath)
|
|
3
|
+
? pathname.slice(basePath.length)
|
|
4
|
+
: pathname;
|
|
5
|
+
const collapsed = `/${relative}`.replace(/\/{2,}/g, "/");
|
|
6
|
+
return collapsed.length > 1 ? collapsed.replace(/\/$/, "") : collapsed;
|
|
7
|
+
};
|
|
8
|
+
const matchesSegment = (pattern, segment) => {
|
|
9
|
+
const parts = pattern.split("*");
|
|
10
|
+
if (parts.length === 1) {
|
|
11
|
+
return pattern === segment;
|
|
12
|
+
}
|
|
13
|
+
const first = parts[0] ?? "";
|
|
14
|
+
const last = parts[parts.length - 1] ?? "";
|
|
15
|
+
if (segment.length < first.length + last.length ||
|
|
16
|
+
!segment.startsWith(first) ||
|
|
17
|
+
!segment.endsWith(last)) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
let cursor = first.length;
|
|
21
|
+
const end = segment.length - last.length;
|
|
22
|
+
for (const part of parts.slice(1, -1)) {
|
|
23
|
+
const found = segment.indexOf(part, cursor);
|
|
24
|
+
if (found === -1 || found + part.length > end) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
cursor = found + part.length;
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
};
|
|
31
|
+
const matchesSegments = (patterns, segments) => {
|
|
32
|
+
const [pattern, ...restPatterns] = patterns;
|
|
33
|
+
if (pattern === undefined) {
|
|
34
|
+
return segments.length === 0;
|
|
35
|
+
}
|
|
36
|
+
if (pattern === "**") {
|
|
37
|
+
for (let skip = 0; skip <= segments.length; skip++) {
|
|
38
|
+
if (matchesSegments(restPatterns, segments.slice(skip))) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
const [segment, ...restSegments] = segments;
|
|
45
|
+
return (segment !== undefined &&
|
|
46
|
+
matchesSegment(pattern, segment) &&
|
|
47
|
+
matchesSegments(restPatterns, restSegments));
|
|
48
|
+
};
|
|
49
|
+
export const createPathMatcher = (endpoints) => {
|
|
50
|
+
const matchers = endpoints.map((endpoint) => {
|
|
51
|
+
if (!endpoint.includes("*")) {
|
|
52
|
+
return (path) => path === endpoint;
|
|
53
|
+
}
|
|
54
|
+
const patterns = endpoint.split("/");
|
|
55
|
+
return (path) => matchesSegments(patterns, path.split("/"));
|
|
56
|
+
});
|
|
57
|
+
return (path) => matchers.some((matches) => matches(path));
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path.js","sourceRoot":"","sources":["../../src/path.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { VerificationResponse } from "@prosopo/types";
|
|
2
|
+
export interface SiteVerifyRequestBody {
|
|
3
|
+
secret: string;
|
|
4
|
+
token: string;
|
|
5
|
+
ip?: string;
|
|
6
|
+
email?: string;
|
|
7
|
+
}
|
|
8
|
+
export type SiteVerifyResponse = Omit<VerificationResponse, "error" | "sessionId">;
|
|
9
|
+
export interface SiteVerifyErrorResponse {
|
|
10
|
+
error: {
|
|
11
|
+
code: number;
|
|
12
|
+
key: string;
|
|
13
|
+
message: string | unknown[];
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export type VerifyResult = {
|
|
17
|
+
outcome: "verified";
|
|
18
|
+
score?: number;
|
|
19
|
+
} | {
|
|
20
|
+
outcome: "rejected";
|
|
21
|
+
reason?: string;
|
|
22
|
+
score?: number;
|
|
23
|
+
} | {
|
|
24
|
+
outcome: "error";
|
|
25
|
+
transient: boolean;
|
|
26
|
+
status?: number;
|
|
27
|
+
key?: string;
|
|
28
|
+
message: string;
|
|
29
|
+
};
|
|
30
|
+
export interface VerifyTokenParams {
|
|
31
|
+
secretKey: string;
|
|
32
|
+
token: string;
|
|
33
|
+
ip?: string;
|
|
34
|
+
email?: string;
|
|
35
|
+
siteVerifyURL?: string;
|
|
36
|
+
timeoutMs?: number;
|
|
37
|
+
fetch?: typeof fetch;
|
|
38
|
+
}
|
|
39
|
+
export declare const verifyProcaptchaToken: ({ secretKey, token, ip, email, siteVerifyURL, timeoutMs, fetch: fetchImpl, }: VerifyTokenParams) => Promise<VerifyResult>;
|
|
40
|
+
//# sourceMappingURL=siteverify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"siteverify.d.ts","sourceRoot":"","sources":["../../src/siteverify.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAG3D,MAAM,WAAW,qBAAqB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,kBAAkB,GAAG,IAAI,CACpC,oBAAoB,EACpB,OAAO,GAAG,WAAW,CACrB,CAAC;AAEF,MAAM,WAAW,uBAAuB;IACvC,KAAK,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,EAAE,MAAM,CAAC;QACZ,OAAO,EAAE,MAAM,GAAG,OAAO,EAAE,CAAC;KAC5B,CAAC;CACF;AAED,MAAM,MAAM,YAAY,GACrB;IAAE,OAAO,EAAE,UAAU,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,OAAO,EAAE,UAAU,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACxD;IACA,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACf,CAAC;AAEL,MAAM,WAAW,iBAAiB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACrB;AA+BD,eAAO,MAAM,qBAAqB,iFAQ/B,iBAAiB,KAAG,OAAO,CAAC,YAAY,CA+D1C,CAAC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { DEFAULT_TIMEOUT_MS, PROCAPTCHA_SITEVERIFY_URL } from "./constants.js";
|
|
2
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3
|
+
const isSiteVerifyResponse = (value) => isRecord(value) &&
|
|
4
|
+
typeof value.status === "string" &&
|
|
5
|
+
typeof value.verified === "boolean" &&
|
|
6
|
+
(value.score === undefined || typeof value.score === "number") &&
|
|
7
|
+
(value.reason === undefined || typeof value.reason === "string");
|
|
8
|
+
const isSiteVerifyErrorResponse = (value) => isRecord(value) &&
|
|
9
|
+
isRecord(value.error) &&
|
|
10
|
+
typeof value.error.key === "string";
|
|
11
|
+
const readJson = async (response) => {
|
|
12
|
+
try {
|
|
13
|
+
const body = await response.json();
|
|
14
|
+
return body;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
const isTransientStatus = (status) => status === 429 || status >= 500;
|
|
21
|
+
export const verifyProcaptchaToken = async ({ secretKey, token, ip, email, siteVerifyURL = PROCAPTCHA_SITEVERIFY_URL, timeoutMs = DEFAULT_TIMEOUT_MS, fetch: fetchImpl = fetch, }) => {
|
|
22
|
+
const body = {
|
|
23
|
+
secret: secretKey,
|
|
24
|
+
token,
|
|
25
|
+
...(ip ? { ip } : {}),
|
|
26
|
+
...(email ? { email } : {}),
|
|
27
|
+
};
|
|
28
|
+
let response;
|
|
29
|
+
try {
|
|
30
|
+
response = await fetchImpl(siteVerifyURL, {
|
|
31
|
+
method: "POST",
|
|
32
|
+
headers: {
|
|
33
|
+
"Content-Type": "application/json",
|
|
34
|
+
Accept: "application/json",
|
|
35
|
+
},
|
|
36
|
+
body: JSON.stringify(body),
|
|
37
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
return {
|
|
42
|
+
outcome: "error",
|
|
43
|
+
transient: true,
|
|
44
|
+
message: error instanceof Error ? error.message : String(error),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const payload = await readJson(response);
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
const errorBody = isSiteVerifyErrorResponse(payload)
|
|
50
|
+
? payload.error
|
|
51
|
+
: undefined;
|
|
52
|
+
return {
|
|
53
|
+
outcome: "error",
|
|
54
|
+
transient: isTransientStatus(response.status),
|
|
55
|
+
status: response.status,
|
|
56
|
+
...(errorBody ? { key: errorBody.key } : {}),
|
|
57
|
+
message: typeof errorBody?.message === "string"
|
|
58
|
+
? errorBody.message
|
|
59
|
+
: `siteverify responded with HTTP ${response.status}`,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (!isSiteVerifyResponse(payload)) {
|
|
63
|
+
return {
|
|
64
|
+
outcome: "error",
|
|
65
|
+
transient: true,
|
|
66
|
+
status: response.status,
|
|
67
|
+
message: "siteverify returned an unexpected response body",
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const score = payload.score === undefined ? {} : { score: payload.score };
|
|
71
|
+
if (!payload.verified) {
|
|
72
|
+
return {
|
|
73
|
+
outcome: "rejected",
|
|
74
|
+
...(payload.reason ? { reason: payload.reason } : {}),
|
|
75
|
+
...score,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return { outcome: "verified", ...score };
|
|
79
|
+
};
|
|
80
|
+
//# sourceMappingURL=siteverify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"siteverify.js","sourceRoot":"","sources":["../../src/siteverify.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.unit.test.d.ts","sourceRoot":"","sources":["../../../src/tests/client.unit.test.ts"],"names":[],"mappings":""}
|