@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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/service.js +55 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotrino/vault",
3
- "version": "0.25.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.