aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/routes/(app)/migrate/+page.server.ts28
1 files changed, 28 insertions, 0 deletions
diff --git a/src/routes/(app)/migrate/+page.server.ts b/src/routes/(app)/migrate/+page.server.ts
index f1964d1b..48ae6a96 100644
--- a/src/routes/(app)/migrate/+page.server.ts
+++ b/src/routes/(app)/migrate/+page.server.ts
@@ -1,8 +1,33 @@
import { auth, post } from "$lib/utils";
import { redirect } from "@sveltejs/kit";
+import { env } from "$env/dynamic/private";
const REGISTRAR = "https://names.coinos.io";
+// Tell the v3 registrar who may claim the released name. This session — the
+// old account's authenticated login — is the proof of ownership; the
+// registrar's own claim guard otherwise only accepts a claim signed by the
+// old account's nostr key, which a v3 wallet never has.
+async function grantMigration(username: string, to: string) {
+ if (!env.MIGRATE_TOKEN) throw new Error("migration hand-off isn't configured");
+ let lastErr;
+ for (let i = 0; i < 3; i++) {
+ try {
+ const r = await fetch(`${REGISTRAR}/migrate-grant`, {
+ method: "POST",
+ headers: { "content-type": "application/json", authorization: `Bearer ${env.MIGRATE_TOKEN}` },
+ body: JSON.stringify({ name: username, to }),
+ });
+ if (r.ok) return;
+ lastErr = new Error((await r.json().catch(() => null))?.error || `registrar said ${r.status}`);
+ } catch (e) {
+ lastErr = e;
+ }
+ await new Promise((res) => setTimeout(res, 1500));
+ }
+ throw lastErr;
+}
+
// An invoice from the v3 registrar for this address and amount (LNURL-pay).
async function invoiceFor(address: string, sats: number) {
const [name, domain] = String(address).split("@");
@@ -66,6 +91,9 @@ export const actions = {
// as it is — same username, same history, still usable here; the
// registrar just becomes the answer for incoming payments.
await post("/user", { migrated: true, ...(pin ? { pin } : {}) }, auth(cookies));
+ // …and tell the registrar which v3 identity the name now belongs
+ // to, or their claim over there can never pass the squat guard.
+ await grantMigration(username, to);
return { ok: true, sent, released: username };
} catch (e) {
const msg = e && typeof e === "object" && "message" in e ? String(e.message) : String(e);