@dotrino/vaultd 0.24.0 → 0.25.1

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 +2 -2
  2. package/src/vault.js +14 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotrino/vaultd",
3
- "version": "0.24.0",
3
+ "version": "0.25.1",
4
4
  "type": "module",
5
5
  "description": "Certificador personal de Dotrino: daemon headless que custodia la clave maestra y delega capacidades a tus dispositivos por el proxy. Tu CA propia.",
6
6
  "bin": {
@@ -19,7 +19,7 @@
19
19
  "node": ">=20"
20
20
  },
21
21
  "dependencies": {
22
- "@dotrino/identity": "^0.44.0",
22
+ "@dotrino/identity": "^0.46.0",
23
23
  "@dotrino/proxy-client": "^0.10.0",
24
24
  "ws": "^8.18.0"
25
25
  },
package/src/vault.js CHANGED
@@ -227,9 +227,18 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
227
227
  * — y hasta ahora el daemon no lo reemitía nunca. Si el aparato estaba apagado cuando lo
228
228
  * quitaste, no se enteraba jamás: seguía enseñando el perfil como si nada.
229
229
  */
230
- async function avisarSiRevocado (pubkey) {
230
+ async function avisarSiRevocado (pubkey, nonce = null) {
231
231
  if (typeof pubkey !== 'string') return
232
232
  try {
233
+ // PRIMERO: ¿sigue siendo del perfil? Un certificado retirado NO significa «estás
234
+ // fuera». Renovar retira el anterior, y cambiar permisos obliga a renovar, así que
235
+ // un aparato que llega con un papel viejo es de casa y solo tiene que renovar. Si
236
+ // aquí se le manda el aviso de expulsión, el aparato se borra solo: dabas
237
+ // «administra» y el dispositivo desaparecía como si lo hubieran echado. El aviso es
238
+ // para quien YA NO ESTÁ en el acta.
239
+ const acta = (await identity.profileActa?.().catch(() => null))?.acta || null
240
+ if (acta && (acta.members || []).some((m) => m.pub === pubkey)) return
241
+
233
242
  // OJO con dónde se buscan: desde identity 0.42 `issued` es «lo que HOY sirve para
234
243
  // entrar», así que los retirados NO están ahí — viven en `revokedCerts`. Buscarlos
235
244
  // en `issued` no daba error, daba una lista vacía y ningún aviso.
@@ -238,7 +247,9 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
238
247
  const candidatos = [...(dele.revokedCerts || []), ...(dele.issued || [])]
239
248
  const suyas = candidatos.filter((x) => x.sub === pubkey && (x.revokedAt || revocados.has(x.nonce)))
240
249
  if (suyas.length) {
241
- await desk.emitRevoke(pubkey, suyas[0].nonce)
250
+ // El aviso nombra el certificado que el aparato ACABA de presentar: es el que
251
+ // tiene en la mano, y es contra ese contra el que comprueba antes de borrarse.
252
+ await desk.emitRevoke(pubkey, nonce || suyas[0].nonce)
242
253
  audit('revoke.notified', { device: await deviceIdOf(pubkey).catch(() => null) })
243
254
  }
244
255
  } catch (e) { log('[vault] could not re-emit the revocation:', e.message) }
@@ -248,7 +259,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
248
259
  if (!isFresh(p.data)) return staleReply(from)
249
260
  const chk = await verifyChain({ data: p.data, signature: p.signature, cert: p.cert, trustedIssuer: master, revoked: await revocationSet() })
250
261
  if (!chk.ok) {
251
- if (chk.reason === 'revoked') await avisarSiRevocado(p.data?.publickey)
262
+ if (chk.reason === 'revoked') await avisarSiRevocado(p.data?.publickey, p.cert?.nonce || null)
252
263
  return reply(from, { type: MSG.ERROR, error: 'unauthorized: ' + chk.reason })
253
264
  }
254
265
  const { issued, revoked } = await identity.listDelegations()