@dotrino/vaultd 0.91.0 → 0.92.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotrino/vaultd",
3
- "version": "0.91.0",
3
+ "version": "0.92.0",
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/manager.js CHANGED
@@ -136,12 +136,37 @@ export async function startVaultManager ({ root = dataDir(), proxyUrl, log = con
136
136
  * Va aquí y no en `profiles.js` porque el registro de perfiles no sabe de bóvedas
137
137
  * corriendo: sabe de contraseñas. Quien tiene las dos cosas delante es esto.
138
138
  */
139
+ /**
140
+ * ABRIR DE VERDAD, NO SOLO QUITAR EL CANDADO.
141
+ *
142
+ * Esto decía `running.get(id)?.takeMasterKey?.()`, y con un `?.` de por medio un perfil
143
+ * que **no estaba corriendo** se marcaba desbloqueado sin abrir nada. Y hay un caso muy
144
+ * normal en el que no está corriendo: **su maestra está sellada bajo la contraseña**, así
145
+ * que al arrancar el servicio no hay frase con la que abrirlo y se queda fuera
146
+ * (`could not open profile …: vault locked`). Justo el perfil que más falta hace abrir
147
+ * era el único al que `unlock` no le hacía nada.
148
+ *
149
+ * Lo que se veía: `status` decía `🔓 desbloqueado` y **cada** petición contestaba
150
+ * `profile is not open`. La TUI se quedaba sin dispositivos, sin un error a la vista.
151
+ *
152
+ * Ahora se arranca si hace falta, y **si algo falla se vuelve a cerrar**: un candado que
153
+ * dice «abierto» sin estarlo es peor que uno cerrado, porque todo lo que venga detrás
154
+ * falla en otro sitio y por otro motivo.
155
+ */
139
156
  async function unlock (id, password) {
140
157
  const r = await profiles.unlock(id, password)
141
- // `takeMasterKey` además la deja SELLADA la primera vez: un perfil que ya tenía
142
- // contraseña guardaba la maestra bajo la llave de máquina, y se migra aquí, que es el
143
- // único momento en que la llave del perfil está en la mano.
144
- try { await running.get(id)?.takeMasterKey?.() } catch (e) { log('[vault] could not take the master key: %s', e.message) }
158
+ try {
159
+ // El orden importa: `profiles.unlock` ya dejó la llave del perfil disponible
160
+ // (`openKey`), así que ahora `startVault` sí puede abrir su maestra.
161
+ const v = running.get(id) || await open(id)
162
+ // `takeMasterKey` además la deja SELLADA la primera vez: un perfil que ya tenía
163
+ // contraseña guardaba la maestra bajo la llave de máquina, y se migra aquí, que es el
164
+ // único momento en que la llave del perfil está en la mano.
165
+ await v.takeMasterKey()
166
+ } catch (e) {
167
+ try { profiles.lock(id) } catch (_) {}
168
+ throw new Error(`unlocked the profile but could not open it, so it stays closed: ${e.message}`)
169
+ }
145
170
  return r
146
171
  }
147
172
 
package/src/transport.js CHANGED
@@ -82,12 +82,26 @@ export async function createTransport ({ identity, dir, url = DEFAULT_PROXY, com
82
82
  // comunicación en el acta se identifica con la maestra, como siempre. Exige el perfil
83
83
  // ABIERTO —la maestra bajo llave no firma— y por eso se dice en voz alta: mientras se
84
84
  // esté aquí, cerrar el perfil deja la bóveda sin voz.
85
- const publickey = await masterPubkeyOf(identity)
86
- if (!publickey) return
87
- const data = { op: 'identify', publickey, token: client.token, ts: Date.now() }
88
- const { signature } = await identity.signData(data)
89
- log('[vault] identifying with the master key: this vault is not in its own record yet (open the profile once to fix it)')
90
- await client.identify({ data, signature, acta: record })
85
+ //
86
+ // QUEDARSE SIN VOZ NO ES NO ARRANCAR, y aquí eran lo mismo. Un perfil con la maestra
87
+ // sellada y sin llave de comunicación todavía llegaba hasta este `signData`, que tira
88
+ // `vault locked`; el error subía por `createTransport` hasta `startVault` y **el perfil
89
+ // entero se quedaba sin abrir**. Al dueño le pasó el 2026-09-02: su perfil principal no
90
+ // arrancaba, `unlock` lo marcaba abierto igual y cada petición contestaba «profile is
91
+ // not open», con la TUI vacía y sin un error a la vista.
92
+ //
93
+ // Se dice y se sigue. Sin red se puede vivir hasta que alguien teclee la frase; sin
94
+ // bóveda, no.
95
+ try {
96
+ const publickey = await masterPubkeyOf(identity)
97
+ if (!publickey) return
98
+ const data = { op: 'identify', publickey, token: client.token, ts: Date.now() }
99
+ const { signature } = await identity.signData(data)
100
+ log('[vault] identifying with the master key: this vault is not in its own record yet (open the profile once to fix it)')
101
+ await client.identify({ data, signature, acta: record })
102
+ } catch (e) {
103
+ log(`[vault] cannot identify on the proxy yet: ${e.message} — the profile still opens; unlock it once and it gets its own communication key`)
104
+ }
91
105
  }
92
106
  await identify()
93
107
  // Re-identificar al reconectar (el token cambia).