24 lines · 1.5 KB
import { html } from "./static";

function escapeHtml(value: string): string {
  return value.replace(/[&<>"']/g, (char) => `&#${char.charCodeAt(0)};`);
}

/** Copies the claim token from the URL fragment into the form, then drops it from the address bar. */
const CLAIM_SCRIPT = `var m=/(?:^#|&)token=([^&]*)/.exec(location.hash);if(m){document.getElementById("token").value=decodeURIComponent(m[1]);history.replaceState(null,"",location.pathname)}`;

export function claimPage(viewerName: string, legacyToken: string, nonce: string): Response {
  return html(
    200,
    `<!doctype html><meta name="viewport" content="width=device-width"><title>Claim scratch site</title>
<body style="font-family:system-ui;max-width:30rem;margin:4rem auto;line-height:1.5"><h1 style="font-size:1.25rem">Claim scratch site</h1><p>Claiming moves this scratch site to @${escapeHtml(viewerName)}, removes its expiry and gives it a new address.</p>
<form method="post"><p><label>Claim token <input id="token" type="password" name="token" required autocomplete="off" value="${escapeHtml(legacyToken)}"></label></p>
<p><label><input type="checkbox" name="public"> If the site has a scratch repository, make it public (a private repository keeps the site behind sign-in)</label></p>
<button>Claim site</button></form><script nonce="${nonce}">${CLAIM_SCRIPT}</script></body>`,
    {
      "content-security-policy": `default-src 'none'; style-src 'unsafe-inline'; script-src 'nonce-${nonce}'; form-action 'self'; frame-ancestors 'none'`,
      "referrer-policy": "no-referrer",
    },
  );
}