@dotrino/vaultd 0.128.0 → 0.129.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.
- package/package.json +2 -2
- package/src/ctl.js +1 -1
- package/src/vault.js +16 -22
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dotrino/vaultd",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.129.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": {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@dotrino/proxy-client": "0.24.0",
|
|
29
29
|
"@dotrino/roadmap": "0.3.7",
|
|
30
30
|
"@dotrino/store": "0.11.0",
|
|
31
|
-
"@dotrino/update": "0.
|
|
31
|
+
"@dotrino/update": "0.2.1",
|
|
32
32
|
"ws": "^8.18.0"
|
|
33
33
|
},
|
|
34
34
|
"license": "MIT",
|
package/src/ctl.js
CHANGED
|
@@ -1754,7 +1754,7 @@ async function cmdUpdate (args = []) {
|
|
|
1754
1754
|
console.log('listo')
|
|
1755
1755
|
|
|
1756
1756
|
process.stdout.write('Comprobando la firma… ')
|
|
1757
|
-
const v = verifyArtifact(file)
|
|
1757
|
+
const v = await verifyArtifact(file)
|
|
1758
1758
|
if (!v.ok) {
|
|
1759
1759
|
console.log('')
|
|
1760
1760
|
console.error('%sNO se instala nada.%s %s', R, Z, v.reason)
|
package/src/vault.js
CHANGED
|
@@ -152,6 +152,12 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
|
|
|
152
152
|
*/
|
|
153
153
|
function needsApproval (pub, record) {
|
|
154
154
|
if (!record) return true // sin acta no se decide que sí: se pide permiso
|
|
155
|
+
// SIN NADIE QUE APRUEBE, NO SE NECESITA APROBACIÓN (dueño, 2026-09-24: «la regla es, si
|
|
156
|
+
// no hay aprobador no se necesita aprobación»). Es la misma que ya seguía la
|
|
157
|
+
// actualización automática: esperar un sí que nadie puede dar solo deja al servicio
|
|
158
|
+
// colgado. Aquí se decide para las tres puertas —entregar claves, contraseñas y guardar
|
|
159
|
+
// variables— y por eso no hay un «nadie aprueba» aparte en ninguna de ellas.
|
|
160
|
+
if (!record.members?.some((m) => Acta.memberCan(record, m.pub, 'approve'))) return false
|
|
155
161
|
return !Acta.memberCan(record, pub, 'unattended')
|
|
156
162
|
}
|
|
157
163
|
|
|
@@ -1460,6 +1466,13 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
|
|
|
1460
1466
|
// hace la BÓVEDA (`bundleFor({ publicOnly })`), no el que pide: si mandáramos todo y el
|
|
1461
1467
|
// cliente eligiera, pedir «solo públicas» sería la manera de saltarse la aprobación.
|
|
1462
1468
|
const publicOnly = p.data?.publicOnly === true
|
|
1469
|
+
// Entregar SIN aprobación porque no hay quien apruebe es la regla (ver `needsApproval`),
|
|
1470
|
+
// pero se deja dicho: quien mire el log tiene que poder ver por qué no sonó el teléfono.
|
|
1471
|
+
if (!publicOnly && record && !Acta.memberCan(record, chk.device, 'unattended') &&
|
|
1472
|
+
!record.members?.some((m) => Acta.memberCan(record, m.pub, 'approve'))) {
|
|
1473
|
+
audit('secrets.no-approver', { device: await deviceIdOf(chk.device).catch(() => null), ns })
|
|
1474
|
+
log(`[vault] ${ns}: served ${await deviceIdOf(chk.device).catch(() => '????-????')} without approval — nobody in the record can approve`)
|
|
1475
|
+
}
|
|
1463
1476
|
if (!publicOnly && needsApproval(chk.device, record)) {
|
|
1464
1477
|
const deviceId = await deviceIdOf(chk.device).catch(() => null)
|
|
1465
1478
|
const label = (record?.members || []).find((m) => m.pub === chk.device)?.label || ''
|
|
@@ -1484,27 +1497,8 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
|
|
|
1484
1497
|
return reply(from, { type: MSG.ERROR, error: 'secrets: invalid ek' })
|
|
1485
1498
|
}
|
|
1486
1499
|
}
|
|
1487
|
-
//
|
|
1488
|
-
//
|
|
1489
|
-
// La bóveda ya lo sabía —lo escribía en su propio log, «rang 0 approver(s)»— y aun
|
|
1490
|
-
// así contestaba «pendiente» y dejaba al otro aguardando a algo que no podía pasar.
|
|
1491
|
-
// Eso es un fallo ruidoso convertido en uno mudo, que es exactamente lo que la norma
|
|
1492
|
-
// prohíbe (CLAUDE.md, «nada de repliegues»), y encima el que sabe es el ÚNICO que
|
|
1493
|
-
// puede enterar al otro (CONVENCIONES §14): el que pide no tiene el acta, así que no
|
|
1494
|
-
// hay forma de que lo averigüe por su cuenta.
|
|
1495
|
-
//
|
|
1496
|
-
// Lo pidió el dueño el 2026-09-05, después de mirar un `dotrino-env check` que parecía
|
|
1497
|
-
// colgado y era esto.
|
|
1498
|
-
const quienAprueba = (record?.members || []).filter((m) => Acta.memberCan(record, m.pub, 'approve'))
|
|
1499
|
-
if (!quienAprueba.length) {
|
|
1500
|
-
audit('rejected', { what: 'secrets', ns, reason: 'sin-aprobador' })
|
|
1501
|
-
log(`[vault] ${ns}: refused ${deviceId || '????-????'} — nobody in the record can approve`)
|
|
1502
|
-
return reply(from, {
|
|
1503
|
-
type: MSG.ERROR,
|
|
1504
|
-
code: 'no-approver',
|
|
1505
|
-
error: `approval: nobody in the record can approve — grant it with \`dotrino-vault caps <ID> +aprueba\`, or let this service run unattended with \`dotrino-vault caps ${deviceId || '<ID>'} +desatendido\``
|
|
1506
|
-
})
|
|
1507
|
-
}
|
|
1500
|
+
// (Aquí se rechazaba con `no-approver` cuando nadie podía aprobar. Desde 2026-09-24 ese
|
|
1501
|
+
// caso ya no llega: sin aprobadores, `needsApproval` dice que no hace falta aprobación.)
|
|
1508
1502
|
// `from` SE GUARDA: la respuesta llega más tarde —cuando alguien apruebe— y tiene que
|
|
1509
1503
|
// volver POR DONDE VINO. Si la pregunta entró por el mostrador local, mandarla por el
|
|
1510
1504
|
// proxio la deja en el vacío: quien preguntó está escuchando en el socket, no ahí.
|
|
@@ -3636,7 +3630,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
|
|
|
3636
3630
|
if (idos.length) {
|
|
3637
3631
|
const quienes = (await Promise.all(idos.map(async (d) => `${await deviceIdOf(d.pub).catch(() => '????-????')}${d.label ? ` (${d.label})` : ''}`))).join(', ')
|
|
3638
3632
|
audit('no-approver', { removed: idos.length, seq })
|
|
3639
|
-
log(`[vault] WARNING: nobody in the record can approve any more — ${quienes} was the last.
|
|
3633
|
+
log(`[vault] WARNING: nobody in the record can approve any more — ${quienes} was the last. From now on every device gets its keys WITHOUT approval, until you enrol one and grant it \`dotrino-vault caps <ID> +aprueba\``)
|
|
3640
3634
|
}
|
|
3641
3635
|
} catch (e) { log(`[vault] unlock: could not remove expired devices: ${e.message}`) }
|
|
3642
3636
|
}
|