@dotrino/identity 0.43.0 → 0.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/vault/core.js +36 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotrino/identity",
3
- "version": "0.43.0",
3
+ "version": "0.45.0",
4
4
  "description": "Identidad y rating de usuarios compartidos entre apps de Dotrino (vault iframe + postMessage)",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/vault/core.js CHANGED
@@ -347,6 +347,13 @@ export async function createIdentityCore ({ kv: rawKv, peers, makeSync = null, k
347
347
  */
348
348
  const wipeVaultLink = () => {
349
349
  try { kv.removeItem(VAULT_CERT_STORAGE); kv.removeItem(VAULT_DEVICE_STORAGE) } catch (_) {}
350
+ // Y el ACTA. Sin esto el aparato borraba su enlace con la bóveda pero seguía
351
+ // enseñando el perfil del que acababan de echarlo —con sus miembros y sus permisos—,
352
+ // porque la copia local se quedaba ahí y ya no podía refrescarla (está revocado). El
353
+ // dueño lo describió exacto: «el device ni por enterado de que está fuera».
354
+ // Queda como lo que es: un dispositivo sin cuenta, que puede crear la suya o
355
+ // emparejarse otra vez.
356
+ try { kv.removeItem(ACTA_STORAGE) } catch (_) {}
350
357
  emitVault({ phase: 'revoked' })
351
358
  }
352
359
 
@@ -472,6 +479,33 @@ export async function createIdentityCore ({ kv: rawKv, peers, makeSync = null, k
472
479
  return true
473
480
  }
474
481
 
482
+ /**
483
+ * QUITAR UN APARATO, entero y de una vez.
484
+ *
485
+ * Esto era media operación repetida en dos sitios, y cada mitad fallaba a su manera:
486
+ * la consola web sacaba al miembro del acta pero le dejaba los certificados vivos
487
+ * (seguía pudiendo entrar y firmar), y la pantalla del PC le retiraba los
488
+ * certificados pero lo dejaba dentro del acta (seguía apareciendo en la lista de la
489
+ * web, «un dispositivo que en la bóveda ya no existe»). Las dos caras del mismo acto
490
+ * van juntas o no van:
491
+ *
492
+ * 1. fuera del acta → deja de ser miembro y deja de figurar en ninguna lista;
493
+ * 2. fuera los papeles → ningún certificado suyo sirve ya para entrar;
494
+ * 3. clave nueva → no podrá abrir el contenido NUEVO. Lo que ya leyó no
495
+ * vuelve: eso no se puede deshacer y no se promete.
496
+ */
497
+ async function removeDevice (pub) {
498
+ if (!pub || typeof pub !== 'string') throw new Error('pub (device pubkey) required')
499
+ // Si no es miembro (papeles de antes de que existiera el acta), no es un error: se
500
+ // le quitan igual los certificados, que es lo que de verdad le abría la puerta.
501
+ const isMember = (loadActa().members || []).some((m) => m.pub === pub)
502
+ const acta = isMember ? await sealChanges([{ op: 'remove', pub }]) : loadActa()
503
+ const nonces = revokePriorCertsFor(pub, null)
504
+ let rotated = null
505
+ try { rotated = await rotateCek() } catch (_) {}
506
+ return { ok: true, seq: acta.seq, nonces, rotated, revokedAt: Date.now() }
507
+ }
508
+
475
509
  /** Rota la clave: generación nueva envuelta SOLO a los miembros actuales. */
476
510
  async function rotateCek () {
477
511
  const acta = loadActa()
@@ -1092,8 +1126,7 @@ export async function createIdentityCore ({ kv: rawKv, peers, makeSync = null, k
1092
1126
  */
1093
1127
  async revokeDevice ({ sub }) {
1094
1128
  if (!sub || typeof sub !== 'string') throw new Error('sub (device pubkey) required')
1095
- const nonces = revokePriorCertsFor(sub, null)
1096
- return { ok: true, nonces, revokedAt: Date.now() }
1129
+ return removeDevice(sub)
1097
1130
  },
1098
1131
 
1099
1132
  async revokeDelegation ({ nonce }) {
@@ -1281,12 +1314,7 @@ export async function createIdentityCore ({ kv: rawKv, peers, makeSync = null, k
1281
1314
  },
1282
1315
 
1283
1316
  async removeMember ({ pub } = {}) {
1284
- const acta = await sealChanges([{ op: 'remove', pub }])
1285
- // Expulsar rota la clave: el que sale no podrá abrir el contenido NUEVO. Lo que ya
1286
- // leyó no vuelve — eso no se puede deshacer y no se promete.
1287
- let rotated = null
1288
- try { rotated = await rotateCek() } catch (_) {}
1289
- return { ok: true, seq: acta.seq, rotated }
1317
+ return removeDevice(pub)
1290
1318
  },
1291
1319
 
1292
1320
  /**