@dotrino/vaultd 0.87.0 → 0.88.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/lib/src/admin.js +3 -1
- package/package.json +1 -1
- package/src/ctl.js +6 -6
- package/src/secretsStore.js +18 -0
- package/src/vault.js +39 -4
package/lib/src/admin.js
CHANGED
|
@@ -204,7 +204,9 @@ export function createAdminDesk ({
|
|
|
204
204
|
const toScope = typeof data.ns === 'string' && !!data.ns
|
|
205
205
|
const toDevice = typeof data.pub === 'string' && !!data.pub
|
|
206
206
|
if (data.op === 'vars') {
|
|
207
|
-
|
|
207
|
+
// QUIÉN PREGUNTA, no solo su nombre: con su llave se le manda la envoltura de
|
|
208
|
+
// cada pública para que pueda abrirla en su casa.
|
|
209
|
+
const result = await vars.list({ by, caller: chk.device })
|
|
208
210
|
audit('admin.vars', { by })
|
|
209
211
|
return { ok: true, result }
|
|
210
212
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dotrino/vaultd",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.88.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/ctl.js
CHANGED
|
@@ -1112,12 +1112,12 @@ async function cmdSecret (rest) {
|
|
|
1112
1112
|
/**
|
|
1113
1113
|
* Una variable en la lista: su nombre, y que TIENE valor. Ninguna lo enseña.
|
|
1114
1114
|
*
|
|
1115
|
-
*
|
|
1116
|
-
*
|
|
1117
|
-
*
|
|
1118
|
-
* una pública era peor que no enseñar nada: parecía que se había perdido.
|
|
1115
|
+
* Las dos van selladas igual desde 2026-09-02. Lo que las separa es que a quien administra
|
|
1116
|
+
* se le hace la envoltura de las PÚBLICAS y la bóveda le manda su sobre, así que puede
|
|
1117
|
+
* abrirlas; de una privada de un cajón con dueño no tiene envoltura ni recibe sobre.
|
|
1119
1118
|
*/
|
|
1120
|
-
const printVar = (k) => console.log(' · %s
|
|
1119
|
+
const printVar = (k) => console.log(' · %s %s', k.key,
|
|
1120
|
+
k.public ? `${k.value ?? '••••••'} (pública)` : '••••••')
|
|
1121
1121
|
/**
|
|
1122
1122
|
* Por qué no se aplicó. El daemon deja el motivo en el volcado siguiente; sin él lo
|
|
1123
1123
|
* único que se podía decir era «revisa los logs», que no ayuda a quien acaba de
|
|
@@ -1187,7 +1187,7 @@ async function cmdSecret (rest) {
|
|
|
1187
1187
|
// QUÉ SIGNIFICA HOY (dueño, 2026-09-02): todas se guardan selladas igual, y `pública`
|
|
1188
1188
|
// solo dice a quién se le entrega SIN APROBACIÓN. Decir «su valor se puede ver» era
|
|
1189
1189
|
// verdad cuando se guardaba en claro; dejarlo ahí sería prometer algo que ya no pasa.
|
|
1190
|
-
console.log('\n(pública) = se entrega sin pedirte aprobación. Todas
|
|
1190
|
+
console.log('\n(pública) = se entrega sin pedirte aprobación y quien administra puede leerla. Todas van cifradas.\n')
|
|
1191
1191
|
printPending(d)
|
|
1192
1192
|
await printNoPassword()
|
|
1193
1193
|
return
|
package/src/secretsStore.js
CHANGED
|
@@ -618,6 +618,24 @@ export function openSecretsStore (dir, { sealer = null, recipients = null, signe
|
|
|
618
618
|
return { gen }
|
|
619
619
|
},
|
|
620
620
|
|
|
621
|
+
/**
|
|
622
|
+
* LA ENTRADA TAL CUAL (sobre, generación, visibilidad) — sin abrir nada.
|
|
623
|
+
*
|
|
624
|
+
* Es lo que hace falta para MANDARLE a alguien una variable que sí puede leer: el sobre
|
|
625
|
+
* viaja cerrado y lo abre en su casa, con su envoltura. Aquí no se descifra.
|
|
626
|
+
*/
|
|
627
|
+
entryOf (owner, key) {
|
|
628
|
+
const [kind, k] = splitOwner(owner)
|
|
629
|
+
const bag = kind === 'ns' ? data.ns : data.dev
|
|
630
|
+
return varsOf(bag, k)[key] || null
|
|
631
|
+
},
|
|
632
|
+
/** La envoltura de ESA generación para ESE miembro, o `null` si no la tiene. */
|
|
633
|
+
wrapOf (owner, gen, memberPub) {
|
|
634
|
+
const [kind, k] = splitOwner(owner)
|
|
635
|
+
const bag = kind === 'ns' ? data.ns : data.dev
|
|
636
|
+
return (bag[k]?.keyring || []).find((g) => g.gen === gen)?.wraps?.[memberPub] || null
|
|
637
|
+
},
|
|
638
|
+
|
|
621
639
|
/**
|
|
622
640
|
* ¿EXISTE YA ESTA VARIABLE? Sin abrirla ni decir qué vale.
|
|
623
641
|
*
|
package/src/vault.js
CHANGED
|
@@ -1358,14 +1358,21 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
|
|
|
1358
1358
|
}
|
|
1359
1359
|
|
|
1360
1360
|
const varsDesk = {
|
|
1361
|
-
async list () {
|
|
1362
|
-
//
|
|
1363
|
-
//
|
|
1361
|
+
async list ({ caller = null } = {}) {
|
|
1362
|
+
// EL VAULT DECIDE QUÉ ENVÍA PARA LEER (dueño, 2026-09-02: «la consola debe tener todos
|
|
1363
|
+
// los sobres; la diferencia es si el vault se los envía para la lectura o no»).
|
|
1364
|
+
//
|
|
1365
|
+
// Tener la envoltura y recibir el sobre son dos cosas: quien administra tiene la
|
|
1366
|
+
// envoltura de cada PÚBLICA, y por eso aquí se le manda el sobre de esas y solo de
|
|
1367
|
+
// esas. Las privadas de un cajón con dueño no se mandan — y aunque se mandaran no
|
|
1368
|
+
// podría abrirlas, porque su envoltura no existe. Dos cerrojos para lo mismo, a
|
|
1369
|
+
// propósito: que uno falle no basta para leerlas.
|
|
1370
|
+
//
|
|
1364
1371
|
// Se sella la lista ENTERA, no solo los valores: el proxy tampoco tiene por qué
|
|
1365
1372
|
// aprender cómo se llaman tus variables ni qué servicios corres.
|
|
1366
1373
|
return {
|
|
1367
1374
|
enc: await identity.sealContent(JSON.stringify({
|
|
1368
|
-
ns: listSecrets(), dev: await listDeviceSecrets(),
|
|
1375
|
+
ns: conSobres(listSecrets(), 'ns', caller), dev: conSobres(await listDeviceSecrets(), 'dev', caller),
|
|
1369
1376
|
// Aparatos que están en el acta pero no pueden abrir lo suyo: hay que
|
|
1370
1377
|
// enseñarlo donde se administra, no solo en el log del servicio.
|
|
1371
1378
|
incomplete: await incompleteMembers(),
|
|
@@ -2327,6 +2334,34 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
|
|
|
2327
2334
|
* de esta máquina»: taparlo justo aquí —en la máquina donde vive, delante de su dueño—
|
|
2328
2335
|
* era lo único que la marca no significaba. La consola remota ya las enseña.
|
|
2329
2336
|
*/
|
|
2337
|
+
/**
|
|
2338
|
+
* LE PONE A CADA PÚBLICA SU SOBRE Y LA ENVOLTURA DE QUIEN PREGUNTA, para que pueda leerla.
|
|
2339
|
+
*
|
|
2340
|
+
* Solo a las públicas: es la política de despacho, y es lo único que cambia entre una y
|
|
2341
|
+
* otra. A una privada no se le manda nada — y aunque se le mandara, quien administra no
|
|
2342
|
+
* tiene su envoltura en un cajón con dueño, así que no la abriría igual.
|
|
2343
|
+
*
|
|
2344
|
+
* Si falta la envoltura de quien pregunta (todavía no se le ha hecho, o el cajón se
|
|
2345
|
+
* escribió antes de que entrara) se manda la variable SIN sobre: se ve que existe y que es
|
|
2346
|
+
* pública, y no se puede leer. Eso es cierto y se arregla abriendo la bóveda; inventarse
|
|
2347
|
+
* un valor o esconder la fila sería peor.
|
|
2348
|
+
*/
|
|
2349
|
+
const conSobres = (lista, tipo, caller) => {
|
|
2350
|
+
if (!caller) return lista
|
|
2351
|
+
const dar = (owner, k) => {
|
|
2352
|
+
if (!k.public) return k
|
|
2353
|
+
const e = secrets.entryOf?.(owner, k.key)
|
|
2354
|
+
const wrap = e?.gen != null ? secrets.wrapOf?.(owner, e.gen, caller) : null
|
|
2355
|
+
return e?.e && wrap ? { ...k, e: e.e, wrap } : k
|
|
2356
|
+
}
|
|
2357
|
+
if (tipo === 'ns') {
|
|
2358
|
+
const out = {}
|
|
2359
|
+
for (const [ns, keys] of Object.entries(lista)) out[ns] = keys.map((k) => dar(`ns:${ns}`, k))
|
|
2360
|
+
return out
|
|
2361
|
+
}
|
|
2362
|
+
return lista.map((row) => ({ ...row, keys: row.keys.map((k) => dar(`dev:${row.pub}`, k)) }))
|
|
2363
|
+
}
|
|
2364
|
+
|
|
2330
2365
|
function listSecrets () {
|
|
2331
2366
|
// YA NO SE ENSEÑA EL VALOR DE UNA PÚBLICA (dueño, 2026-09-02). Desde que todas van en
|
|
2332
2367
|
// sobre, «pública» dejó de significar «en claro»: dice a quién se le despacha sin
|