@dotrino/identity 0.44.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 +29 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotrino/identity",
3
- "version": "0.44.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
@@ -479,6 +479,33 @@ export async function createIdentityCore ({ kv: rawKv, peers, makeSync = null, k
479
479
  return true
480
480
  }
481
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
+
482
509
  /** Rota la clave: generación nueva envuelta SOLO a los miembros actuales. */
483
510
  async function rotateCek () {
484
511
  const acta = loadActa()
@@ -1099,8 +1126,7 @@ export async function createIdentityCore ({ kv: rawKv, peers, makeSync = null, k
1099
1126
  */
1100
1127
  async revokeDevice ({ sub }) {
1101
1128
  if (!sub || typeof sub !== 'string') throw new Error('sub (device pubkey) required')
1102
- const nonces = revokePriorCertsFor(sub, null)
1103
- return { ok: true, nonces, revokedAt: Date.now() }
1129
+ return removeDevice(sub)
1104
1130
  },
1105
1131
 
1106
1132
  async revokeDelegation ({ nonce }) {
@@ -1288,12 +1314,7 @@ export async function createIdentityCore ({ kv: rawKv, peers, makeSync = null, k
1288
1314
  },
1289
1315
 
1290
1316
  async removeMember ({ pub } = {}) {
1291
- const acta = await sealChanges([{ op: 'remove', pub }])
1292
- // Expulsar rota la clave: el que sale no podrá abrir el contenido NUEVO. Lo que ya
1293
- // leyó no vuelve — eso no se puede deshacer y no se promete.
1294
- let rotated = null
1295
- try { rotated = await rotateCek() } catch (_) {}
1296
- return { ok: true, seq: acta.seq, rotated }
1317
+ return removeDevice(pub)
1297
1318
  },
1298
1319
 
1299
1320
  /**