| … | … | @@ -138,10 +138,29 @@ export function createApplyFunction (opts = {}) { |
| 138 | 138 | const existing = await b.get(key) |
| 139 | 139 | if (!existing) continue |
| 140 | 140 | |
| 141 | | // Remove identity index entries |
| 142 | | for (const id of (existing.value.identities || [])) { |
| 141 | const user = existing.value |
| 142 | // Remove identity index entries AND the identity records + their |
| 143 | // reverse indexes FROM THE VIEW. Since the view-migration these |
| 144 | // records live in the view; deleteUserCascade only cleaned the |
| 145 | // legacy db, so the view's pubkey/sshkey/noisekey indexes |
| 146 | // survived a delete. Mirror REGISTER_IDENTITY's index writes in |
| 147 | // reverse so a cascade is complete and replicates to peers. |
| 148 | for (const id of (user.identities || [])) { |
| 143 | 149 | await b.del(`${prefix}user-identity:${id}`) |
| 150 | const idEntry = await b.get(`${prefix}identity:${id}`) |
| 151 | if (idEntry) { |
| 152 | const idRec = idEntry.value |
| 153 | if (idRec.publicKey) await b.del(`${prefix}pubkey:${idRec.publicKey}`) |
| 154 | if (idRec.method === 'ssh-key' && idRec.credentials && idRec.credentials.fingerprint) { |
| 155 | await b.del(`${prefix}sshkey:${idRec.credentials.fingerprint}`) |
| 156 | } |
| 157 | if (idRec.method === 'noise-key' && idRec.credentials && idRec.credentials.publicKey) { |
| 158 | await b.del(`${prefix}noisekey:${idRec.credentials.publicKey}`) |
| 159 | } |
| 160 | await b.del(`${prefix}identity:${id}`) |
| 161 | } |
| 144 | 162 | } |
| 163 | if (user.username) await b.del(`${prefix}username:${user.username}`) |
| 145 | 164 | await b.del(key) |
| 146 | 165 | break |
| 147 | 166 | } |
| … | … | @@ -186,6 +205,19 @@ export function createApplyFunction (opts = {}) { |
| 186 | 205 | await b.put(key, user) |
| 187 | 206 | } |
| 188 | 207 | } |
| 208 | // Stamp the owning userId onto the identity record IN THE VIEW. |
| 209 | // Since the view-migration, identity records live in the view and |
| 210 | // getIdentity reads it first; the registry method only wrote |
| 211 | // userId to the legacy db, leaving the view record without it |
| 212 | // (cross-daemon link ownership invisible). Idempotent. |
| 213 | const idKey = `${prefix}identity:${op.identityId}` |
| 214 | const idEntry = await b.get(idKey) |
| 215 | if (idEntry && idEntry.value.userId !== op.userId) { |
| 216 | const idRec = idEntry.value |
| 217 | idRec.userId = op.userId |
| 218 | idRec.updatedAt = Date.now() |
| 219 | await b.put(idKey, idRec) |
| 220 | } |
| 189 | 221 | break |
| 190 | 222 | } |
| 191 | 223 | |