1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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;
}
|