Vollstaendige Next.js/Prisma-E-Commerce-Anwendung fuer eine Imkerei: Shop, Warenkorb, Stripe-Checkout, Kundenkonto mit 2FA, Admin-Bereich (Produkte, Ernten, Chargen, Bestellungen, Gutscheine, admin-editierbare Website-Inhalte), i18n (DE/EN), Rate-Limiting/CSP/Audit-Log-Haertung, PostgreSQL- und MySQL-Unterstuetzung ueber austauschbare Prisma- Treiber-Adapter, Unit-/Komponenten-/E2E-Tests.
34 lines
1.4 KiB
TypeScript
34 lines
1.4 KiB
TypeScript
import { randomBytes, createHash } from "node:crypto";
|
|
import { prisma } from "@/lib/prisma";
|
|
import { sendMail } from "@/lib/mail";
|
|
import { emailVerificationEmail } from "@/lib/email-templates";
|
|
import { getBaseUrl } from "@/lib/url";
|
|
import { getLocale } from "@/i18n/locale";
|
|
|
|
const VERIFICATION_TOKEN_TTL_MS = 24 * 60 * 60 * 1000; // 24 Stunden
|
|
|
|
export function hashVerificationToken(token: string): string {
|
|
return createHash("sha256").update(token).digest("hex");
|
|
}
|
|
|
|
/**
|
|
* Erzeugt einen einmaligen E-Mail-Bestaetigungs-Token und verschickt den
|
|
* Link. Wird nach der Selbst-Registrierung aufgerufen sowie ueber den
|
|
* "Link erneut senden"-Button auf /konto, solange das Konto unbestaetigt ist.
|
|
*/
|
|
export async function createAndSendVerificationEmail(customer: { id: string; email: string }): Promise<void> {
|
|
const rawToken = randomBytes(32).toString("hex");
|
|
await prisma.emailVerificationToken.deleteMany({ where: { customerId: customer.id, usedAt: null } });
|
|
await prisma.emailVerificationToken.create({
|
|
data: {
|
|
customerId: customer.id,
|
|
tokenHash: hashVerificationToken(rawToken),
|
|
expiresAt: new Date(Date.now() + VERIFICATION_TOKEN_TTL_MS),
|
|
},
|
|
});
|
|
|
|
const verifyUrl = `${getBaseUrl()}/api/konto/email-bestaetigen?token=${rawToken}`;
|
|
const { subject, html, text } = await emailVerificationEmail(await getLocale(), verifyUrl);
|
|
await sendMail({ to: customer.email, subject, html, text });
|
|
}
|