@dotrino/vaultd 0.93.0 → 0.93.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 (3) hide show
  1. package/package.json +1 -1
  2. package/src/ctl.js +5 -5
  3. package/src/vault.js +31 -31
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotrino/vaultd",
3
- "version": "0.93.0",
3
+ "version": "0.93.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": {
package/src/ctl.js CHANGED
@@ -573,7 +573,7 @@ async function cmdMembers () {
573
573
  m.addedAt ? ` ${D}· conectado el ${fechaCorta(m.addedAt)}${Z}` : '',
574
574
  marks.length ? ' [' + marks.join(' · ') + ']' : '', caps)
575
575
  // Un servicio SIN llave de cifrado no puede leer ninguna variable privada: van
576
- // selladas a esa llave. Se dice aquí, junto a él, porque es el único sitio where_
576
+ // selladas a esa llave. Se dice aquí, junto a él, porque es el único sitio donde
577
577
  // se mira quién es quién — y en la lista de variables ya seria tarde.
578
578
  if (m.cn && !m.canSeal) console.log(' %ssin llave de cifrado: NO puede leer sus variables%s', R, Z)
579
579
  }
@@ -820,11 +820,11 @@ function cmdAtrest (rest) {
820
820
  // versión vieja dejó en claro, con el verificador de la contraseña dentro— meses
821
821
  // después de que su migración terminara. Se mira el perfil Y la raíz, porque el canal
822
822
  // local con la CLI vive arriba.
823
- for (const [where_, d] of [['este perfil', dir], ['la raíz de la bóveda', vaultRoot]]) {
823
+ for (const [label, d] of [['este perfil', dir], ['la raíz de la bóveda', vaultRoot]]) {
824
824
  const loose = plaintextFilesIn(d)
825
825
  if (loose.length) {
826
826
  console.log('')
827
- console.log(`${R}En claro en ${where_}:${Z} ` + loose.join(', '))
827
+ console.log(`${R}En claro en ${label}:${Z} ` + loose.join(', '))
828
828
  console.log(' Si es un respaldo de una migración terminada, bórralo: no lo cifra nadie.')
829
829
  }
830
830
  }
@@ -958,7 +958,7 @@ function cmdActivity (n = 30) {
958
958
  /**
959
959
  * `KEY=valor KEY2=valor2` — la forma de CARGAR VARIAS de una vez. Devuelve `null` si no
960
960
  * son todos pares, para que la forma clásica de tres argumentos (`set ns CLAVE valor`,
961
- * where_ el valor puede llevar espacios y hasta un `=`) siga funcionando igual.
961
+ * donde el valor puede llevar espacios y hasta un `=`) siga funcionando igual.
962
962
  */
963
963
  function asPairs (args) {
964
964
  if (!args.length) return null
@@ -1395,7 +1395,7 @@ function reportProfiles (d) {
1395
1395
  async function cmdProfile (rest) {
1396
1396
  const [sub, ...rawArgs] = rest
1397
1397
  // `--kms <archivo>` se saca ANTES de armar el nombre: el nombre se compone juntando
1398
- // los argumentos loose, así que si no se quita acabaría llamándose «midevault --kms
1398
+ // los argumentos sueltos, así que si no se quita acabaría llamándose «midevault --kms
1399
1399
  // cfg.json».
1400
1400
  const kmsAt = rawArgs.indexOf('--kms')
1401
1401
  const kmsFile = kmsAt !== -1 ? rawArgs[kmsAt + 1] : null
package/src/vault.js CHANGED
@@ -119,7 +119,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
119
119
  * Lo dice el ACTA, con el permiso `unattended`: quien lo tiene se las lleva solo; quien
120
120
  * no, espera a que un aparato con `approve` lo firme.
121
121
  *
122
- * Antes era al revés y vivía aquí: una list_ local de «estos SÍ piden permiso», así que
122
+ * Antes era al revés y vivía aquí: una lista local de «estos SÍ piden permiso», así que
123
123
  * un aparato nuevo nacía pudiendo llevarse las claves y nadie elegía eso — se elegía por
124
124
  * omisión. Ahora hay que conceder a propósito quién puede llevárselas solo, y **si falta
125
125
  * el dato se pide permiso**, que es lo que hay que hacer cuando no se sabe (dueño,
@@ -135,7 +135,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
135
135
  }
136
136
  // LA BÓVEDA DE CONTRASEÑAS: entradas y su llave, en el dir del perfil y cifradas en
137
137
  // reposo como todo lo demás. QUIÉN PUEDE PEDIR LO DICE EL ACTA (capacidad
138
- // `passwords`), como cualquier otro permiso: aquí no hay una segunda list_ de
138
+ // `passwords`), como cualquier otro permiso: aquí no hay una segunda lista de
139
139
  // aparatos. Tenerla obligaba a acordarse de dos sitios al quitar un aparato, y era
140
140
  // además un emparejamiento paralelo al del ecosistema.
141
141
  const passwordsFile = path.join(dir, 'passwords.json')
@@ -464,7 +464,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
464
464
  *
465
465
  * Sustituye a `trustedIssuer: master`, que comparaba contra UNA llave fija y por eso el
466
466
  * multivault no podía existir — una segunda selladora sellaba el acta y luego sus papeles
467
- * los rechazaban los diez mostradores. Ahora se compara contra la list_ que dice el acta.
467
+ * los rechazaban los diez mostradores. Ahora se compara contra la lista que dice el acta.
468
468
  *
469
469
  * Sin acta se devuelven nulos a propósito: `verifyDelegation` responde `no-acta` y el
470
470
  * mostrador deniega. Es lo contrario de un repliegue — no hay con qué decidir, así que no
@@ -664,7 +664,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
664
664
  * exactamente lo que el acta nombra, así que decir quién pregunta no necesita más.
665
665
  *
666
666
  * La respuesta es sí o no, y nada más: al que sigue dentro no se le manda el acta —no la
667
- * pidió, y contarle el perfil entero a quien no trae papel es dar de más—. Al que ya no
667
+ * pidió, y contarle el perfil entero a quien no trae papel es attach de más—. Al que ya no
668
668
  * está se le manda el aviso FIRMADO de expulsión, que es lo único que le borra la cuenta.
669
669
  * Que un desconocido pregunte no cuesta nada: lo que se le puede contestar es un aviso a
670
670
  * nombre de SU propia llave, que no le sirve contra nadie más (`verifyRevoke` exige que
@@ -710,7 +710,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
710
710
  audit('devices', { device: await deviceIdOf(chk.device).catch(() => null), solo: 'revocaciones' })
711
711
  return reply(from, { type: MSG.DEVICES_RESULT, devices: [], revoked, acta: record })
712
712
  }
713
- // El acta viaja con la list_: así cada dispositivo se entera de los cambios de
713
+ // El acta viaja con la lista: así cada dispositivo se entera de los cambios de
714
714
  // política (quién manda, quién puede qué) sin un canal aparte.
715
715
  // Si el dispositivo estuvo apagado y viene con un `seq` viejo, se le manda la CADENA
716
716
  // que falta (ventana de retención, §1.3) para que compruebe el encadenamiento en vez
@@ -728,7 +728,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
728
728
  }
729
729
  // `sub` (pubkey completa) va incluida: es la DIRECCIÓN de cada dispositivo en el
730
730
  // proxy → permite a las apps AUTODESCUBRIR tus máquinas (p. ej. la terminal
731
- // list_ tus agentes sin pegar nada). Solo la ve quien presenta un cert tuyo válido.
731
+ // lista tus agentes sin pegar nada). Solo la ve quien presenta un cert tuyo válido.
732
732
  const devices = await Promise.all(issued.map(async (x) => ({
733
733
  deviceId: x.sub ? await deviceIdOf(x.sub) : null, sub: x.sub || null, label: x.label || '', scope: x.scope, exp: x.exp, nonce: x.nonce
734
734
  })))
@@ -773,7 +773,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
773
773
  const prev = (issued || []).find((x) => x.nonce === p.cert.nonce)
774
774
  // EL SCOPE SALE DEL ACTA, no del cert viejo. El acta es la política (lo que el dueño
775
775
  // decidió con `caps`); el cert es su reflejo, y solo dura 30 días para poder cambiar.
776
- // Copiar `p.cert.scope` congelaba la política en el momento del emparejamiento: dar
776
+ // Copiar `p.cert.scope` congelaba la política en el momento del emparejamiento: attach
777
777
  // `administra` no llegaba nunca al cert (la consola remota no podía funcionar) y
778
778
  // QUITARLO tampoco surtía efecto hasta que el cert caducara, hasta un mes después.
779
779
  // Si el miembro ya no está en el acta, no se renueva nada: lo echaron.
@@ -1059,7 +1059,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
1059
1059
  * NUNCA. El pedido solo se veía si al dueño se le ocurría abrir la app por su cuenta.
1060
1060
  *
1061
1061
  * El aviso no lleva nada que no esté ya en el pedido, y el timbre que sale de aquí sigue
1062
- * sin contenido: quien lo recibe pregunta por la list_, no la lee del aviso.
1062
+ * sin contenido: quien lo recibe pregunta por la lista, no la lee del aviso.
1063
1063
  */
1064
1064
  async function notifyApprovers (pend, record) {
1065
1065
  try {
@@ -1170,7 +1170,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
1170
1170
  cek: await passwordsKey(),
1171
1171
  // UNA sola condición, y es del ACTA: el aparato tiene la capacidad `passwords`.
1172
1172
  // Quitársela —o quitar el aparato— le corta esto en la siguiente pasada, sin
1173
- // que haya una segunda list_ que acordarse de tocar.
1173
+ // que haya una segunda lista que acordarse de tocar.
1174
1174
  isAllowed: (pub) => !!actaCache && Acta.memberCan(actaCache, pub, 'passwords'),
1175
1175
  encPubOf: (pub) => (actaCache?.members || []).find((m) => m.pub === pub)?.encPub || null,
1176
1176
  // EN VIVO, no del caché: conceder o quitar `unattended` tiene que surtir efecto en
@@ -1348,11 +1348,11 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
1348
1348
  // Esto avisaba únicamente por `issued` —las delegaciones que emitió esta bóveda—, y
1349
1349
  // eso deja fuera exactamente el caso del multivault: la segunda bóveda entró por
1350
1350
  // `join`, así que la delegación la emitió la PRIMERA. Cuando la segunda sellaba un
1351
- // acta nueva (admitir un aparato con su permiso `sella`), su list_ de emitidas no
1351
+ // acta nueva (admitir un aparato con su permiso `sella`), su lista de emitidas no
1352
1352
  // tenía a la primera dentro y el cambio no llegaba a ninguna parte: las dos bóvedas
1353
1353
  // quedaban con actas distintas y la del dueño sin enterarse de nada.
1354
1354
  //
1355
- // El acta es la list_ de quién es del perfil: esa es la list_ correcta. `issued` se
1355
+ // El acta es la lista de quién es del perfil: esa es la lista correcta. `issued` se
1356
1356
  // suma porque cubre a quien tiene cert y todavía no aparece ahí.
1357
1357
  const miembros = (await identity.profileMembers?.().catch(() => null))?.members || []
1358
1358
  const yo = identity.me?.publickey || null
@@ -1417,7 +1417,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
1417
1417
  // podría abrirlas, porque su envoltura no existe. Dos cerrojos para lo mismo, a
1418
1418
  // propósito: que uno falle no basta para leerlas.
1419
1419
  //
1420
- // Se sella la list_ ENTERA, no solo los valores: el proxy tampoco tiene por qué
1420
+ // Se sella la lista ENTERA, no solo los valores: el proxy tampoco tiene por qué
1421
1421
  // aprender cómo se llaman tus variables ni qué servicios corres.
1422
1422
  return {
1423
1423
  enc: await identity.sealContent(JSON.stringify({
@@ -1438,7 +1438,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
1438
1438
  }
1439
1439
  },
1440
1440
  /**
1441
- * PARA QUIÉN ENVOLVER. Lo contesta la bóveda porque la list_ sale del ACTA
1441
+ * PARA QUIÉN ENVOLVER. Lo contesta la bóveda porque la lista sale del ACTA
1442
1442
  * (`recipientsOf`), y tener dos sitios respondiendo a «quién puede abrir este cajón» es
1443
1443
  * exactamente cómo se acaba dejando fuera a alguien sin que nadie se entere.
1444
1444
  */
@@ -1622,7 +1622,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
1622
1622
  // listar y borrar no la piden (ver `secretsStore.js`).
1623
1623
  /**
1624
1624
  * Los miembros que deben poder abrir un cajón: los SERVICIOS de ese namespace
1625
- * (miembros del acta con ese `cn`). La bóveda NO entra en la list_ — envolverle la
1625
+ * (miembros del acta con ese `cn`). La bóveda NO entra en la lista — envolverle la
1626
1626
  * CEK a ella misma sería devolverle la capacidad de leerlo todo, que es justo lo
1627
1627
  * que este diseño quita.
1628
1628
  */
@@ -1630,7 +1630,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
1630
1630
  const record = (await identity.profileActa?.().catch(() => null))?.acta
1631
1631
  if (!record) return []
1632
1632
  // LLEVAR EL `cn` NO ES PODER LEER. El acta manda también aquí: un miembro entra en la
1633
- // list_ si además puede leer los secretos de ese cajón (`memberCanReadSecrets`).
1633
+ // lista si además puede leer los secretos de ese cajón (`memberCanReadSecrets`).
1634
1634
  //
1635
1635
  // Sin esa segunda mitad, el `cn` era la única puerta y `cn` es un texto libre: la LLAVE
1636
1636
  // DE COMUNICACIÓN de la bóveda entra en el acta con `cn: 'vault'` y `caps: ['sign']`,
@@ -1648,7 +1648,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
1648
1648
  * ningún sitio, que es todo el punto del §8.2 — la capacidad de leer se muda de una
1649
1649
  * frase que se escribe en cualquier parte a una llave que no sale del aparato.
1650
1650
  *
1651
- * La bóveda NO entra en la list_, ni aquí ni en `nsMembers`: envolverle la llave a
1651
+ * La bóveda NO entra en la lista, ni aquí ni en `nsMembers`: envolverle la llave a
1652
1652
  * ella misma sería devolverle la capacidad de leerlo todo, que es justo lo que este
1653
1653
  * diseño quita. Hay un test que lo afirma.
1654
1654
  */
@@ -1841,7 +1841,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
1841
1841
  * hay quien la teclee.
1842
1842
  *
1843
1843
  * Que no puedan leer es CORRECTO y no se relaja. Lo que se arregla aquí es que se
1844
- * vea: hasta ahora un servicio recién enrolado aparecía en la list_ como cualquier
1844
+ * vea: hasta ahora un servicio recién enrolado aparecía en la lista como cualquier
1845
1845
  * otro y arrancaba sin configuración, repitiendo un error en su propio log que nadie
1846
1846
  * mira. Con esto, la consola y la TUI pueden decir exactamente qué falta y qué hacer
1847
1847
  * (`dotrino-vault secret settle`, que sí pide la frase).
@@ -1860,7 +1860,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
1860
1860
  // «Ver» de la consola le fallaría sin explicar por qué.
1861
1861
  // Un aparato que administra NO debe tener envoltura de los cajones con dueño
1862
1862
  // (`recipientsOf`), así que no se le cuenta como falta: lo que ahí falta es a
1863
- // propósito y ponerlo en la list_ sería pedir que se «arregle» lo correcto.
1863
+ // propósito y ponerlo en la lista sería pedir que se «arregle» lo correcto.
1864
1864
  const ownedNs = new Set((record?.members || []).filter((x) => x.cn).map((x) => x.cn))
1865
1865
  const drawers = m.cn
1866
1866
  ? [`ns:${m.cn}`, `dev:${m.pub}`]
@@ -1960,7 +1960,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
1960
1960
  * único que la frase guarda (§8.3).
1961
1961
  *
1962
1962
  * No lanza: devuelve qué pasó con cada cajón, porque una deuda que no se puede saldar
1963
- * tiene que seguir viéndose en la list_ en vez de tumbar la operación entera.
1963
+ * tiene que seguir viéndose en la lista en vez de tumbar la operación entera.
1964
1964
  */
1965
1965
  /**
1966
1966
  * PIDE AL SERVICIO QUE REPARTA la llave de su cajón a un miembro nuevo (§8.11).
@@ -2236,8 +2236,8 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
2236
2236
  const out = { drawers: 0, wrapped: 0, dropped: 0, sinLlave: [], failed: [] }
2237
2237
  for (const owner of secrets.owners?.() || []) {
2238
2238
  const before = new Set(secrets.recipientsIn(owner))
2239
- // POR VISIBILIDAD, no una list_ fija: una pública lleva además la envoltura de quien
2240
- // administra. Con una sola list_ se le daría también la de una privada con dueño, que
2239
+ // POR VISIBILIDAD, no una lista fija: una pública lleva además la envoltura de quien
2240
+ // administra. Con una sola lista se le daría también la de una privada con dueño, que
2241
2241
  // es justo lo que no puede pasar.
2242
2242
  const members = (esPublica) => recipientsOf(owner, { public: esPublica })
2243
2243
  try {
@@ -2300,7 +2300,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
2300
2300
  if (!owed) return null
2301
2301
  // QUIÉN RECIBE ENVOLTURA LO DICE `recipientsOf`, Y SOLO ÉL.
2302
2302
  //
2303
- // Antes cada llamador traía su propia list_ (`nsMembers`, o el miembro suelto), y todas
2303
+ // Antes cada llamador traía su propia lista (`nsMembers`, o el miembro suelto), y todas
2304
2304
  // se dejaban fuera a los SELLADORES — que `recipientsOf` sí incluye. Resultado: escribir
2305
2305
  // una variable envolvía para el servicio y dejaba al sellador con la generación vieja
2306
2306
  // (dueño, 2026-09-01: «al envolver hay que envolver siempre para todos los selladores,
@@ -2406,9 +2406,9 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
2406
2406
  * pública, y no se puede leer. Eso es cierto y se arregla abriendo la bóveda; inventarse
2407
2407
  * un valor o esconder la fila sería peor.
2408
2408
  */
2409
- const withEnvelopes = (list_, kind, caller) => {
2410
- if (!caller) return list_
2411
- const dar = (owner, k) => {
2409
+ const withEnvelopes = (entries, kind, caller) => {
2410
+ if (!caller) return entries
2411
+ const attach = (owner, k) => {
2412
2412
  if (!k.public) return k
2413
2413
  const e = secrets.entryOf?.(owner, k.key)
2414
2414
  const wrap = e?.gen != null ? secrets.wrapOf?.(owner, e.gen, caller) : null
@@ -2416,10 +2416,10 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
2416
2416
  }
2417
2417
  if (kind === 'ns') {
2418
2418
  const out = {}
2419
- for (const [ns, keys] of Object.entries(list_)) out[ns] = keys.map((k) => dar(`ns:${ns}`, k))
2419
+ for (const [ns, keys] of Object.entries(entries)) out[ns] = keys.map((k) => attach(`ns:${ns}`, k))
2420
2420
  return out
2421
2421
  }
2422
- return list_.map((row) => ({ ...row, keys: row.keys.map((k) => dar(`dev:${row.pub}`, k)) }))
2422
+ return entries.map((row) => ({ ...row, keys: row.keys.map((k) => attach(`dev:${row.pub}`, k)) }))
2423
2423
  }
2424
2424
 
2425
2425
  function listSecrets () {
@@ -2549,10 +2549,10 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
2549
2549
  stopPairing: desk.stopPairing,
2550
2550
  listPending: desk.listPending,
2551
2551
  // ¿Pide permiso este aparato para recibir claves privadas? Lo dice el ACTA
2552
- // (`unattended`), no una list_ de esta máquina — por eso ya no hay `setApproval` ni
2552
+ // (`unattended`), no una lista de esta máquina — por eso ya no hay `setApproval` ni
2553
2553
  // `supervised`: se concede y se quita como cualquier otro permiso, con `caps`.
2554
2554
  needsApproval: async (pub) => needsApproval(pub, await refreshActa()),
2555
- // La bóveda de contraseñas (`passwords.js`). Aquí SÍ se list_: es donde está la
2555
+ // La bóveda de contraseñas (`passwords.js`). Aquí SÍ se lista: es donde está la
2556
2556
  // llave. Lo que no puede es listarla un aparato.
2557
2557
  passwordDevices,
2558
2558
  passwordsVault: () => passwords?.vault || null,
@@ -2599,7 +2599,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
2599
2599
  // desbloquear: deja `secrets.json.v3.bak` para poder volver.
2600
2600
  /**
2601
2601
  * Convierte el archivo de secretos al formato nuevo. `membersOf` es opcional y lo
2602
- * normal es NO pasarlo: por defecto se usa la misma list_ de destinatarios que
2602
+ * normal es NO pasarlo: por defecto se usa la misma lista de destinatarios que
2603
2603
  * cualquier escritura —los servicios del cajón MÁS los aparatos que administran—.
2604
2604
  *
2605
2605
  * Pasarla a mano fue un error real: la conversión envolvía solo a los servicios, y
@@ -2644,7 +2644,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
2644
2644
  isMaster: () => identity.isMaster(),
2645
2645
  setCaps: async (pub, caps) => {
2646
2646
  const r = await identity.setCaps(pub, caps)
2647
- // ¿SE QUEDÓ ALGUNO POR EL CAMINO? El acta tiene una list_ CERRADA de permisos y
2647
+ // ¿SE QUEDÓ ALGUNO POR EL CAMINO? El acta tiene una lista CERRADA de permisos y
2648
2648
  // `cleanCaps` descarta los que no conoce — correcto al recibir un acta ajena, y
2649
2649
  // pésimo aquí: conceder `+sella` con una versión del pilar que no sabe qué es
2650
2650
  // devolvía «Listo», resellaba el acta y no concedía nada. Costó una tarde en un