diff options
| author | Adam Soltys <[email protected]> | 2026-03-27 23:41:08 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-03-27 23:41:08 -0700 |
| commit | ef06f2eb48581c201e62fc2cde27b106e898e54d (patch) | |
| tree | 67a8991ffdba15cd231dbbc5890f56ac3a7511f1 /lib/changeid.ts | |
| parent | 13372a9ee10a00ce3e17676198e97d2991b4855d (diff) | |
| download | coinos-server-ef06f2eb48581c201e62fc2cde27b106e898e54d.tar.gz coinos-server-ef06f2eb48581c201e62fc2cde27b106e898e54d.zip | |
lnurl proxy
Diffstat (limited to 'lib/changeid.ts')
| -rw-r--r-- | lib/changeid.ts | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/lib/changeid.ts b/lib/changeid.ts new file mode 100644 index 00000000..49d3a0fb --- /dev/null +++ b/lib/changeid.ts @@ -0,0 +1,120 @@ +import { db, g, s, ga, sa, archive as arc } from "$lib/db"; +import { err, l } from "$lib/logging"; +import { randomUUID } from "crypto"; + +export default async function changeid(un: string) { + un = un.toLowerCase(); + const id = await g(`user:${un}`); + if (!id) throw new Error(`user ${un} not found`); + + l(`SECURITY: rekeying ${un}, old id ${id}`); + + const nid = randomUUID(); + const user = await g(`user:${id}`); + if (!user) throw new Error(`user record ${id} not found`); + + user.id = nid; + user.password = "reset"; + + if (user.pubkey) { + await s(user.pubkey, nid); + await sa(user.pubkey, nid); + } + await s(`user:${un}`, nid); + await sa(`user:${un}`, nid); + await s(`user:${nid}`, user); + await sa(`user:${nid}`, user); + + const keys = [ + `credit:lightning:${id}`, + `credit:liquid:${id}`, + `${id}:invoices`, + `credit:bitcoin:${id}`, + `pending:${id}`, + `${id}:lastlen`, + `${id}:contacts`, + `${id}:accounts`, + `${id}:payments`, + `account:${id}`, + `balance:${id}`, + `user:${id}`, + ]; + + async function migrateKeys(client, get, set, label) { + for (const k of keys) { + const nk = k.replace(id, nid); + try { + if ( + k.includes("credit:") || + k.includes("balance:") || + k.includes("pending:") + ) { + const a = await get(k); + await client.incrBy(nk, parseInt(a) || 0); + await client.del(k); + } else if (k.includes(":invoices") || k.includes(":payments")) { + const arr = await client.lRange(k, 0, -1); + const narr = []; + for (const pid of arr) { + const ok = `${k.split(":")[1].slice(0, -1)}:${pid}`; + const o = await get(ok); + if (!o) continue; + o.id = pid; + o.uid = nid; + if (o.aid === id) o.aid = nid; + await set(ok, o); + narr.push(o); + } + + await client.del(k); + + for (const o of narr.sort((a, b) => b?.created - a?.created)) { + if (o) await client.rPush(nk, o.id); + } + } else if (k.includes("account:")) { + const acc = await get(k); + if (!acc) continue; + acc.id = nid; + await set(nk, acc); + await client.del(k); + } else if (k.includes("user:")) { + await client.del(k); + } else { + await client.rename(k, nk); + } + } catch (e: any) { + err(`changeid [${label}]`, k, e.message); + } + } + + await client.lRem(`${nid}:accounts`, 0, id); + await client.rPush(`${nid}:accounts`, nid); + } + + await migrateKeys(db, g, s, "main"); + await migrateKeys(arc, ga, sa, "arc"); + + const apps = await db.sMembers(`${id}:apps`); + for (const aid of apps) { + await db.del(`app:${aid}`); + } + await db.del(`${id}:apps`); + + // Update invoices that reference the old uid + for await (const k of db.scanIterator({ MATCH: "invoice:*" })) { + try { + const inv = await g(k); + if (!inv || typeof inv === "string") continue; + let changed = false; + if (inv.uid === id) { inv.uid = nid; changed = true; } + if (inv.aid === id) { inv.aid = nid; changed = true; } + if (changed) { + await s(k, inv); + l("changeid: updated invoice", k); + } + } catch (e) {} + } + + l(`SECURITY: rekeyed ${un} from ${id} to ${nid}`); + return nid; +} |
