@dotrino/identity 0.81.0 → 0.82.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/vault/remote.js +26 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotrino/identity",
3
- "version": "0.81.0",
3
+ "version": "0.82.0",
4
4
  "description": "Identidad y rating de usuarios compartidos entre apps de Dotrino (vault iframe + postMessage)",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/vault/remote.js CHANGED
@@ -258,6 +258,21 @@ const REVOKE_GRACE_MS = 1500
258
258
  * dispositivo estaba apagado la bóveda emitió un `vault.revoked` firmado, llega aquí y se
259
259
  * ejecuta el autoborrado (`onRevoked`) tras verificar la firma contra la maestra pineada.
260
260
  */
261
+ /**
262
+ * EL ERROR DE LA BÓVEDA, CON LO QUE TRAE. Se rechazaba con `new Error(p.error)` a secas y
263
+ * se perdían el `code` y —desde que se puede abrir a distancia— el freno: cuántos intentos
264
+ * van y cuánto hay que esperar. Sin eso, quien llama solo puede emparejar por el TEXTO, que
265
+ * es justo lo que rompe en silencio cuando alguien lo traduce («los errores son un
266
+ * contrato»), y el admin reintenta contra una puerta que ya no responde sin saber por qué.
267
+ */
268
+ function vaultError (p) {
269
+ const e = new Error(p?.error || 'vault error')
270
+ if (p?.code) e.code = p.code
271
+ if (p?.tries != null) e.tries = p.tries
272
+ if (p?.waitSec != null) e.waitSec = p.waitSec
273
+ return e
274
+ }
275
+
261
276
  async function vaultRpc ({ master, proxy, device, cert, acta = null, sendType, okType, data, onRevoked, timeoutMs = 15000 }) {
262
277
  if (!master || !proxy || !(device?.privateJwk || device?.privateKey) || !cert) throw new Error('missing pairing data')
263
278
  const { WebSocketProxyClient } = await import('@dotrino/proxy-client')
@@ -285,10 +300,10 @@ async function vaultRpc ({ master, proxy, device, cert, acta = null, sendType, o
285
300
  // antes que el segundo, y entonces el aparato se quedaba con la cuenta puesta
286
301
  // hasta vaya a saber cuándo. Se le da un respiro corto para recogerlo.
287
302
  if (/\brevoked\b/.test(p.error || '') && !graceTimer) {
288
- graceTimer = setTimeout(() => { cleanup(); reject(new Error(p.error)) }, REVOKE_GRACE_MS)
303
+ graceTimer = setTimeout(() => { cleanup(); reject(vaultError(p)) }, REVOKE_GRACE_MS)
289
304
  return
290
305
  }
291
- cleanup(); reject(new Error(p.error))
306
+ cleanup(); reject(vaultError(p))
292
307
  }
293
308
  })
294
309
  const t = setTimeout(() => { cleanup(); reject(new Error('the vault did not reply (is it running?)')) }, timeoutMs)
@@ -406,9 +421,15 @@ export async function requestRenounce ({ master, proxy, device, cert, record, on
406
421
  * El `nonce` de un solo uso va en cada petición porque `approve` y `revoke` cambian
407
422
  * estado, y para eso la ventana de frescura de ±5 min no alcanza.
408
423
  */
409
- export async function requestAdmin ({ master, proxy, device, cert, op, onRevoked, ...rest } = {}) {
410
- const nonce = [...crypto.getRandomValues(new Uint8Array(16))]
411
- .map((b) => b.toString(16).padStart(2, '0')).join('')
424
+ export async function requestAdmin ({ master, proxy, device, cert, op, onRevoked, nonce: dado, ...rest } = {}) {
425
+ // EL NONCE SE PUEDE DAR, y hace falta para abrir la bóveda a distancia: ahí va también
426
+ // DENTRO del sobre sellado, y quien lo sella tiene que conocerlo antes de llamar. Si se
427
+ // generara siempre aquí, el de fuera y el de dentro no podrían coincidir — y el de
428
+ // dentro es el que impide que un sobre capturado se reenvíe con un nonce nuevo.
429
+ const nonce = typeof dado === 'string' && dado.length >= 16
430
+ ? dado
431
+ : [...crypto.getRandomValues(new Uint8Array(16))]
432
+ .map((b) => b.toString(16).padStart(2, '0')).join('')
412
433
  const res = await vaultRpc({
413
434
  master, proxy, device, cert, onRevoked,
414
435
  sendType: MSG.ADMIN, okType: MSG.ADMIN_RESULT,