@dotrino/vault 0.43.0 → 0.45.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 +1 -1
- package/src/admin.js +2 -6
- package/src/service.js +17 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dotrino/vault",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.45.0",
|
|
4
4
|
"description": "Usa ESTE dispositivo (navegador) como bóveda/CA del ecosistema Dotrino: atiende enrolamientos por el proxy y firma certificados de delegación a tus máquinas. Incluye el cliente de SERVICIO (Node): un proyecto se enrola una vez y jala sus credenciales del vault en vez del .env (`import '@dotrino/vault/config'`).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
package/src/admin.js
CHANGED
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
export const ADMIN_OPS = Object.freeze([
|
|
47
47
|
// `pending`, `pair`, `approve` y `reject` NO están, y no es un olvido: agregar aparatos
|
|
48
48
|
// a distancia se quitó (ver la cabecera). Lo que queda es mirar, quitar y configurar.
|
|
49
|
-
'
|
|
49
|
+
'revoke', 'audit',
|
|
50
50
|
// Variables de entorno: verlas (nombres siempre; valor solo de las públicas) y
|
|
51
51
|
// ponerles valor (de las dos). Borrar NO está, y es a propósito: un aparato robado
|
|
52
52
|
// no debe poder dejar sin configuración a los servicios.
|
|
@@ -72,7 +72,7 @@ export const ADMIN_OPS = Object.freeze([
|
|
|
72
72
|
* Se dejan las de LEER a propósito: si se cortaran todas, la consola no podría ni
|
|
73
73
|
* enterarse de por qué no funciona y parecería rota. Así puede decir «está cerrada».
|
|
74
74
|
*/
|
|
75
|
-
export const ADMIN_OPS_WHILE_LOCKED = Object.freeze(['
|
|
75
|
+
export const ADMIN_OPS_WHILE_LOCKED = Object.freeze(['audit', 'vars'])
|
|
76
76
|
|
|
77
77
|
/** Cuánto se recuerda un nonce ya usado (el doble de la ventana de frescura). */
|
|
78
78
|
export const ADMIN_NONCE_TTL_MS = 10 * 60 * 1000
|
|
@@ -159,10 +159,6 @@ export function createAdminDesk ({
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
try {
|
|
162
|
-
// Lo mínimo que la consola necesita saber de la bóveda para explicarse: si está
|
|
163
|
-
// cerrada, lo que queda (revocar, configurar) no se puede, y hay que decir por qué en
|
|
164
|
-
// vez de dejar pulsar un botón para recibir un error.
|
|
165
|
-
if (data.op === 'status') return { ok: true, result: { locked: !!isLocked() } }
|
|
166
162
|
|
|
167
163
|
if (data.op === 'audit') {
|
|
168
164
|
const limit = Math.min(Math.max(Number(data.limit) || 100, 1), AUDIT_MAX)
|
package/src/service.js
CHANGED
|
@@ -421,7 +421,7 @@ export async function registerEncKey ({ dir, ns, proxyUrl, masterPubkey, device,
|
|
|
421
421
|
* Renueva el cert automáticamente si está por vencer (best-effort).
|
|
422
422
|
* @returns {Promise<Record<string,string>>} secretos KEY→valor
|
|
423
423
|
*/
|
|
424
|
-
export async function fetchSecrets ({ dir, ns, proxyUrl, masterPubkey, device, cert, enc, timeoutMs = 30000, onPending, approvalTimeoutMs = APPROVAL_TIMEOUT_MS } = {}) {
|
|
424
|
+
export async function fetchSecrets ({ dir, ns, proxyUrl, masterPubkey, device, cert, enc, timeoutMs = 30000, onPending, onCert, approvalTimeoutMs = APPROVAL_TIMEOUT_MS } = {}) {
|
|
425
425
|
let saved = null
|
|
426
426
|
if (dir) saved = readServiceIdentity(dir)
|
|
427
427
|
// Sin `dir`: la identidad viene entera por parámetros — es el caso de un agente
|
|
@@ -465,7 +465,15 @@ export async function fetchSecrets ({ dir, ns, proxyUrl, masterPubkey, device, c
|
|
|
465
465
|
recordar({ actaSeq: acta.seq })
|
|
466
466
|
}
|
|
467
467
|
|
|
468
|
-
|
|
468
|
+
// DOS MOTIVOS PARA PEDIR PAPEL NUEVO:
|
|
469
|
+
// · el nuestro es del MODELO VIEJO (lleva `exp` y no `seq`). Ese hay que cambiarlo sí
|
|
470
|
+
// o sí: se acepta por el repliegue de migración, pero muere en su fecha y con él el
|
|
471
|
+
// servicio. Sin esta rama la migración no terminaba nunca — el disparador comparaba
|
|
472
|
+
// `seq` contra `seq`, y un papel viejo no tiene ninguno, así que no saltaba jamás.
|
|
473
|
+
// · o el acta que hemos visto va por delante del papel: el dueño cambió permisos.
|
|
474
|
+
const legado = !!cert && typeof cert.seq !== 'number'
|
|
475
|
+
const atrasado = typeof saved?.actaSeq === 'number' && typeof cert?.seq === 'number' && saved.actaSeq > cert.seq
|
|
476
|
+
const renovar = legado || atrasado
|
|
469
477
|
|
|
470
478
|
// RENOVAR YA NO ES UNA TAREA DE CALENDARIO. El papel no vence: lo único que obliga a
|
|
471
479
|
// pedir otro es que la bóveda diga que el nuestro se quedó atrás respecto del acta, y
|
|
@@ -481,6 +489,11 @@ export async function fetchSecrets ({ dir, ns, proxyUrl, masterPubkey, device, c
|
|
|
481
489
|
if (res.type === MSG.RENEWED && res.cert?.sub === device.publickey) {
|
|
482
490
|
cert = res.cert
|
|
483
491
|
recordar({ cert })
|
|
492
|
+
// QUIEN NO PASA `dir` GUARDA ÉL. Un servicio que lleva su identidad en su propio
|
|
493
|
+
// archivo (`link.json`) y nos pasa el enlace a mano no tiene `saved`, así que
|
|
494
|
+
// `recordar` no escribe nada: sin esto renovaba en cada arranque y volvía a
|
|
495
|
+
// empezar, y su papel del modelo viejo no se cambiaba NUNCA.
|
|
496
|
+
try { onCert?.(cert) } catch (_) {}
|
|
484
497
|
}
|
|
485
498
|
} catch (_) { /* la renovación no bloquea el fetch */ }
|
|
486
499
|
}
|
|
@@ -978,11 +991,11 @@ function fingerprintOf (secrets) {
|
|
|
978
991
|
* servicio no opera hasta que esto resuelva — esa es la regla.
|
|
979
992
|
* @returns {Promise<Record<string,string>>}
|
|
980
993
|
*/
|
|
981
|
-
export async function waitForSecrets ({ dir, ns, proxyUrl, masterPubkey, device, cert, enc, retryMs = 5000, maxRetryMs = 60000, onRetry, onPending } = {}) {
|
|
994
|
+
export async function waitForSecrets ({ dir, ns, proxyUrl, masterPubkey, device, cert, enc, retryMs = 5000, maxRetryMs = 60000, onRetry, onPending, onCert } = {}) {
|
|
982
995
|
let delay = retryMs
|
|
983
996
|
for (;;) {
|
|
984
997
|
try {
|
|
985
|
-
return await fetchSecrets({ dir, ns, proxyUrl, masterPubkey, device, cert, enc, onPending })
|
|
998
|
+
return await fetchSecrets({ dir, ns, proxyUrl, masterPubkey, device, cert, enc, onPending, onCert })
|
|
986
999
|
} catch (e) {
|
|
987
1000
|
// Lo NO transitorio no se arregla reintentando: falta de enrolamiento,
|
|
988
1001
|
// cert revocado/vencido o scope equivocado exigen re-emparejar → se corta.
|