@dotrino/identity 0.80.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.
- package/package.json +1 -1
- package/vault/acta.js +8 -8
- package/vault/remote.js +26 -5
- package/vault/vendor/vault/VERSION.txt +1 -1
- package/vault/vendor/vault/protocol.js +15 -0
package/package.json
CHANGED
package/vault/acta.js
CHANGED
|
@@ -968,8 +968,8 @@ export function effectiveCaps (acta, pub, extraRenounces = []) {
|
|
|
968
968
|
* `ns` es opcional y es para lo que va atado a un cajón: un servicio (miembro con `cn`)
|
|
969
969
|
* solo firma dentro del suyo. Sin `ns`, se pregunta por la capacidad a secas.
|
|
970
970
|
*/
|
|
971
|
-
export function memberCanSign (acta, pub, ns = null) {
|
|
972
|
-
if (!memberCan(acta, pub, 'sign')) return false
|
|
971
|
+
export function memberCanSign (acta, pub, ns = null, extraRenounces = []) {
|
|
972
|
+
if (!memberCan(acta, pub, 'sign', extraRenounces)) return false
|
|
973
973
|
const m = (acta?.members || []).find((x) => x.pub === pub)
|
|
974
974
|
// SIN `cn` = un aparato TUYO: firma como tú, y no hay nada que preguntarle a nadie.
|
|
975
975
|
if (!m?.cn) return true
|
|
@@ -996,19 +996,19 @@ export function memberCanSign (acta, pub, ns = null) {
|
|
|
996
996
|
* Devuelve `false` ante un scope que no reconoce: si aparece uno nuevo, lo que toca es
|
|
997
997
|
* añadirlo aquí, no que se cuele por no estar en la lista.
|
|
998
998
|
*/
|
|
999
|
-
export function memberCanScope (acta, pub, scope) {
|
|
999
|
+
export function memberCanScope (acta, pub, scope, extraRenounces = []) {
|
|
1000
1000
|
if (!acta || typeof scope !== 'string') return false
|
|
1001
1001
|
const secretos = /^vault:secrets:([a-z0-9-]{1,32})$/.exec(scope)
|
|
1002
|
-
if (secretos) return memberCanReadSecrets(acta, pub, secretos[1])
|
|
1003
|
-
if (scope === 'vault:sign') return memberCanSign(acta, pub)
|
|
1002
|
+
if (secretos) return memberCanReadSecrets(acta, pub, secretos[1], extraRenounces)
|
|
1003
|
+
if (scope === 'vault:sign') return memberCanSign(acta, pub, null, extraRenounces)
|
|
1004
1004
|
const cap = Object.keys(CAP_SCOPE).find((c) => CAP_SCOPE[c] === scope)
|
|
1005
|
-
return cap ? memberCan(acta, pub, cap) : false
|
|
1005
|
+
return cap ? memberCan(acta, pub, cap, extraRenounces) : false
|
|
1006
1006
|
}
|
|
1007
1007
|
|
|
1008
|
-
export function memberCanReadSecrets (acta, pub, ns) {
|
|
1008
|
+
export function memberCanReadSecrets (acta, pub, ns, extraRenounces = []) {
|
|
1009
1009
|
const m = (acta?.members || []).find((x) => x.pub === pub)
|
|
1010
1010
|
if (!m || !m.cn) return false
|
|
1011
|
-
return m.cn === ns && effectiveCaps(acta, pub).includes('secrets')
|
|
1011
|
+
return m.cn === ns && effectiveCaps(acta, pub, extraRenounces).includes('secrets')
|
|
1012
1012
|
}
|
|
1013
1013
|
|
|
1014
1014
|
/** Los scopes de cert que le corresponden a un miembro según el acta. */
|
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(
|
|
303
|
+
graceTimer = setTimeout(() => { cleanup(); reject(vaultError(p)) }, REVOKE_GRACE_MS)
|
|
289
304
|
return
|
|
290
305
|
}
|
|
291
|
-
cleanup(); reject(
|
|
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
|
-
|
|
411
|
-
|
|
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,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Copia vendorizada de @dotrino/vault@0.
|
|
1
|
+
Copia vendorizada de @dotrino/vault@0.61.0 (dotrino-vault/lib/src/{index,enroll,protocol}.js).
|
|
2
2
|
NO se edita a mano: la escribe `node vendor.mjs` y la vigila test/vendor-up-to-date.test.mjs.
|
|
3
3
|
index.js importa ./enroll.js y ./protocol.js (relativos, van en esta misma copia),
|
|
4
4
|
@dotrino/identity/{capabilities,acta} (= ../../{capabilities,acta}.js) y
|
|
@@ -128,3 +128,18 @@ export const isValidSecretsNs = (ns) => typeof ns === 'string' && /^[a-z0-9-]{1,
|
|
|
128
128
|
* remota y el lector de `.env`, y tres copias de una regla son tres reglas.
|
|
129
129
|
*/
|
|
130
130
|
export const isValidVarKey = (key) => typeof key === 'string' && /^[A-Z0-9_]{1,64}$/.test(key)
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* LA VERSIÓN DEL CABLE (CONVENCIONES §14, `@dotrino/compat`).
|
|
134
|
+
*
|
|
135
|
+
* Sube **solo cuando cambia el protocolo**, no con cada release: es lo que decide *si dos
|
|
136
|
+
* piezas pueden hablar*. La `version` del paquete decide otra cosa —si esa build concreta
|
|
137
|
+
* está rota— y por eso hacen falta las dos.
|
|
138
|
+
*
|
|
139
|
+
* Empieza en 1 hoy, con todo lo anterior sin declarar nada: a quien calla se le atiende
|
|
140
|
+
* hasta que cierre la ventana de migración del pilar, y después no.
|
|
141
|
+
*/
|
|
142
|
+
export const VAULT_PROTOCOL = 1
|
|
143
|
+
|
|
144
|
+
/** Los protocolos que esta build entiende. Al añadir el 2, aquí van `[1, 2]`. */
|
|
145
|
+
export const VAULT_SPEAKS = [1]
|