import { AddonInput, BaseAddon, IsAddon } from "@certd/lib-server"; import { CaptchaRequest, ICaptchaAddon } from "../api.js"; @IsAddon({ addonType: "captcha", name: "cfTurnstile", title: "Cloudflare Turnstile", desc: "谨慎使用,国内被墙了", showTest: false, }) export class CfTurnstileCaptcha extends BaseAddon implements ICaptchaAddon { @AddonInput({ title: "站点密钥", component: { placeholder: "SiteKey", }, helper: "[Cloudflare Turnstile](https://www.cloudflare.com/zh-cn/application-services/products/turnstile/) -> 添加小组件", required: true, }) siteKey = ""; @AddonInput({ title: "密钥", component: { placeholder: "SecretKey", }, required: true, }) secretKey = ""; async onValidate(data?: any, req?: CaptchaRequest) { if (!data) { return false; } const { token } = data; const { remoteIp } = req; const formData = new FormData(); formData.append("secret", this.secretKey); formData.append("response", token); formData.append("remoteip", remoteIp); const res = await this.http.request({ url: "https://challenges.cloudflare.com/turnstile/v0/siteverify", method: "POST", headers: { "Content-Type": "multipart/form-data", }, data: formData, }); if (res.success) { // Token is valid - process the form return true; } else { // Token is invalid - reject the submission const errorMessage = "Cloudflare Turnstile 校验失败:" + res["error-codes"].join(", "); this.logger.error(errorMessage); throw new Error(errorMessage); } } async getCaptcha(): Promise { return { siteKey: this.siteKey, }; } }