@dotrino/identity 0.112.0 → 0.113.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 +1 -1
- package/vault/acta.js +15 -5
- package/vault/core.js +8 -2
package/package.json
CHANGED
package/vault/acta.js
CHANGED
|
@@ -328,8 +328,9 @@ export async function verifySealerLink (link) {
|
|
|
328
328
|
*
|
|
329
329
|
* Es la hermana de `verifySealerChain`, que hace lo mismo con actas enteras para quien las
|
|
330
330
|
* tiene. Lo que comprueba, y por qué basta:
|
|
331
|
-
* 1. el primero
|
|
332
|
-
* que
|
|
331
|
+
* 1. el primero está firmado por `profileId` — el ancla, que no se puede fabricar sin la
|
|
332
|
+
* llave que da nombre al perfil. Normalmente es el génesis (`seq 1`, sin `prev`), pero
|
|
333
|
+
* no tiene por qué: una cuenta que perdió su génesis ancla en un eslabón posterior;
|
|
333
334
|
* 2. cada siguiente lo firmó alguien a quien el ANTERIOR autorizaba;
|
|
334
335
|
* 3. y apunta al anterior por `seq` + hash, así que no se cuela uno de otra rama.
|
|
335
336
|
*
|
|
@@ -339,7 +340,9 @@ export async function verifySealerLink (link) {
|
|
|
339
340
|
export async function verifySealerLinkChain (chain, { expectedProfileId = null } = {}) {
|
|
340
341
|
if (!Array.isArray(chain) || !chain.length) return { ok: false, reason: 'cadena-vacia' }
|
|
341
342
|
const [raiz] = chain
|
|
342
|
-
|
|
343
|
+
// La misma regla que en `verifySealerChain`: la raíz la ancla la llave del perfil, no el
|
|
344
|
+
// número 1 (una cuenta puede haber perdido su génesis; ver allí).
|
|
345
|
+
if (!Number.isInteger(raiz?.seq) || raiz.seq < 1) return { ok: false, reason: 'no-empieza-en-genesis' }
|
|
343
346
|
if (raiz.by !== raiz.profileId) return { ok: false, reason: 'genesis-no-autofirmado' }
|
|
344
347
|
if (expectedProfileId != null && raiz.profileId !== expectedProfileId) return { ok: false, reason: 'otro-perfil' }
|
|
345
348
|
const vr = await verifySealerLink(raiz)
|
|
@@ -637,8 +640,15 @@ export async function verifySealerChain (chain, { expectedProfileId = null } = {
|
|
|
637
640
|
if (!Array.isArray(chain) || !chain.length) return { ok: false, reason: 'cadena-vacia' }
|
|
638
641
|
const [raiz] = chain
|
|
639
642
|
|
|
640
|
-
|
|
641
|
-
//
|
|
643
|
+
// EL ANCLA ES LA LLAVE DEL PERFIL, NO EL NÚMERO 1 (dueño, 2026-10-14). La raíz vale si
|
|
644
|
+
// está firmada por la llave que da nombre al perfil, sea el génesis o un acta posterior.
|
|
645
|
+
// Antes se exigía `seq 1`, y eso dejaba sin cadena a toda cuenta anterior a las actas v5:
|
|
646
|
+
// su génesis no llevaba `sealerChanged`, la ventana de retención lo podó, y no hay de
|
|
647
|
+
// dónde recuperarlo. Exigir el génesis no protegía de nada: quien tenga la llave del
|
|
648
|
+
// perfil fabrica un génesis alterno igual que un acta posterior, y contra eso la capa es
|
|
649
|
+
// el registro público. Lo que sí sostiene la cadena —que cada eslabón lo firmó alguien a
|
|
650
|
+
// quien el anterior autorizaba— sigue intacto.
|
|
651
|
+
if (!Number.isInteger(raiz.seq) || raiz.seq < 1) return { ok: false, reason: 'no-empieza-en-genesis' }
|
|
642
652
|
if (raiz.sealedBy !== raiz.profileId) return { ok: false, reason: 'genesis-no-autofirmado' }
|
|
643
653
|
if (expectedProfileId != null && raiz.profileId !== expectedProfileId) return { ok: false, reason: 'otro-perfil' }
|
|
644
654
|
const vr = await verifyActa({ acta: raiz })
|
package/vault/core.js
CHANGED
|
@@ -873,7 +873,9 @@ export async function createIdentityCore ({ kv: hostKv, peers, makeSync = null,
|
|
|
873
873
|
h.sort((a, b) => a.seq - b.seq)
|
|
874
874
|
const ventana = h.slice(-ACTA_WINDOW)
|
|
875
875
|
const enVentana = new Set(ventana.map((a) => a.seq))
|
|
876
|
-
|
|
876
|
+
// El génesis cuenta siempre como eslabón: las actas anteriores a v5 no llevaban la
|
|
877
|
+
// marca, y por eso la poda se llevó el génesis de las cuentas viejas.
|
|
878
|
+
const eslabones = h.filter((a) => (a.sealerChanged || a.seq === 1) && !enVentana.has(a.seq))
|
|
877
879
|
kv.setItem(ACTA_HISTORY_STORAGE, JSON.stringify([...eslabones, ...ventana].sort((a, b) => a.seq - b.seq)))
|
|
878
880
|
}
|
|
879
881
|
|
|
@@ -888,7 +890,7 @@ export async function createIdentityCore ({ kv: hostKv, peers, makeSync = null,
|
|
|
888
890
|
// La vigente cuenta como parte del material aunque todavía no esté en la historia
|
|
889
891
|
// (ahí entra al dejar de serlo). Sin esto, una cuenta recién creada devolvía [].
|
|
890
892
|
const porSeq = new Map([...loadHistory(), cur].map((a) => [a.seq, a]))
|
|
891
|
-
const eslabones = [...porSeq.values()].filter((a) => a.sealerChanged).sort((a, b) => a.seq - b.seq)
|
|
893
|
+
const eslabones = [...porSeq.values()].filter((a) => a.sealerChanged || a.seq === 1).sort((a, b) => a.seq - b.seq)
|
|
892
894
|
// Y la actual va al final si ella misma no es un eslabón: el verificador necesita ver
|
|
893
895
|
// la cabeza para saber en qué `seq` está y quién la selló.
|
|
894
896
|
return eslabones.length && eslabones[eslabones.length - 1].seq === cur.seq ? eslabones : [...eslabones, cur]
|
|
@@ -2506,6 +2508,10 @@ export async function createIdentityCore ({ kv: hostKv, peers, makeSync = null,
|
|
|
2506
2508
|
* Una cuenta de una sola bóveda devuelve SIEMPRE eso y nada más, y no puede quedarse
|
|
2507
2509
|
* obsoleta: su conjunto de selladores no puede cambiar, porque el único no puede
|
|
2508
2510
|
* quitarse a sí mismo y no hay otro que se lo quite.
|
|
2511
|
+
*
|
|
2512
|
+
* SIN GÉNESIS, la cadena es `[acta actual]` y vale igual mientras la actual esté firmada
|
|
2513
|
+
* por la llave del perfil: la raíz la ancla esa llave, no el número 1 (`verifySealerChain`).
|
|
2514
|
+
* Pasa en las cuentas anteriores a v5, cuyo génesis se podó sin la marca de eslabón.
|
|
2509
2515
|
*/
|
|
2510
2516
|
async sealerChain () { return sealerChain() },
|
|
2511
2517
|
|