mirror of
https://github.com/XFox111/my-website.git
synced 2026-04-22 07:28:01 +03:00
!feat: added Cloudflare Turnstile captcha to the contact form
feat: added contact form disclaimer
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
import { canonicalName } from "@/_data/metadata";
|
||||
import nodemailer from "nodemailer";
|
||||
import { z } from "zod";
|
||||
import { verifyTurnstile } from "./turnstile";
|
||||
|
||||
const schema = z.object({
|
||||
email: z.string().email().max(60),
|
||||
@@ -24,6 +25,32 @@ const mailClient = nodemailer.createTransport({
|
||||
|
||||
export default async function sendInquiry(_: FormStatus, formData: FormData): Promise<FormStatus>
|
||||
{
|
||||
const cfToken = formData.get("cf-turnstile-response")?.toString();
|
||||
|
||||
if (!cfToken)
|
||||
return {
|
||||
status: "error",
|
||||
message: "You must complete the challenge"
|
||||
};
|
||||
|
||||
const [isValid, error] = await verifyTurnstile(cfToken);
|
||||
|
||||
if (!isValid)
|
||||
{
|
||||
if (error === "timeout-or-duplicate")
|
||||
return {
|
||||
status: "error",
|
||||
message: "Challenge has expired. Try again"
|
||||
};
|
||||
|
||||
console.error(error);
|
||||
|
||||
return {
|
||||
status: "error",
|
||||
message: "Something went wrong"
|
||||
};
|
||||
}
|
||||
|
||||
const { success, data } = schema.safeParse({
|
||||
email: formData.get("email"),
|
||||
subject: formData.get("subject"),
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
"use server";
|
||||
|
||||
import { headers } from "next/headers";
|
||||
|
||||
export async function getSitekey(): Promise<string | undefined>
|
||||
{
|
||||
return process.env.CF_SITEKEY;
|
||||
}
|
||||
|
||||
export async function verifyTurnstile(token: string): Promise<[false, TurnstileErrorType] | [true]>
|
||||
{
|
||||
if (!process.env.CF_SECRET)
|
||||
return [true];
|
||||
|
||||
const formData = new FormData();
|
||||
|
||||
console.log(headers().get("CF-Connecting-IP"));
|
||||
|
||||
formData.append("secret", process.env.CF_SECRET);
|
||||
formData.append("response", token);
|
||||
formData.append("remoteip", headers().get("CF-Connecting-IP") ?? "");
|
||||
|
||||
const response = await fetch("https://challenges.cloudflare.com/turnstile/v0/siteverify",
|
||||
{
|
||||
body: formData,
|
||||
method: "POST"
|
||||
}
|
||||
);
|
||||
|
||||
const result: TurnstileValidationResponse = await response.json();
|
||||
|
||||
if (result.success)
|
||||
return [result.success];
|
||||
else
|
||||
return [result.success, result["error-codes"][0]];
|
||||
}
|
||||
|
||||
export type TurnstileValidationResponse =
|
||||
{
|
||||
success: boolean;
|
||||
challenge_ts: string;
|
||||
hostname: string;
|
||||
"error-codes": TurnstileErrorType[];
|
||||
action: string;
|
||||
cdata: `sessionid-${string}`;
|
||||
metadata: Record<string, string>;
|
||||
};
|
||||
|
||||
export type TurnstileErrorType =
|
||||
"missing-input-secret" | "invalid-input-secret" | "missing-input-response" |
|
||||
"invalid-input-response" | "bad-request" | "timeout-or-duplicate" | "internal-error";
|
||||
Reference in New Issue
Block a user