@dotrino/vaultd 0.153.2 → 0.154.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.
- package/lib/src/index.js +4 -1
- package/package.json +2 -2
- package/src/transport.js +15 -3
- package/src/vault.js +8 -2
package/lib/src/index.js
CHANGED
|
@@ -217,7 +217,10 @@ export async function startDeviceVault (identity, { proxyUrl, client: injectedCl
|
|
|
217
217
|
deviceId: x.sub ? await deviceIdOf(x.sub) : null, sub: x.sub || null,
|
|
218
218
|
label: x.label || '', scope: x.scope, seq: x.seq, nonce: x.nonce
|
|
219
219
|
})))
|
|
220
|
-
|
|
220
|
+
// La cadena de selladores va con la lista (como en el daemon): es lo que un aparato de
|
|
221
|
+
// Node necesita para firmar a nombre de la cuenta de forma que un extraño lo compruebe.
|
|
222
|
+
const sealerChain = await identity.sealerChain?.().catch(() => null) || null
|
|
223
|
+
send(from, { type: MSG.DEVICES_RESULT, devices, revoked: (revoked || []).map((r) => r.nonce || r), sealerChain })
|
|
221
224
|
// ¿el que consulta es una máquina revocada que reapareció? → re-emite el REVOKED firmado.
|
|
222
225
|
// Se busca en `revokedCerts`: desde que `issued` solo trae lo vigente, los retirados
|
|
223
226
|
// ya no están ahí y este aviso dejaba de dispararse (se caía en silencio).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dotrino/vaultd",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.154.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": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"@dotrino/identity": "^0.111.0",
|
|
26
26
|
"@dotrino/opaque": "0.1.0",
|
|
27
27
|
"@dotrino/passmanager": "0.17.0",
|
|
28
|
-
"@dotrino/proxy-client": "^0.32.
|
|
28
|
+
"@dotrino/proxy-client": "^0.32.2",
|
|
29
29
|
"@dotrino/roadmap": "0.3.19",
|
|
30
30
|
"@dotrino/store": "0.11.0",
|
|
31
31
|
"@dotrino/update": "0.5.1",
|
package/src/transport.js
CHANGED
|
@@ -36,7 +36,7 @@ export async function masterPubkeyOf (identity) {
|
|
|
36
36
|
* @param {string} [opts.url] URL del proxy (default wss://proxy.dotrino.com).
|
|
37
37
|
* @returns {Promise<{ client, token:string, identify():Promise<void> }>}
|
|
38
38
|
*/
|
|
39
|
-
export async function createTransport ({ identity, dir, url = DEFAULT_PROXY, commKey = null, log = () => {}, makeClient = null, announce = null, recheckMs = 60_000, reannounceMs = 10 * 60_000 }) {
|
|
39
|
+
export async function createTransport ({ identity, dir, url = DEFAULT_PROXY, commKey = null, log = () => {}, makeClient = null, announce = null, recheckMs = 60_000, patienceMs = 5 * 60_000, reannounceMs = 10 * 60_000 }) {
|
|
40
40
|
installNodeGlobals(dir)
|
|
41
41
|
// Import dinámico DESPUÉS de instalar los globals que el paquete usa.
|
|
42
42
|
// `WebSocketProxyClient` (la clase) y NO el helper `getWebSocketProxyClient`:
|
|
@@ -222,21 +222,33 @@ export async function createTransport ({ identity, dir, url = DEFAULT_PROXY, com
|
|
|
222
222
|
* nada.
|
|
223
223
|
*/
|
|
224
224
|
const RECHECK_MS = recheckMs
|
|
225
|
-
const PATIENCE_MS =
|
|
225
|
+
const PATIENCE_MS = patienceMs
|
|
226
226
|
const REANNOUNCE_MS = reannounceMs // la mitad de lo que el proxio guarda una entrada
|
|
227
227
|
let downSince = 0
|
|
228
228
|
let saidDown = false
|
|
229
229
|
client.on('disconnect', ({ code, reason } = {}) => {
|
|
230
|
+
// Sin socket no hay nadie atado al proxio: lo que se identificó era la conexión anterior.
|
|
231
|
+
identificado = false
|
|
230
232
|
if (!downSince) downSince = Date.now()
|
|
231
233
|
if (saidDown) return
|
|
232
234
|
saidDown = true
|
|
233
235
|
log(`[vault] off the proxy (${code || '?'}${reason ? ': ' + reason : ''}) — nobody can reach this vault while this lasts`)
|
|
234
236
|
})
|
|
237
|
+
// LOS INTENTOS SE VEN. El 2026-10-15 la bóveda pasó hora y media fuera y no quedó ni una
|
|
238
|
+
// línea de si el transporte estaba reintentando o no; en el proxio no llegó ninguno. El
|
|
239
|
+
// primero se dice, y luego uno de cada 15 (un minuto con el retardo de 4 s).
|
|
240
|
+
client.on('reconnecting', (attempt) => {
|
|
241
|
+
if (attempt === 1 || attempt % 15 === 0) log(`[vault] reconnecting to the proxy (attempt ${attempt})`)
|
|
242
|
+
})
|
|
235
243
|
client.on('reconnect_failed', (attempts) => {
|
|
236
244
|
log(`[vault] the transport gave up reconnecting after ${attempts} attempt(s) — this vault is unreachable until it is restarted`)
|
|
237
245
|
})
|
|
238
246
|
const watchdog = setInterval(async () => {
|
|
239
|
-
|
|
247
|
+
// CONECTADO DE VERDAD, no «tengo un token». El token es el de la última conexión y no se
|
|
248
|
+
// borra al caerse, así que mirarlo daba la bóveda por vuelta con el socket cerrado: el
|
|
249
|
+
// 2026-10-15 dijo «back on the proxy after 50s», no volvió a marcar nunca y pasó hora y
|
|
250
|
+
// media fuera, avisando cada 10 minutos de que no podía anunciarse.
|
|
251
|
+
if (identificado && client.isConnected && client.token) {
|
|
240
252
|
if (downSince) log(`[vault] back on the proxy after ${Math.round((Date.now() - downSince) / 1000)}s`)
|
|
241
253
|
downSince = 0; saidDown = false
|
|
242
254
|
// EL ANUNCIO CADUCA: el proxio borra una entrada de canal a los 20 minutos de publicada.
|
package/src/vault.js
CHANGED
|
@@ -1288,6 +1288,12 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
|
|
|
1288
1288
|
// sigue pidiendo `lee`. Antes no preguntaba nada, así que un aparato al que le quitaste
|
|
1289
1289
|
// el permiso seguía viéndolo todo hasta que su papel caducara.
|
|
1290
1290
|
const record = (await identity.profileActa?.().catch(() => null))?.acta || null
|
|
1291
|
+
// LA CADENA DE SELLADORES VIAJA CON LA LISTA, también para quien solo puede ver
|
|
1292
|
+
// revocaciones. Es lo que un aparato de Node necesita para FIRMAR a nombre de la cuenta
|
|
1293
|
+
// de forma que un extraño lo compruebe (`verifySignedFor` exige la cadena desde el
|
|
1294
|
+
// génesis), y hasta ahora ningún agente headless podía: solo el navegador la tenía. Es
|
|
1295
|
+
// corta a propósito (génesis, cambios de sellador, actual), así que no pasa por `fitChain`.
|
|
1296
|
+
const sealerChainOf = async () => { try { return (await identity.sealerChain?.()) || null } catch (e) { log('[vault] could not build the sealer chain:', e.message); return null } }
|
|
1291
1297
|
const puedeVerTodo = !!record && Acta.memberCanScope(record, chk.device, SCOPE.READ)
|
|
1292
1298
|
const { issued, revoked } = await identity.listDelegations()
|
|
1293
1299
|
if (!puedeVerTodo) {
|
|
@@ -1296,7 +1302,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
|
|
|
1296
1302
|
return reply(from, { type: MSG.ERROR, error: 'unauthorized: this vault has no record to decide with' })
|
|
1297
1303
|
}
|
|
1298
1304
|
audit('devices', { device: await deviceIdOf(chk.device).catch(() => null), solo: 'revocaciones' })
|
|
1299
|
-
return reply(from, { type: MSG.DEVICES_RESULT, devices: [], revoked, blocked: blocked.pubs(), acta: record })
|
|
1305
|
+
return reply(from, { type: MSG.DEVICES_RESULT, devices: [], revoked, blocked: blocked.pubs(), acta: record, sealerChain: await sealerChainOf() })
|
|
1300
1306
|
}
|
|
1301
1307
|
// El acta viaja con la lista: así cada dispositivo se entera de los cambios de
|
|
1302
1308
|
// política (quién manda, quién puede qué) sin un canal aparte.
|
|
@@ -1329,7 +1335,7 @@ export async function startVault ({ dir = dataDir(), proxyUrl, log = console.log
|
|
|
1329
1335
|
// LA SUBACTA VIAJA CON EL ACTA. Es la mitad de «se comparte entre todos los
|
|
1330
1336
|
// dispositivos»: sin esto, una renuncia sin sellar solo la respeta esta máquina.
|
|
1331
1337
|
// Cada entrada va firmada por su sujeto, así que quien la recibe la verifica sola.
|
|
1332
|
-
reply(from, fitChain({ type: MSG.DEVICES_RESULT, devices, revoked, blocked: blocked.pubs(), acta: record, chain, vault: MI_VERSION, subacta: subacta.entries() }))
|
|
1338
|
+
reply(from, fitChain({ type: MSG.DEVICES_RESULT, devices, revoked, blocked: blocked.pubs(), acta: record, chain, sealerChain: await sealerChainOf(), vault: MI_VERSION, subacta: subacta.entries() }))
|
|
1333
1339
|
}
|
|
1334
1340
|
|
|
1335
1341
|
/**
|