@dotrino/identity 0.41.0 → 0.42.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 +9 -0
- package/vault/core.js +11 -1
- package/vault/remote.js +23 -0
package/package.json
CHANGED
package/vault/acta.js
CHANGED
|
@@ -245,6 +245,15 @@ export async function applyChanges (acta, changes, { by, now = Date.now() } = {}
|
|
|
245
245
|
// No se puede ascender un servicio a dispositivo cambiándole las capacidades: para
|
|
246
246
|
// eso hay que sacarlo y volver a admitirlo, que es un gesto visible.
|
|
247
247
|
m.caps = cleanCaps(ch.caps).filter((c) => (m.cn ? SERVICE_CAPS : DEVICE_CAPS).includes(c))
|
|
248
|
+
// CONCEDER LIMPIA LA RENUNCIA. `effectiveCaps` resta lo renunciado, así que sin
|
|
249
|
+
// esto una renuncia sellada era IRREVERSIBLE: el master le devolvía el permiso en
|
|
250
|
+
// `caps` y la resta seguía dejándolo fuera, para siempre. La interfaz promete
|
|
251
|
+
// «puedes devolvérselo desde el Master», así que tiene que ser verdad.
|
|
252
|
+
// Se tira el registro entero y no se le recortan capacidades: va FIRMADO por el
|
|
253
|
+
// miembro, y editarlo lo dejaría sin firma válida.
|
|
254
|
+
const renunciadas = new Set()
|
|
255
|
+
for (const r of next.renounced) if (r.member === m.pub) for (const c of (r.caps || [])) renunciadas.add(c)
|
|
256
|
+
if (m.caps.some((c) => renunciadas.has(c))) next.renounced = next.renounced.filter((r) => r.member !== m.pub)
|
|
248
257
|
break
|
|
249
258
|
}
|
|
250
259
|
case 'label': {
|
package/vault/core.js
CHANGED
|
@@ -22,7 +22,7 @@ import { signDelegationWith, MAX_DELEGATION_MS, DEFAULT_DELEGATION_MS } from './
|
|
|
22
22
|
import * as Acta from './acta.js'
|
|
23
23
|
import * as Content from './content.js'
|
|
24
24
|
import { pubkeyId as pubkeyIdOf } from './capabilities.js'
|
|
25
|
-
import { enrollDevice as remoteEnroll, requestSign as remoteSign, requestStore as remoteStore, requestDevices as remoteDevices, requestRenew as remoteRenew, requestAdmin as remoteAdmin } from './remote.js'
|
|
25
|
+
import { enrollDevice as remoteEnroll, requestSign as remoteSign, requestStore as remoteStore, requestDevices as remoteDevices, requestRenew as remoteRenew, requestAdmin as remoteAdmin, requestRenounce as remoteRenounce } from './remote.js'
|
|
26
26
|
|
|
27
27
|
export const KEY_STORAGE = 'dotrino.identity.keypair'
|
|
28
28
|
export const ENC_KEY_STORAGE = 'dotrino.identity.enc-keypair'
|
|
@@ -1270,6 +1270,16 @@ export async function createIdentityCore ({ kv: rawKv, peers, makeSync = null, k
|
|
|
1270
1270
|
pend.push(record)
|
|
1271
1271
|
saveRenounces(pend)
|
|
1272
1272
|
emitVault({ phase: 'renounced', caps: record.caps })
|
|
1273
|
+
// Y se le MANDA a la bóveda para que la selle en el acta. Sin esto la renuncia solo
|
|
1274
|
+
// valía aquí dentro: la bóveda seguía teniendo escrito que este aparato puede firmar
|
|
1275
|
+
// y le seguía aceptando peticiones. Best-effort: si la bóveda está apagada, la
|
|
1276
|
+
// renuncia ya está en pie localmente (para eso no necesita a nadie) y se reintenta
|
|
1277
|
+
// la próxima vez que se renuncie.
|
|
1278
|
+
const v = loadVaultCert(); const dev = loadVaultDevice()
|
|
1279
|
+
if (v?.cert && dev) {
|
|
1280
|
+
remoteRenounce({ master: v.master, proxy: v.proxy, device: dev, cert: v.cert, record })
|
|
1281
|
+
.catch(() => {})
|
|
1282
|
+
}
|
|
1273
1283
|
// Si además soy el master, la absorbo ya en el acta.
|
|
1274
1284
|
if (amMaster()) { try { await sealChanges([{ op: 'renounce', record }]) } catch (_) {} }
|
|
1275
1285
|
return { ok: true, record, caps: Acta.effectiveCaps(loadActa(), publickeyJwkStr, loadRenounces()) }
|
package/vault/remote.js
CHANGED
|
@@ -32,6 +32,9 @@ const MSG = {
|
|
|
32
32
|
ADMIN: 'vault.admin',
|
|
33
33
|
ADMIN_RESULT: 'vault.admin.result',
|
|
34
34
|
ADMIN_EVENT: 'vault.admin.event',
|
|
35
|
+
// Renuncia: el miembro se quita capacidades a sí mismo y la bóveda la sella en el acta.
|
|
36
|
+
RENOUNCE: 'vault.renounce',
|
|
37
|
+
RENOUNCE_RESULT: 'vault.renounce.result',
|
|
35
38
|
ERROR: 'vault.error'
|
|
36
39
|
}
|
|
37
40
|
export { MSG as VAULT_MSG }
|
|
@@ -275,6 +278,26 @@ export async function requestRenew ({ master, proxy, device, cert, onRevoked } =
|
|
|
275
278
|
return { cert: res.cert }
|
|
276
279
|
}
|
|
277
280
|
|
|
281
|
+
/**
|
|
282
|
+
* Manda a la bóveda la RENUNCIA de este dispositivo para que la selle en el acta.
|
|
283
|
+
*
|
|
284
|
+
* Sin esto, renunciar solo valía en el propio aparato: la bóveda seguía teniendo escrito
|
|
285
|
+
* que podía firmar, le seguía aceptando peticiones, y cualquiera que mirara el acta lo
|
|
286
|
+
* seguía viendo como firmante. Una renuncia que no llega al acta no es oponible a nadie —
|
|
287
|
+
* y en el caso que la justifica (te robaron el aparato) su registro local no vale nada,
|
|
288
|
+
* porque lo borra quien lo tenga en la mano.
|
|
289
|
+
*
|
|
290
|
+
* El `record` va FIRMADO por el propio miembro y solo puede QUITAR, así que la bóveda no
|
|
291
|
+
* necesita comprobar ningún certificado para honrarlo: le basta la firma.
|
|
292
|
+
*/
|
|
293
|
+
export async function requestRenounce ({ master, proxy, device, cert, record, onRevoked } = {}) {
|
|
294
|
+
const res = await vaultRpc({
|
|
295
|
+
master, proxy, device, cert, onRevoked,
|
|
296
|
+
sendType: MSG.RENOUNCE, okType: MSG.RENOUNCE_RESULT, data: { op: 'renounce', record }
|
|
297
|
+
})
|
|
298
|
+
return { ok: !!res.ok, seq: res.seq ?? null }
|
|
299
|
+
}
|
|
300
|
+
|
|
278
301
|
/**
|
|
279
302
|
* CONSOLA REMOTA (`dotrino-vault/docs/consola-remota.md`): administrar el perfil desde
|
|
280
303
|
* este dispositivo, sin ir al PC. Requiere un cert con scope `vault:admin`, que **no se
|