@dotrino/vaultd 0.111.0 → 0.111.1

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/client.js +16 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotrino/vaultd",
3
- "version": "0.111.0",
3
+ "version": "0.111.1",
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/client.js CHANGED
@@ -194,16 +194,29 @@ export async function requestStore ({ masterPubkey, proxyUrl, device, cert, meth
194
194
  * El `nonce` de un solo uso NO es decorativo: `approve` y `revoke` cambian estado, así
195
195
  * que la ventana de frescura de ±5 min no basta para descartar un replay.
196
196
  */
197
- export async function requestAdmin ({ masterPubkey, proxyUrl, device, cert, op, dir, ...rest } = {}) {
197
+ export async function requestAdmin ({ masterPubkey, proxyUrl, device, cert, op, dir, nonce: dado, ...rest } = {}) {
198
198
  const client = await freshClient({ proxyUrl, dir })
199
199
  try {
200
- const nonce = [...crypto.getRandomValues(new Uint8Array(16))].map((b) => b.toString(16).padStart(2, '0')).join('')
200
+ // EL NONCE SE PUEDE DAR. Abrir la bóveda a distancia lo mete TAMBIÉN dentro del sobre
201
+ // sellado —es lo que impide reenviar uno capturado con un nonce nuevo— y quien sella
202
+ // tiene que conocerlo antes de llamar.
203
+ const nonce = typeof dado === 'string' && dado.length >= 16
204
+ ? dado
205
+ : [...crypto.getRandomValues(new Uint8Array(16))].map((b) => b.toString(16).padStart(2, '0')).join('')
201
206
  const data = { op, ...rest, publickey: device.publickey, ts: Date.now(), nonce }
202
207
  const { signature } = await signWithDevice({ privateJwk: device.privateJwk, data })
203
208
  const pending = waitFor(client, (p) => p.type === MSG.ADMIN_RESULT || p.type === MSG.ERROR)
204
209
  client.sendByPubkey(masterPubkey, { type: MSG.ADMIN, data, signature, cert })
205
210
  const res = await pending
206
- if (res.type === MSG.ERROR) throw new Error(res.error)
211
+ if (res.type === MSG.ERROR) {
212
+ // CON LO QUE TRAE: el `code` y —al abrir— el freno. Emparejar por el TEXTO es lo que
213
+ // rompe en silencio en cuanto alguien lo traduce.
214
+ const e = new Error(res.error)
215
+ if (res.code) e.code = res.code
216
+ if (res.tries != null) e.tries = res.tries
217
+ if (res.waitSec != null) e.waitSec = res.waitSec
218
+ throw e
219
+ }
207
220
  return res.result
208
221
  } finally { client.close() }
209
222
  }