@dotrino/identity 0.44.0 → 0.46.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/core.js +29 -8
- package/vault/remote.js +9 -2
package/package.json
CHANGED
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
|
-
|
|
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
|
-
|
|
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
|
/**
|
package/vault/remote.js
CHANGED
|
@@ -45,10 +45,17 @@ export { MSG as VAULT_MSG }
|
|
|
45
45
|
* un `vault.error` con la palabra «revocado» no borra nada (cierra el wipe-DoS, ver
|
|
46
46
|
* `dotrino-vault/docs/pairing-protocol.md §2.3`).
|
|
47
47
|
*/
|
|
48
|
-
export async function isAuthenticRevoke ({ body, signature, master, devicePubkey }) {
|
|
48
|
+
export async function isAuthenticRevoke ({ body, signature, master, devicePubkey, currentNonce = null }) {
|
|
49
49
|
if (!body || body.op !== 'revoke' || typeof signature !== 'string') return false
|
|
50
50
|
if (body.sub !== devicePubkey) return false
|
|
51
51
|
if (typeof body.exp === 'number' && Date.now() > body.exp) return false
|
|
52
|
+
// Y tiene que hablar del certificado que este aparato usa AHORA. Un certificado se
|
|
53
|
+
// retira también cuando NO pasa nada malo: renovar retira el anterior, y cambiar
|
|
54
|
+
// permisos obliga a renovar. Sin esta comprobación, el aviso de «tu papel viejo ya no
|
|
55
|
+
// vale» borraba el enlace con la bóveda entero: dabas «administra» a un aparato y el
|
|
56
|
+
// aparato desaparecía solo, como si lo hubieran echado. El proxy encola 24 h, así que
|
|
57
|
+
// el aviso puede llegar mucho después de haber renovado.
|
|
58
|
+
if (currentNonce && typeof body.nonce === 'string' && body.nonce !== currentNonce) return false
|
|
52
59
|
return verifyDeviceSig({ publickey: master, data: body, signature })
|
|
53
60
|
}
|
|
54
61
|
|
|
@@ -236,7 +243,7 @@ async function vaultRpc ({ master, proxy, device, cert, acta = null, sendType, o
|
|
|
236
243
|
const off = client.on('message', (_f, p) => {
|
|
237
244
|
if (!p || typeof p !== 'object') return
|
|
238
245
|
if (p.type === MSG.REVOKED) {
|
|
239
|
-
isAuthenticRevoke({ body: p.body, signature: p.signature, master, devicePubkey: device.publickey })
|
|
246
|
+
isAuthenticRevoke({ body: p.body, signature: p.signature, master, devicePubkey: device.publickey, currentNonce: cert?.nonce || null })
|
|
240
247
|
.then((ok) => { if (ok) { try { onRevoked?.() } catch (_) {} } })
|
|
241
248
|
.catch(() => {})
|
|
242
249
|
return
|