@dotrino/vault 0.90.1 → 0.90.3

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotrino/vault",
3
- "version": "0.90.1",
3
+ "version": "0.90.3",
4
4
  "description": "La bóveda de Dotrino como librería: el MISMO núcleo que el binario corriendo en el navegador (`@dotrino/vault/browser`), el mostrador de emparejamiento y 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",
@@ -5,4 +5,4 @@
5
5
  * si no coincide con la del paquete: una versión anunciada que no es la que corre es peor
6
6
  * que no anunciar ninguna.
7
7
  */
8
- export const LIB_VERSION = '0.90.1'
8
+ export const LIB_VERSION = '0.90.3'
package/src/deviceInfo.js CHANGED
@@ -14,12 +14,10 @@
14
14
  * Sirve cualquier enlace con la forma común `{ device: { publickey }, cert, iss, proxy }`
15
15
  * (el de remote-agent y el de un servicio de dotrino-env).
16
16
  */
17
- import { pubkeyId } from '@dotrino/identity/capabilities'
17
+ import { keyLabel } from '@dotrino/identity/capabilities'
18
18
 
19
19
  /** El id corto de una llave, como lo enseña la bóveda: `AB12-CD34`. */
20
- export async function shortId (publickey) {
21
- return (await pubkeyId(publickey)).slice(0, 8).toUpperCase().replace(/(.{4})(.{4})/, '$1-$2')
22
- }
20
+ export const shortId = keyLabel
23
21
 
24
22
  /**
25
23
  * La información del aparato a partir de su enlace.
package/src/sealed.js CHANGED
@@ -16,30 +16,13 @@
16
16
  * P-256 + AES-GCM, llaves como JWK string.
17
17
  */
18
18
 
19
- const subtle = globalThis.crypto.subtle
20
-
21
- function b64 (buf) {
22
- const bytes = new Uint8Array(buf)
23
- let s = ''
24
- for (let i = 0; i < bytes.length; i++) s += String.fromCharCode(bytes[i])
25
- return btoa(s)
26
- }
19
+ import { wrapForMember, openWrap } from '@dotrino/identity/content'
27
20
 
28
- function fromB64 (str) {
29
- const bin = atob(str)
30
- const out = new Uint8Array(bin.length)
31
- for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i)
32
- return out
33
- }
21
+ // El sobre es el MISMO que el de las llaves de contenido de identity (ECDH P-256 efímero
22
+ // → AES-256-GCM, `epk` en JWK): aquí solo se le mete un JSON en vez de una CEK. Antes
23
+ // estaba escrito otra vez en este archivo, byte a byte igual.
34
24
 
35
- async function deriveAesKey (privateKey, publicJwkStr) {
36
- const pub = await subtle.importKey(
37
- 'jwk', JSON.parse(publicJwkStr),
38
- { name: 'ECDH', namedCurve: 'P-256' }, false, []
39
- )
40
- const bits = await subtle.deriveBits({ name: 'ECDH', public: pub }, privateKey, 256)
41
- return subtle.importKey('raw', bits, { name: 'AES-GCM' }, false, ['encrypt', 'decrypt'])
42
- }
25
+ const subtle = globalThis.crypto.subtle
43
26
 
44
27
  /**
45
28
  * Genera la llave ECDH EFÍMERA del solicitante (una por petición).
@@ -57,17 +40,7 @@ export async function makeEphemeralKey () {
57
40
  * @returns {Promise<{epk:string, iv:string, ct:string}>}
58
41
  */
59
42
  export async function seal ({ ek, payload }) {
60
- const eph = await subtle.generateKey({ name: 'ECDH', namedCurve: 'P-256' }, false, ['deriveBits'])
61
- const key = await deriveAesKey(eph.privateKey, ek)
62
- const iv = globalThis.crypto.getRandomValues(new Uint8Array(12))
63
- const pt = new TextEncoder().encode(JSON.stringify(payload))
64
- const ct = await subtle.encrypt({ name: 'AES-GCM', iv }, key, pt)
65
- const epkJwk = await subtle.exportKey('jwk', eph.publicKey)
66
- return {
67
- epk: JSON.stringify({ kty: epkJwk.kty, crv: epkJwk.crv, x: epkJwk.x, y: epkJwk.y }),
68
- iv: b64(iv),
69
- ct: b64(ct)
70
- }
43
+ return wrapForMember({ cek: JSON.stringify(payload), memberEncPub: ek })
71
44
  }
72
45
 
73
46
  /**
@@ -78,7 +51,5 @@ export async function openSealed ({ privateKey, enc }) {
78
51
  if (!enc || typeof enc.epk !== 'string' || typeof enc.iv !== 'string' || typeof enc.ct !== 'string') {
79
52
  throw new Error('invalid sealed envelope')
80
53
  }
81
- const key = await deriveAesKey(privateKey, enc.epk)
82
- const pt = await subtle.decrypt({ name: 'AES-GCM', iv: fromB64(enc.iv) }, key, fromB64(enc.ct))
83
- return JSON.parse(new TextDecoder().decode(pt))
54
+ return JSON.parse(await openWrap({ wrap: enc, myEncPrivateKey: privateKey }))
84
55
  }
package/src/service.js CHANGED
@@ -23,7 +23,7 @@ import path from 'node:path'
23
23
  import { createHash } from 'node:crypto'
24
24
  import {
25
25
  makeDeviceKey, makeDeviceEncKey, importDeviceEncKey, signWithDevice,
26
- verifyDeviceSig, makePairingCode, commitCode, pubkeyId } from '@dotrino/identity/capabilities'
26
+ verifyDeviceSig, makePairingCode, commitCode, pubkeyId, keyLabel } from '@dotrino/identity/capabilities'
27
27
  import { openWrap, wrapForMember, decryptWithCek } from '@dotrino/identity/content'
28
28
  import { verifyActa, sealKeyAt, memberCan, checkVaultReply } from '@dotrino/identity/acta'
29
29
  import { MSG, secretsScope, isValidSecretsNs, VAULT_PROTOCOL, VAULT_SPEAKS } from './protocol.js'
@@ -373,7 +373,7 @@ export async function enrollWithVault ({ qr, label = 'agent', expectedScope = nu
373
373
  // aparato entra al acta pero no le llega ningún secreto, y no da error. Un replicador
374
374
  // entra así A PROPÓSITO (ver `withEncKey`): reparte sobres cerrados y no abre ninguno.
375
375
  const enc = withEncKey ? await makeDeviceEncKey() : null
376
- const deviceId = (await pubkeyId(device.publickey)).slice(0, 8).toUpperCase().replace(/(.{4})(.{4})/, '$1-$2')
376
+ const deviceId = await keyLabel(device.publickey)
377
377
  // Código de emparejamiento ALEATORIO: se muestra y NO se envía. La bóveda lo
378
378
  // aprende solo cuando un humano lo tipea → aprobar exige TENER esta máquina.
379
379
  const code = makePairingCode()