@dotrino/vault 0.25.0 → 0.26.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/service.js +55 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dotrino/vault",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.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/service.js
CHANGED
|
@@ -327,6 +327,61 @@ export async function enrollService ({ qr, ns, dir, label, onCode, onReplace, ap
|
|
|
327
327
|
} finally { client.close() }
|
|
328
328
|
}
|
|
329
329
|
|
|
330
|
+
/**
|
|
331
|
+
* Se asegura de que este servicio TENGA llave de cifrado, generándola si le falta.
|
|
332
|
+
*
|
|
333
|
+
* Existe para los agentes que se enrolaron ANTES de que la llave existiera: su
|
|
334
|
+
* `service-identity.json` es v1 y solo lleva la de firma. Sin esto, la única forma de
|
|
335
|
+
* conseguirla sería re-enrolarse — y re-enrolar le cambia la pubkey, con lo que pierde
|
|
336
|
+
* su cajón de variables (va indexado por ella) y arrancaría sin configuración, en
|
|
337
|
+
* silencio. Ese es justo el accidente que esta función existe para evitar.
|
|
338
|
+
*
|
|
339
|
+
* La llave de FIRMA no se toca: de ella sale el `nodeId` del proxio.
|
|
340
|
+
*
|
|
341
|
+
* @returns {Promise<{ encPub: string, created: boolean }>}
|
|
342
|
+
*/
|
|
343
|
+
export async function ensureEncKey ({ dir } = {}) {
|
|
344
|
+
const saved = readServiceIdentity(dir)
|
|
345
|
+
if (!saved) throw new Error('service not enrolled: run enrollService() first')
|
|
346
|
+
if (saved.enc?.publickey && saved.enc?.privateJwk) return { encPub: saved.enc.publickey, created: false }
|
|
347
|
+
const enc = await makeDeviceEncKey()
|
|
348
|
+
writeServiceIdentity(dir, { ...saved, v: 2, enc: { publickey: enc.encPublickey, privateJwk: enc.encPrivateJwk } })
|
|
349
|
+
return { encPub: enc.encPublickey, created: true }
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Registra en la bóveda la llave de cifrado de ESTE servicio, para que pueda sellarle
|
|
354
|
+
* sus variables. Genera la llave si falta.
|
|
355
|
+
*
|
|
356
|
+
* Va por `MSG.SECRETS` con `op:'enckey'` a propósito: no hace falta una constante nueva
|
|
357
|
+
* del protocolo, y así el trío de archivos vendorizado en el iframe de identidad no se
|
|
358
|
+
* mueve. Registrar una llave no da acceso a nada por sí solo —quien firma esta petición
|
|
359
|
+
* ya tiene la llave de firma del servicio, o sea ya lee ese namespace—, así que no exige
|
|
360
|
+
* la contraseña del perfil.
|
|
361
|
+
*/
|
|
362
|
+
export async function registerEncKey ({ dir, ns, proxyUrl, masterPubkey, device, cert, timeoutMs = 30000 } = {}) {
|
|
363
|
+
const saved = readServiceIdentity(dir)
|
|
364
|
+
const { encPub, created } = await ensureEncKey({ dir })
|
|
365
|
+
ns = ns || saved?.ns
|
|
366
|
+
proxyUrl = proxyUrl || saved?.proxy
|
|
367
|
+
masterPubkey = masterPubkey || saved?.iss
|
|
368
|
+
device = device || saved?.device
|
|
369
|
+
cert = cert || saved?.cert
|
|
370
|
+
if (!proxyUrl || !masterPubkey || !device || !cert) throw new Error('service not enrolled')
|
|
371
|
+
|
|
372
|
+
const client = await freshClient(proxyUrl)
|
|
373
|
+
try {
|
|
374
|
+
await identifyAsService(client, device)
|
|
375
|
+
const data = { op: 'enckey', ns, encPub, publickey: device.publickey, ts: Date.now() }
|
|
376
|
+
const { signature } = await signWithDevice({ privateJwk: device.privateJwk, data })
|
|
377
|
+
const pending = waitForMsg(client, (p) => p.type === MSG.SECRETS_RESULT || p.type === MSG.ERROR, timeoutMs)
|
|
378
|
+
client.sendByPubkey(masterPubkey, { type: MSG.SECRETS, data, signature, cert })
|
|
379
|
+
const res = await pending
|
|
380
|
+
if (res.type === MSG.ERROR) throw new Error(res.error)
|
|
381
|
+
return { encPub, created, ok: true }
|
|
382
|
+
} finally { client.close() }
|
|
383
|
+
}
|
|
384
|
+
|
|
330
385
|
/**
|
|
331
386
|
* Pide los secretos del ns al vault (una petición puntual; lanza si falla).
|
|
332
387
|
* Usa la identidad persistida por `enrollService` salvo que se pase explícita.
|