@dotrino/vaultd 0.59.0 → 0.60.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotrino/vaultd",
3
- "version": "0.59.0",
3
+ "version": "0.60.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": {
package/src/tui/app.js CHANGED
@@ -127,6 +127,10 @@ function mergeMembersAndCerts (members, issued) {
127
127
  label: m.label || cert?.label || '',
128
128
  isMaster: !!m.isMaster,
129
129
  cn: m.cn || null,
130
+ // CUÁNDO ENTRÓ. Venía en el acta y se perdía aquí, así que la lista no podía
131
+ // enseñarlo por mucho que se quisiera. El nombre lo pone el propio aparato y muchas
132
+ // veces no distingue nada: la fecha es lo que deja reconocer cuál es cuál.
133
+ addedAt: m.addedAt || null,
130
134
  // El master es la propia bóveda: no tiene (ni necesita) certificado. Un servicio
131
135
  // tampoco lleva uno de dispositivo. Marcarlos «sin acceso» sería una alarma falsa.
132
136
  noAccess: !cert && !m.isMaster && !m.cn
@@ -260,6 +264,7 @@ function deviceRows (st, t) {
260
264
  const label = d.label || t.muted(i.noLabel)
261
265
  const vars = devVarsOf(st, d.sub).length
262
266
  const debt = debtOf(st, d.sub)
267
+ const desde = d.addedAt ? t.muted(` ${i.deviceSince}:${fmtExp(d.addedAt)}`) : ''
263
268
  const extra = (d.certCount > 1 ? t.muted(` certs:${d.certCount}`) : '') +
264
269
  (vars ? t.muted(` vars:${vars}`) : '') +
265
270
  // EN DEUDA: en el acta y sin poder abrir lo suyo. Va en color de aviso al lado de
@@ -272,7 +277,7 @@ function deviceRows (st, t) {
272
277
  : d.isMaster
273
278
  ? t.muted(i.thisVault)
274
279
  : t.muted('scope:' + shortScope(d.scope)) + ' ' + t.muted('exp:' + fmtExp(d.exp))
275
- rows.push({ text: ` ${t.bold(d.deviceId)} ${label} ${status}${extra}`, sel: true, meta: d })
280
+ rows.push({ text: ` ${t.bold(d.deviceId)} ${label}${desde} ${status}${extra}`, sel: true, meta: d })
276
281
  }
277
282
  const revoked = st.devices?.revoked || []
278
283
  if (revoked.length) {
@@ -318,7 +323,17 @@ function pairModeRows (st, t) {
318
323
  * una marca de si los tiene. El de administrar va aparte y avisado: es el único que deja
319
324
  * a ese aparato meter y sacar dispositivos sin venir aquí.
320
325
  */
321
- const CAPS_ORDER = ['sign', 'store', 'read', 'admin', 'passwords']
326
+ /**
327
+ * TODOS los permisos que el acta reconoce para un aparato, en el orden en que se leen: de
328
+ * lo cotidiano a lo que cambia quién manda.
329
+ *
330
+ * `approve` y `sealer` faltaban, y solo se podían conceder por la CLI. Un permiso que
331
+ * existe y no se ve en la pantalla que se llama «permisos» hace creer que no existe — y
332
+ * `sealer` es justo el que hay que entender para el multivault. Se ven siempre, aunque en
333
+ * un teléfono normal `sealer` no lo vaya a usar nadie: verlo apagado explica el modelo
334
+ * (dueño, 2026-08-31).
335
+ */
336
+ const CAPS_ORDER = ['sign', 'store', 'read', 'admin', 'approve', 'passwords', 'sealer']
322
337
 
323
338
  function capsRows (st, t) {
324
339
  const i = L(st)
package/src/tui/i18n.js CHANGED
@@ -46,14 +46,22 @@ const es = {
46
46
  store: 'Guardar tus datos',
47
47
  read: 'Leer tus datos',
48
48
  admin: 'Administrar el perfil',
49
- passwords: 'Pedir tus contraseñas'
49
+ passwords: 'Pedir tus contraseñas',
50
+ approve: 'Aprobar pedidos',
51
+ sealer: 'Sellar el acta'
50
52
  },
51
53
  capHint: {
52
54
  sign: 'usar tu identidad en las apps del ecosistema',
53
55
  store: 'escribir en tu bóveda (perfil, contenido, datos sensibles)',
54
56
  read: 'ver lo que guardaste',
55
57
  admin: 'conectar y quitar dispositivos desde ese aparato, sin venir aquí',
56
- passwords: 'el gestor: pedir una credencial por sitio, nunca la lista entera'
58
+ passwords: 'el gestor: pedir una credencial por sitio, nunca la lista entera',
59
+ approve: 'dar el visto bueno cuando otro aparato pide claves privadas',
60
+ // Sellar solo significa algo en un aparato que HAGA de bóveda (otra máquina con el
61
+ // daemon, o un navegador que se puso de bóveda). En un teléfono normal se concede y no
62
+ // lo usa nadie. Se enseña igual, y se dice: verlo desactivado explica el modelo;
63
+ // esconderlo hacía creer que no existe (dueño, 2026-08-31).
64
+ sealer: 'admitir aparatos y cambiar permisos él solo, si esta bóveda no está. Solo sirve en otra BÓVEDA'
57
65
  },
58
66
  confirmAdmin: (id) => `¿Dejar que ${id} conecte y quite dispositivos sin venir aquí?`,
59
67
  capGiven: (n) => `Concedido: ${n}`,
@@ -140,6 +148,7 @@ const es = {
140
148
  cantRemoveMaster: 'Esta bóveda es la que manda: no se quita a sí misma.',
141
149
  revokedCount: (n) => ` Revocados: ${n}`,
142
150
  startingPairing: 'Iniciando emparejamiento…',
151
+ deviceSince: 'desde',
143
152
  nameDeviceLabel: '¿Cómo se va a llamar este aparato?',
144
153
  nameDeviceHint: 'Enter para dejar que lo diga él (usará tu apodo, y así no se distinguen)',
145
154
  noPending: 'No hay ningún dispositivo pendiente',
@@ -347,14 +356,18 @@ const en = {
347
356
  store: 'Save your data',
348
357
  read: 'Read your data',
349
358
  admin: 'Manage the profile',
350
- passwords: 'Ask for your passwords'
359
+ passwords: 'Ask for your passwords',
360
+ approve: 'Approve requests',
361
+ sealer: 'Seal the record'
351
362
  },
352
363
  capHint: {
353
364
  sign: 'use your identity across the ecosystem apps',
354
365
  store: 'write to your vault (profile, content, sensitive data)',
355
366
  read: 'see what you saved',
356
367
  admin: 'connect and remove devices from that device, without coming here',
357
- passwords: 'the manager: ask for one credential per site, never the whole list'
368
+ passwords: 'the manager: ask for one credential per site, never the whole list',
369
+ approve: 'give the go-ahead when another device asks for private keys',
370
+ sealer: 'admit devices and change permissions on its own if this vault is gone. Only useful on another VAULT'
358
371
  },
359
372
  confirmAdmin: (id) => `Let ${id} connect and remove devices without coming here?`,
360
373
  capGiven: (n) => `Granted: ${n}`,
@@ -437,6 +450,7 @@ const en = {
437
450
  cantRemoveMaster: 'This vault is the Master: it does not remove itself.',
438
451
  revokedCount: (n) => ` Revoked: ${n}`,
439
452
  startingPairing: 'Starting pairing…',
453
+ deviceSince: 'since',
440
454
  nameDeviceLabel: 'What will this device be called?',
441
455
  nameDeviceHint: 'Enter to let it say (it will use your nickname, and then they all look alike)',
442
456
  noPending: 'No device is waiting',