@dotrino/vaultd 0.159.0 → 0.160.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.
@@ -5,4 +5,4 @@
5
5
  * si no coincide con la del paquete: una versión anunciada que no es la que corre es peor
6
6
  * que no anunciar ninguna.
7
7
  */
8
- export const LIB_VERSION = '0.87.0'
8
+ export const LIB_VERSION = '0.88.0'
@@ -23,7 +23,6 @@ import { SealedStore, SealedResponder } from '@dotrino/passmanager'
23
23
  import { verifyDeviceSig } from '@dotrino/identity/capabilities'
24
24
 
25
25
  export const PASSWORDS_CAP = 'passwords'
26
- export const PASSKEYS_CAP = 'passkeys'
27
26
 
28
27
  /**
29
28
  * @param {object} opts
@@ -311,14 +311,14 @@ export async function startVault ({ platform, proxyUrl, log = console.log, onEnr
311
311
  * eso se filtran explícitamente aquí, que es donde se construye la lista, y no en quien la
312
312
  * consume (`sealed-passwords.md` §2.1).
313
313
  *
314
- * `main` son los aparatos con `contraseñas`; `passkeys`, los que además pueden abrir la
315
- * privada de una passkey (§2.8). Un miembro sin llave de cifrado no puede recibir nada: se
314
+ * `main` y `passkeys` (la generación aparte de la privada de una passkey) son los MISMOS:
315
+ * los aparatos con `contraseñas`. Hubo un permiso `passkeys` aparte y se fusionó en ese
316
+ * (dueño, 2026-10-16: «realmente deberían ser uno solo»); `kind` se queda por el formato. Un miembro sin llave de cifrado no puede recibir nada: se
316
317
  * queda fuera y se ve en `incompleteMembers`.
317
318
  */
318
319
  const noEsLaBoveda = (pub) => pub !== master && pub !== commKey.pub()
319
- const passwordRecipients = (kind = 'main') => (actaCache?.members || [])
320
+ const passwordRecipients = (_kind = 'main') => (actaCache?.members || [])
320
321
  .filter((m) => m.encPub && noEsLaBoveda(m.pub) && Acta.memberCan(actaCache, m.pub, 'passwords'))
321
- .filter((m) => kind !== 'passkeys' || Acta.memberCan(actaCache, m.pub, 'passkeys'))
322
322
  .map((m) => ({ pub: m.pub, encPub: m.encPub }))
323
323
 
324
324
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotrino/vaultd",
3
- "version": "0.159.0",
3
+ "version": "0.160.0",
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": {
@@ -22,11 +22,11 @@
22
22
  },
23
23
  "dependencies": {
24
24
  "@dotrino/compat": "0.4.0",
25
- "@dotrino/identity": "^0.117.2",
25
+ "@dotrino/identity": "^0.118.0",
26
26
  "@dotrino/opaque": "0.1.0",
27
- "@dotrino/passmanager": "0.17.0",
27
+ "@dotrino/passmanager": "0.18.1",
28
28
  "@dotrino/proxy-client": "^0.36.1",
29
- "@dotrino/roadmap": "0.4.13",
29
+ "@dotrino/roadmap": "0.4.20",
30
30
  "@dotrino/store": "0.11.0",
31
31
  "@dotrino/update": "0.9.0",
32
32
  "sigstore": "5.0.0",
package/src/ctl.js CHANGED
@@ -785,12 +785,9 @@ const CAP_BY_WORD = {
785
785
  // `contraseñas`: el gestor (la extensión, la app del teléfono) puede PEDIR
786
786
  // credenciales de a una. Se acepta con y sin tilde: nadie escribe la ñ en una CLI.
787
787
  contrasenas: 'passwords', 'contraseñas': 'passwords',
788
- // `passkeys`: además de las contraseñas, puede abrir la LLAVE PRIVADA de una passkey.
789
- // Va aparte porque una passkey copiada sirve hasta que la borres en cada sitio donde
790
- // la registraste — de una contraseña, al menos, se puede cambiar
791
- // (`dotrino-passmanager/docs/sealed-passwords.md` §2.8). Sin `contraseñas` no
792
- // significa nada: la passkey vive en una entrada de contraseñas.
793
- passkeys: 'passkeys', llaves: 'passkeys',
788
+ // `contraseñas` cubre también las PASSKEYS: hubo un `passkeys` aparte y se fusionó en este
789
+ // (dueño, 2026-10-16). Quien escriba la palabra vieja recibe lo que hoy significa.
790
+ passkeys: 'passwords',
794
791
  // `desatendido`: RECIBE CLAVES PRIVADAS SIN QUE NADIE APRUEBE. Sin él, la bóveda no
795
792
  // entrega nada hasta que un aparato con `aprueba` lo firme (una vez por arranque).
796
793
  //
@@ -2340,7 +2337,7 @@ function help () {
2340
2337
  pair --quiet escupe SOLO la invitación (una línea) y termina: sin QR y sin
2341
2338
  esperar. Para desplegar (un contenedor no mira un QR en pantalla)
2342
2339
  pair --scope <lista> los PERMISOS con los que entra, cualquiera de los de caps (firma,lee,guarda,administra,
2343
- aprueba,contrasenas,passkeys,sella,desatendido,replica) y secrets:<ns>. Sin esto: firma,lee,guarda.
2340
+ aprueba,contrasenas,sella,desatendido,replica) y secrets:<ns>. Sin esto: firma,lee,guarda.
2344
2341
  Entra al acta ya con ellos. Se combina con --service: --service eco --scope firma
2345
2342
  secret set <ns> <CLAVE> <valor> variable del scope <ns>: la comparten TODOS los
2346
2343
  aparatos del perfil que sirven ese namespace
package/src/service.js CHANGED
@@ -40,6 +40,16 @@ export function daemonCommand () {
40
40
  return { cmd: process.execPath, args: [path.join(here, '..', 'bin', 'dotrino-vaultd.js')] }
41
41
  }
42
42
 
43
+ /**
44
+ * La orden para volver a correr ESTA misma invocación (la TUI tras actualizar). En el binario
45
+ * (SEA) `process.argv[1]` es otra vez el ejecutable, así que `argv.slice(1)` le pasaba su
46
+ * propia ruta como primer argumento: `sea-entry.js` no lo reconocía y arrancaba el DAEMON en
47
+ * la terminal en vez de la TUI (2026-10-16, al pasar a 0.159.0).
48
+ */
49
+ export function selfCommand (argv = process.argv, sea = !!globalThis.__DOTRINO_SEA__) {
50
+ return { cmd: process.execPath, args: argv.slice(sea ? 2 : 1) }
51
+ }
52
+
43
53
  /** Dónde escribe el daemon suelto lo que diría por consola. */
44
54
  export const daemonLogFile = () => path.join(dataDir(), 'daemon.log')
45
55
 
package/src/tui/app.js CHANGED
@@ -647,7 +647,7 @@ function pairModeRows (st, t) {
647
647
  * esté nombrado se añade al final: un permiso puede salir en mal sitio, nunca desaparecer.
648
648
  * `test/tui-permisos.test.mjs` exige además que todos tengan nombre en los dos idiomas.
649
649
  */
650
- const ORDEN = ['sign', 'store', 'read', 'admin', 'approve', 'passwords', 'passkeys', 'sealer', 'unattended', 'replica']
650
+ const ORDEN = ['sign', 'store', 'read', 'admin', 'approve', 'passwords', 'sealer', 'unattended', 'replica']
651
651
  const CAPS_ORDER = [...ORDEN.filter((c) => DEVICE_CAPS.includes(c)),
652
652
  ...DEVICE_CAPS.filter((c) => !ORDEN.includes(c))]
653
653
 
@@ -3006,7 +3006,8 @@ export async function runTui () {
3006
3006
  // TRAS ACTUALIZAR Y REINICIAR, esta pantalla también se vuelve a abrir: es el binario
3007
3007
  // anterior el que sigue en memoria. Se lanza el nuevo en esta misma terminal.
3008
3008
  if (st.relaunch) {
3009
- const r = spawnSync(process.execPath, process.argv.slice(1), { stdio: 'inherit' })
3009
+ const { cmd, args } = service.selfCommand()
3010
+ const r = spawnSync(cmd, args, { stdio: 'inherit' })
3010
3011
  process.exit(r.status ?? 0)
3011
3012
  }
3012
3013
  }
package/src/tui/i18n.js CHANGED
@@ -123,7 +123,6 @@ const es = {
123
123
  read: 'lee',
124
124
  admin: 'administra',
125
125
  passwords: 'contrasenas',
126
- passkeys: 'passkeys',
127
126
  approve: 'aprueba',
128
127
  sealer: 'sella',
129
128
  unattended: 'desatendido',
@@ -140,7 +139,6 @@ const es = {
140
139
  passwords: 'pedir una contraseña por sitio, nunca la lista entera',
141
140
  // Una passkey copiada sirve hasta que la borres en cada sitio: de una contraseña, al
142
141
  // menos, se puede cambiar. Por eso es una decisión aparte.
143
- passkeys: 'abrir además las passkeys guardadas, que son llaves y no se pueden cambiar. Sin «contrasenas» no hace nada',
144
142
  approve: 'dar el visto bueno cuando otro aparato pide claves privadas',
145
143
  // Sellar solo significa algo en un aparato que HAGA de bóveda (otra máquina con el
146
144
  // daemon, o un navegador que se puso de bóveda). En un teléfono normal se concede y no
@@ -619,7 +617,6 @@ const en = {
619
617
  read: 'read',
620
618
  admin: 'admin',
621
619
  passwords: 'passwords',
622
- passkeys: 'passkeys',
623
620
  approve: 'approve',
624
621
  sealer: 'sealer',
625
622
  unattended: 'unattended',
@@ -632,7 +629,6 @@ const en = {
632
629
  read: 'see what you saved',
633
630
  admin: 'connect and remove devices from there, without coming here. It cannot change permissions',
634
631
  passwords: 'ask for one password per site, never the whole list',
635
- passkeys: 'also open saved passkeys, which are keys and cannot be changed. Without «passwords» it does nothing',
636
632
  approve: 'give the go-ahead when another device asks for private keys',
637
633
  sealer: 'admit devices and change permissions on its own when this vault is away. Only useful on another VAULT',
638
634
  unattended: 'take private keys without asking you. Off, it must be approved from a device with «approve» every time it starts',