mirror of
https://github.com/Since-3/Kuma.git
synced 2026-10-12 19:51:17 +00:00
49 lines
1.8 KiB
TypeScript
49 lines
1.8 KiB
TypeScript
import { createHmac, timingSafeEqual } from "crypto";
|
|
|
|
/**
|
|
* Signierter Abmeldelink: Wer eine Werbe-Mail bekommt, soll sich ohne Anmeldung
|
|
* abmelden können. Das Token enthält Kunde und Studio und ist mit
|
|
* MARKETING_TOKEN_SECRET signiert, damit niemand fremde Einwilligungen
|
|
* widerrufen kann. Es läuft bewusst nicht ab - ein Abmeldelink aus einer alten
|
|
* Mail muss weiter funktionieren.
|
|
*/
|
|
|
|
function secret(): string {
|
|
const value = process.env.MARKETING_TOKEN_SECRET;
|
|
if (!value) throw new Error("MARKETING_TOKEN_SECRET ist nicht gesetzt");
|
|
return value;
|
|
}
|
|
|
|
function sign(payload: string): string {
|
|
return createHmac("sha256", secret()).update(payload).digest("base64url");
|
|
}
|
|
|
|
export function createUnsubscribeToken(userId: string, businessId: string): string {
|
|
const payload = `${userId}.${businessId}`;
|
|
return `${payload}.${sign(payload)}`;
|
|
}
|
|
|
|
export function verifyUnsubscribeToken(
|
|
token: string | null | undefined
|
|
): { userId: string; businessId: string } | null {
|
|
if (!token) return null;
|
|
const parts = token.split(".");
|
|
if (parts.length !== 3) return null;
|
|
const [userId, businessId, signature] = parts;
|
|
if (!userId || !businessId || !signature) return null;
|
|
|
|
const expected = Buffer.from(sign(`${userId}.${businessId}`));
|
|
const actual = Buffer.from(signature);
|
|
if (expected.length !== actual.length || !timingSafeEqual(expected, actual)) return null;
|
|
|
|
return { userId, businessId };
|
|
}
|
|
|
|
export function unsubscribePageUrl(baseUrl: string, token: string): string {
|
|
return `${baseUrl}/abmelden?t=${encodeURIComponent(token)}`;
|
|
}
|
|
|
|
/** Ziel für den List-Unsubscribe-Header (Ein-Klick-Abmeldung im Mailprogramm). */
|
|
export function unsubscribeApiUrl(baseUrl: string, token: string): string {
|
|
return `${baseUrl}/api/marketing/unsubscribe?t=${encodeURIComponent(token)}`;
|
|
}
|