@dotrino/vaultd 0.7.2 → 0.7.4
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/README.md +31 -3
- package/package.json +1 -1
- package/src/ctl.js +27 -5
- package/src/daemon.js +8 -2
- package/src/tui/app.js +292 -139
- package/src/tui/i18n.js +376 -0
- package/src/vaultControl.js +19 -9
package/README.md
CHANGED
|
@@ -103,9 +103,12 @@ los dispositivos/variables que estás viendo:
|
|
|
103
103
|
**entrar** a uno — lo activa si no lo estaba). Ahí también creas una bóveda
|
|
104
104
|
nueva, renombras, borras y pones/quitas/usas la contraseña (candado).
|
|
105
105
|
2. Al entrar caes en sus **pestañas horizontales**, que cambias con `←→`:
|
|
106
|
-
- **Dispositivos (pares):** verlos, **emparejar** uno nuevo
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
- **Dispositivos (pares):** verlos, **emparejar** uno nuevo, **aprobar** con el
|
|
107
|
+
código que muestra el dispositivo, **rechazar** y **revocar**. Al emparejar, la
|
|
108
|
+
bóveda **pregunta primero a qué cuenta entra el dispositivo** —a esta, o a una
|
|
109
|
+
cuenta nueva que se estrena para él— y recién después muestra el QR, que además
|
|
110
|
+
dice de qué cuenta salió. (En la CLI: `dotrino-vault pair --new-account
|
|
111
|
+
[nombre]`.)
|
|
109
112
|
- **Scopes y variables (secretos):** ver los scopes y sus variables (nunca los
|
|
110
113
|
valores), **agregar** una variable (con su scope) y **quitar** una variable o
|
|
111
114
|
un scope entero.
|
|
@@ -114,6 +117,31 @@ los dispositivos/variables que estás viendo:
|
|
|
114
117
|
sale desde cualquier pantalla. Las teclas de cada acción se listan en la barra
|
|
115
118
|
inferior.
|
|
116
119
|
|
|
120
|
+
**Idioma (`l`).** La TUI está en **español e inglés** y la tecla `l` conmuta entre
|
|
121
|
+
los dos en cualquier pantalla (incluida la de "el daemon no está corriendo"). El
|
|
122
|
+
idioma elegido se recuerda en `prefs.json` del dir de datos. Sin elección previa
|
|
123
|
+
se toma del entorno (`DOTRINO_LANG`, o el locale `LC_ALL`/`LANG`), con el español
|
|
124
|
+
por defecto.
|
|
125
|
+
|
|
126
|
+
**Las teclas NO cambian con el idioma**: son mnemónicos en **inglés** y valen igual
|
|
127
|
+
en español (solo se traduce la palabra que las explica en la barra de ayuda).
|
|
128
|
+
|
|
129
|
+
| Tecla | Acción | Dónde |
|
|
130
|
+
|---|---|---|
|
|
131
|
+
| `Enter` | open — entrar a la bóveda | Bóvedas |
|
|
132
|
+
| `n` | new — bóveda nueva / variable nueva | Bóvedas · Scopes |
|
|
133
|
+
| `r` | rename (Bóvedas) · refresh (Dispositivos/Scopes) · restart (Emparejar) | — |
|
|
134
|
+
| `d` | delete — borrar la bóveda | Bóvedas |
|
|
135
|
+
| `p` | password (Bóvedas) · pair — emparejar (Dispositivos) | — |
|
|
136
|
+
| `x` | quitar: contraseña · dispositivo pendiente · variable/scope | todas |
|
|
137
|
+
| `u` / `k` | unlock / locK — candado de la bóveda | Bóvedas |
|
|
138
|
+
| `a` | approve — aprobar el dispositivo | Dispositivos · Emparejar |
|
|
139
|
+
| `v` | reVoke — revocar un dispositivo enrolado | Dispositivos |
|
|
140
|
+
| `y` | yes — confirmar (también se acepta `s`) | confirmaciones |
|
|
141
|
+
| `b` / `Esc` | back — volver | pestañas · Emparejar |
|
|
142
|
+
| `l` | language — español ⇄ English | todas |
|
|
143
|
+
| `q` | quit — salir | todas |
|
|
144
|
+
|
|
117
145
|
### Varios perfiles en el mismo PC
|
|
118
146
|
|
|
119
147
|
Puedes tener varias identidades tuyas en la misma máquina (p. ej. personal y
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dotrino/vaultd",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.4",
|
|
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/ctl.js
CHANGED
|
@@ -136,7 +136,7 @@ function showChallenge (pe) {
|
|
|
136
136
|
console.log(' dispositivo : %s%s%s', B, pe.deviceId, Z)
|
|
137
137
|
console.log('\n Ingresa el código que MUESTRA el dispositivo (el vault no lo conoce):')
|
|
138
138
|
console.log(' %sdotrino-vault approve <código>%s', B, Z)
|
|
139
|
-
console.log(' Si no
|
|
139
|
+
console.log(' Si no reconoces este dispositivo: dotrino-vault reject %s\n', pe.deviceId)
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
async function cmdPair (args = []) {
|
|
@@ -144,7 +144,7 @@ async function cmdPair (args = []) {
|
|
|
144
144
|
try { fs.rmSync(pairFile, { force: true }) } catch (_) {}
|
|
145
145
|
try { fs.rmSync(pendingFile, { force: true }) } catch (_) {}
|
|
146
146
|
// --service <ns>: emparejar un SERVICIO (proxy, geo…) con cert limitado a
|
|
147
|
-
// vault:secrets:<ns> (no puede firmar como
|
|
147
|
+
// vault:secrets:<ns> (no puede firmar como tú ni leer tus datos).
|
|
148
148
|
const svcIdx = args.indexOf('--service')
|
|
149
149
|
let service = null
|
|
150
150
|
if (svcIdx >= 0) {
|
|
@@ -153,6 +153,20 @@ async function cmdPair (args = []) {
|
|
|
153
153
|
console.error('uso: dotrino-vault pair --service <ns> (ns en minúsculas, p.ej. proxy)'); process.exit(2)
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
|
+
// `--new-account [nombre]`: la otra respuesta a «¿a qué cuenta entra?». En vez de
|
|
157
|
+
// meter el dispositivo en una cuenta que ya vive aquí, se ESTRENA una (vacía) y
|
|
158
|
+
// entra a ella; las demás no se tocan. En la TUI esto es una pregunta con sus
|
|
159
|
+
// opciones; en la CLI es una bandera, para que siga sirviendo en un script.
|
|
160
|
+
const naIdx = args.findIndex((a) => a === '--new-account')
|
|
161
|
+
if (naIdx >= 0) {
|
|
162
|
+
const next = args[naIdx + 1]
|
|
163
|
+
const name = (next && !next.startsWith('-')) ? next : `cuenta ${new Date().toISOString().slice(0, 10)}`
|
|
164
|
+
const d = await profileRequest('add', { name })
|
|
165
|
+
if (d.error) { console.error('%s', d.error); process.exit(1) }
|
|
166
|
+
if (!d.id) { console.error('El daemon no dijo qué cuenta creó.'); process.exit(1) }
|
|
167
|
+
PROFILE = d.id // el emparejamiento y los comandos siguientes apuntan a ELLA
|
|
168
|
+
console.log('Cuenta nueva: %s (%s)', name, d.id)
|
|
169
|
+
}
|
|
156
170
|
// La petición se escribe SIEMPRE (aunque no haya --service): lleva a qué perfil
|
|
157
171
|
// se empareja el dispositivo.
|
|
158
172
|
writeReq('pair-request.json', service ? { service } : {})
|
|
@@ -166,11 +180,16 @@ async function cmdPair (args = []) {
|
|
|
166
180
|
const b64 = Buffer.from(payload, 'utf8').toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')
|
|
167
181
|
const url = PROFILE_URL + b64
|
|
168
182
|
const mins = Math.round((pair.expiresAt - Date.now()) / 60000)
|
|
169
|
-
|
|
183
|
+
// QUÉ CUENTA se comparte: el vault puede tener varias bóvedas y este QR sale de
|
|
184
|
+
// UNA (la activa, o la de --profile). Decirlo evita enrolar el dispositivo en la
|
|
185
|
+
// equivocada; es la misma línea que muestra la TUI.
|
|
186
|
+
const acct = pair.profileName || pair.profile
|
|
187
|
+
if (acct) console.log('\nCuenta que se comparte: %s%s', acct, pair.profileName && pair.profile ? ` (${pair.profile})` : '')
|
|
188
|
+
console.log('\nEscanea este QR con el dispositivo que quieres conectar (válido %d min):\n', mins)
|
|
170
189
|
console.log(qrToString(url)) // el QR abre vault.dotrino.com/dispositivos y empareja solo
|
|
171
190
|
console.log(`${R}${B}⚠ Este código deja LEER tus datos y FIRMAR con tu identidad.${Z}`)
|
|
172
|
-
console.log(`${R} NO lo compartas con nadie, ni con "soporte". Solo
|
|
173
|
-
console.log('\nO
|
|
191
|
+
console.log(`${R} NO lo compartas con nadie, ni con "soporte". Solo escanéalo en TU dispositivo.${Z}`)
|
|
192
|
+
console.log('\nO abre esta dirección en el dispositivo:\n ' + url)
|
|
174
193
|
console.log('\nO pega este código en vault.dotrino.com/dispositivos :\n ' + payload)
|
|
175
194
|
|
|
176
195
|
// --save [archivo]: escribe la invitación (.dpair) para transferirla y abrirla en profile.
|
|
@@ -534,6 +553,9 @@ function help () {
|
|
|
534
553
|
tui interfaz de terminal a pantalla completa (bóvedas, pares, secretos)
|
|
535
554
|
status estado del servicio + fingerprint
|
|
536
555
|
pair [--save <f>] inicia un emparejamiento (QR + espera); --save escribe la invitación (.dpair)
|
|
556
|
+
pair --new-account [nombre]
|
|
557
|
+
estrena una cuenta VACÍA en este vault y mete ahí al dispositivo
|
|
558
|
+
(sin la bandera entra a la cuenta activa, o a la de --profile)
|
|
537
559
|
pair --service <ns> empareja un SERVICIO (proxy, geo…) con acceso SOLO a sus secretos
|
|
538
560
|
secret set <ns> <CLAVE> <valor> guarda un secreto para el servicio <ns>
|
|
539
561
|
secret rm <ns> <CLAVE> borra un secreto
|
package/src/daemon.js
CHANGED
|
@@ -118,7 +118,11 @@ export async function runDaemon () {
|
|
|
118
118
|
const scope = isService ? ['vault:secrets:' + pairReq.service] : ['vault:sign', 'vault:read', 'vault:store']
|
|
119
119
|
const label = pairReq?.label || (isService ? 'servicio:' + pairReq.service : 'cli')
|
|
120
120
|
const { qr, expiresInMs } = vault.startPairing({ scope, label, ttlMs: DEVICE_TTL_MS })
|
|
121
|
-
|
|
121
|
+
// `profile`/`profileName`: la CUENTA del vault a la que entra el dispositivo.
|
|
122
|
+
// Con varias bóvedas en el mismo daemon, el QR sale de UNA y quien empareja
|
|
123
|
+
// tiene que verlo (lo muestran la TUI y `dotrino-vault pair`).
|
|
124
|
+
const profileName = mgr.profiles.get(profileId)?.name || ''
|
|
125
|
+
writeJson(pairFile, { v: 2, qr, expiresAt: Date.now() + expiresInMs, profile: profileId, profileName })
|
|
122
126
|
// El token es un secreto efímero: no debe quedar en disco más allá de su
|
|
123
127
|
// vida. Se borra al VENCER (aquí) y al APROBARSE (abajo, consumido).
|
|
124
128
|
const tok = qr.token
|
|
@@ -152,7 +156,9 @@ export async function runDaemon () {
|
|
|
152
156
|
const ref = () => mgr.resolve(req.profile || mgr.currentId())
|
|
153
157
|
switch (req.op) {
|
|
154
158
|
case 'list': return {} // el volcado de perfiles ya se hace abajo
|
|
155
|
-
|
|
159
|
+
// `id`: quien la crea necesita saber CUÁL quedó, no adivinar por nombre (dos
|
|
160
|
+
// cuentas pueden llamarse igual). Lo usa «emparejar en una cuenta nueva».
|
|
161
|
+
case 'add': { const p = await mgr.add(req.name); return { done: `perfil creado: ${p.name || p.id}`, id: p.id } }
|
|
156
162
|
case 'rm': { const r = await mgr.remove(req.profile); return { done: `perfil borrado: ${r.name || r.id}` } }
|
|
157
163
|
case 'rename': { const p = mgr.profiles.rename(ref(), req.name); return { done: `perfil renombrado: ${p.name}` } }
|
|
158
164
|
case 'use': { const p = mgr.profiles.setCurrent(ref()); return { done: `perfil activo: ${p.name || p.id}` } }
|