@dotrino/identity 0.68.0 → 0.69.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotrino/identity",
3
- "version": "0.68.0",
3
+ "version": "0.69.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/src/index.js CHANGED
@@ -278,6 +278,8 @@ export class Identity {
278
278
 
279
279
  /** El acta vigente + si este dispositivo es el master + sus capacidades efectivas. */
280
280
  async profileActa () { return this._call('profileActa') }
281
+ /** La cadena de selladores, para mandarla con una firma (ver `vault/acta.js`). */
282
+ async sealerChain () { return this._call('sealerChain') }
281
283
 
282
284
  /** Miembros del perfil, ya con id legible y capacidades efectivas. */
283
285
  async profileMembers () { return this._call('profileMembers') }
package/src/node.js CHANGED
@@ -169,6 +169,8 @@ export class Identity {
169
169
  listDelegations () { return this._h('listDelegations') }
170
170
  // Acta de perfil (qué llaves son del perfil y qué puede cada una; ver acta-de-perfil.md)
171
171
  profileActa () { return this._h('profileActa') }
172
+ /** La cadena de selladores, para mandarla con una firma (ver `vault/acta.js`). */
173
+ sealerChain () { return this._h('sealerChain') }
172
174
  profileMembers () { return this._h('profileMembers') }
173
175
  /**
174
176
  * Quien SELLA SOBRES (la bóveda) registra aquí cómo estrenar su llave de sellado: se
package/vault/core.js CHANGED
@@ -563,8 +563,13 @@ export async function createIdentityCore ({ kv: rawKv, peers, makeSync = null, k
563
563
  const sealerChain = () => {
564
564
  const cur = loadActa()
565
565
  if (!cur) return []
566
- const eslabones = loadHistory().filter((a) => a.sealerChanged).sort((a, b) => a.seq - b.seq)
567
- return cur.sealerChanged ? eslabones : [...eslabones, cur]
566
+ // La vigente cuenta como parte del material aunque todavía no esté en la historia
567
+ // (ahí entra al dejar de serlo). Sin esto, una cuenta recién creada devolvía [].
568
+ const porSeq = new Map([...loadHistory(), cur].map((a) => [a.seq, a]))
569
+ const eslabones = [...porSeq.values()].filter((a) => a.sealerChanged).sort((a, b) => a.seq - b.seq)
570
+ // Y la actual va al final si ella misma no es un eslabón: el verificador necesita ver
571
+ // la cabeza para saber en qué `seq` está y quién la selló.
572
+ return eslabones.length && eslabones[eslabones.length - 1].seq === cur.seq ? eslabones : [...eslabones, cur]
568
573
  }
569
574
 
570
575
  const loadRenounces = () => { try { return JSON.parse(kv.getItem(RENOUNCE_STORAGE) || '[]') || [] } catch (_) { return [] } }
@@ -627,7 +632,14 @@ export async function createIdentityCore ({ kv: rawKv, peers, makeSync = null, k
627
632
  const { generation } = await Content.makeGeneration({ members: base.members, gen: 1 })
628
633
  base.keyring = [generation]
629
634
  } catch (e) { console.warn('[identity] could not create the content key:', e.message) }
630
- saveActa(await seal(base))
635
+ const genesis = await seal(base)
636
+ saveActa(genesis)
637
+ // EL GÉNESIS VA A LA HISTORIA DESDE EL PRIMER DÍA. Es el ancla de la cadena de
638
+ // selladores —el único eslabón autofirmado por la llave que da nombre al perfil— y
639
+ // sin él nadie de fuera puede verificar nada de esta cuenta, nunca. Antes solo se
640
+ // guardaba lo que DEJABA de ser vigente, así que una cuenta que nunca cambió su acta
641
+ // no tenía génesis guardado y su cadena salía vacía.
642
+ pushHistory(genesis)
631
643
  return loadActa()
632
644
  }
633
645
 
@@ -1144,7 +1156,7 @@ export async function createIdentityCore ({ kv: rawKv, peers, makeSync = null, k
1144
1156
  const LOCK_EXEMPT = new Set([
1145
1157
  'profileLockStatus', 'unlockProfile', 'listProfiles', 'currentProfile',
1146
1158
  'switchProfile', 'createProfile',
1147
- 'profileActa', 'profileMembers', 'myMembership', 'isMaster'
1159
+ 'profileActa', 'profileMembers', 'myMembership', 'isMaster', 'sealerChain'
1148
1160
  ])
1149
1161
 
1150
1162
  const handlers = {
@@ -1498,6 +1510,20 @@ export async function createIdentityCore ({ kv: rawKv, peers, makeSync = null, k
1498
1510
  return { acta, isMaster: amMaster(), myCaps: Acta.effectiveCaps(acta, publickeyJwkStr, loadRenounces()) }
1499
1511
  },
1500
1512
 
1513
+ /**
1514
+ * LA CADENA DE SELLADORES, para mandarla junto con una firma.
1515
+ *
1516
+ * Es lo que deja a un EXTRAÑO comprobar que quien firmó habla por esta identidad, sin
1517
+ * preguntarle a nadie: `[génesis, …cambios de sellador…, acta actual]`. No son todas
1518
+ * las actas —eso crecería con cada emparejamiento— sino solo los eslabones donde
1519
+ * cambió quién sella, que casi nunca pasa. Lo normal es longitud 1: el génesis.
1520
+ *
1521
+ * Una cuenta de una sola bóveda devuelve SIEMPRE eso y nada más, y no puede quedarse
1522
+ * obsoleta: su conjunto de selladores no puede cambiar, porque el único no puede
1523
+ * quitarse a sí mismo y no hay otro que se lo quite.
1524
+ */
1525
+ async sealerChain () { return sealerChain() },
1526
+
1501
1527
  /**
1502
1528
  * Quien sella sobres de secretos (la bóveda) registra aquí cómo estrenar su LLAVE DE
1503
1529
  * SELLADO: una función que crea el par, se guarda la privada y devuelve la pública. Se