68 lines · 3.3 KB
import { isNotificationCategory, CATEGORY_INFO } from "~/lib/notification-categories";
import { enforceRateLimit, requestIp } from "../limits";
import { canUnsubscribe, unsubscribe, userForUnsubscribeToken } from "./prefs";
import type { UnsubscribeTarget } from "./prefs";

export const UNSUBSCRIBE_PATH = "/email/unsubscribe";
const HTML_ESCAPES: Record<string, string> = { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" };

function escapeHtml(value: string): string {
  return value.replace(/[&<>"']/g, (char) => HTML_ESCAPES[char] ?? char);
}

function parseTarget(value: string | null): UnsubscribeTarget | null {
  if (value === "participating" || value === "watching") return value;
  return value && isNotificationCategory(value) ? value : null;
}

function targetLabel(target: UnsubscribeTarget): string {
  if (target === "participating") return "participating and @mention";
  if (target === "watching") return "watched repository";
  return CATEGORY_INFO[target].label.toLowerCase();
}

function page(body: string, status = 200): Response {
  return new Response(
    `<!doctype html><html><head><meta name="viewport" content="width=device-width"><title>Unsubscribe</title></head>
<body style="font-family:system-ui;background:#09090b;color:#e4e4e7;padding:32px"><div style="max-width:480px;margin:0 auto">${body}
<p><a href="/settings/notifications" style="color:#fb923c">Manage notification settings</a></p></div></body></html>`,
    {
      status,
      headers: {
        "content-type": "text/html; charset=utf-8",
        "content-security-policy": "default-src 'none'; style-src 'unsafe-inline'; form-action 'self'",
        "referrer-policy": "no-referrer",
      },
    },
  );
}

/**