@dotrino/vaultd 0.26.2 → 0.46.2
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 +145 -25
- package/bin/dotrino-vaultd.js +4 -4
- package/lib/README.md +13 -2
- package/lib/src/admin.js +92 -3
- package/lib/src/atrest.js +0 -0
- package/lib/src/config.js +1 -1
- package/lib/src/enroll.js +38 -25
- package/lib/src/env.js +37 -17
- package/lib/src/envtext.js +94 -0
- package/lib/src/index.js +4 -4
- package/lib/src/invite.js +8 -8
- package/lib/src/protocol.js +22 -0
- package/lib/src/service.js +497 -135
- package/package.json +11 -6
- package/src/ctl.js +639 -98
- package/src/daemon.js +321 -52
- package/src/manager.js +12 -6
- package/src/profiles.js +109 -13
- package/src/sealKey.js +80 -0
- package/src/sealer.js +170 -0
- package/src/secretsStore.js +881 -29
- package/src/store.js +3 -1
- package/src/transport.js +2 -2
- package/src/tui/app.js +625 -129
- package/src/tui/i18n.js +145 -24
- package/src/vault.js +972 -48
- package/src/vaultControl.js +286 -61
package/src/tui/i18n.js
CHANGED
|
@@ -37,7 +37,7 @@ const es = {
|
|
|
37
37
|
tabMe: 'Perfil',
|
|
38
38
|
// PERMISOS de un dispositivo (§9.1: se dice el beneficio, no el scope del cert).
|
|
39
39
|
titleCaps: 'Permisos del dispositivo',
|
|
40
|
-
capsFor: (id,
|
|
40
|
+
capsFor: (id, name) => `Permisos de ${id}${name ? ' · ' + name : ''}`,
|
|
41
41
|
capsNoMember: ' (este dispositivo ya no está en el acta)',
|
|
42
42
|
capsApplyHint: 'Enter marca o desmarca. Cada cambio se aplica y se avisa a tus otros aparatos.',
|
|
43
43
|
capName: {
|
|
@@ -63,7 +63,7 @@ const es = {
|
|
|
63
63
|
loadingProfile: 'Cargando el perfil…',
|
|
64
64
|
noProfile: ' (esta bóveda todavía no tiene perfil)',
|
|
65
65
|
noProfileHint: ' Edita tu nombre o tu foto en un dispositivo emparejado y pulsa F5.',
|
|
66
|
-
profileUpdated: (
|
|
66
|
+
profileUpdated: (when) => ` actualizado ${when}`,
|
|
67
67
|
fieldName: 'nombre',
|
|
68
68
|
fieldPhoto: 'foto',
|
|
69
69
|
fieldFirstName: 'nombres',
|
|
@@ -74,7 +74,6 @@ const es = {
|
|
|
74
74
|
links: 'Enlaces',
|
|
75
75
|
otherData: 'Otros datos',
|
|
76
76
|
hidden: ' (oculto)',
|
|
77
|
-
noName: '(sin nombre)',
|
|
78
77
|
no: 'no',
|
|
79
78
|
helpMe: ['←→ pestaña', 'F5 refrescar', 'Esc bóvedas', 'l English', 'q salir'],
|
|
80
79
|
tabsHint: ' (←→ cambiar)',
|
|
@@ -84,10 +83,12 @@ const es = {
|
|
|
84
83
|
|
|
85
84
|
// bóvedas (perfiles)
|
|
86
85
|
noPassword: 'sin clave',
|
|
86
|
+
noPasswordWarn: 'Este perfil no tiene contraseña: una copia de este disco abre las variables privadas.',
|
|
87
|
+
pendingSeal: (owner, kind, who) => kind === 'rotate' ? `${owner}: sin rotar (salió un aparato). Guarda una variable con la contraseña.` : `${owner}: sin llave todavía en ${who}. Se reparte sola con otro aparato del grupo encendido, o al abrir la bóveda.`,
|
|
87
88
|
locked: '🔒 bloqueada',
|
|
88
89
|
unlocked: '🔓 abierta',
|
|
89
90
|
passwordOf: (name) => `Contraseña de "${name}"`,
|
|
90
|
-
passwordToEdit: 'necesaria para
|
|
91
|
+
passwordToEdit: 'necesaria para abrir la bóveda: sin ella no se ve ni se toca',
|
|
91
92
|
unlocking: 'Desbloqueando…',
|
|
92
93
|
loading: 'Cargando…',
|
|
93
94
|
loadingDevices: 'Cargando dispositivos…',
|
|
@@ -110,7 +111,7 @@ const es = {
|
|
|
110
111
|
deletingVault: 'Borrando bóveda…',
|
|
111
112
|
vaultDeleted: 'Bóveda borrada',
|
|
112
113
|
newPasswordLabel: (name) => `Contraseña nueva para "${name}" (mín. 4)`,
|
|
113
|
-
passwordTooShort: 'La contraseña debe tener al menos
|
|
114
|
+
passwordTooShort: 'La contraseña debe tener al menos 12 caracteres: usa varias palabras al azar',
|
|
114
115
|
repeatPassword: 'Repite la contraseña',
|
|
115
116
|
passwordMismatch: 'Las contraseñas no coinciden',
|
|
116
117
|
savingPassword: 'Guardando contraseña…',
|
|
@@ -130,6 +131,7 @@ const es = {
|
|
|
130
131
|
noLabel: '(sin etiqueta)',
|
|
131
132
|
// Está en el acta y no puede entrar: o le retiraron el certificado, o se le venció.
|
|
132
133
|
deviceNoAccess: 'SIN ACCESO — está en el acta pero no puede entrar',
|
|
134
|
+
deviceDebt: (n) => `no abre ${n}`,
|
|
133
135
|
thisVault: 'esta bóveda (manda ella)',
|
|
134
136
|
cantRemoveMaster: 'Esta bóveda es la que manda: no se quita a sí misma.',
|
|
135
137
|
revokedCount: (n) => ` Revocados: ${n}`,
|
|
@@ -170,17 +172,58 @@ const es = {
|
|
|
170
172
|
savingVar: 'Guardando variable…',
|
|
171
173
|
varSaved: (ns, key) => `Guardado ${ns}/${key}`,
|
|
172
174
|
|
|
175
|
+
// CARGAR VARIAS DE UNA VEZ (tecla c). Una a una, cada variable es un cambio de
|
|
176
|
+
// configuración y el servicio se reinicia a media carga; juntas, se reinicia una vez.
|
|
177
|
+
loadLabel: (ns) => `Cargar varias en "${ns}"`,
|
|
178
|
+
loadHint: 'CLAVE=valor CLAVE2=valor2 · o la ruta de un archivo .env',
|
|
179
|
+
loadNoFile: (f) => `No se pudo leer ${f}`,
|
|
180
|
+
loadingVars: 'Cargando variables…',
|
|
181
|
+
loadedVars: (n, ns) => `${n} variables cargadas en ${ns} · un solo aviso de cambio`,
|
|
182
|
+
envErr: {
|
|
183
|
+
shape: (e) => `línea ${e.line}: no tiene la forma CLAVE=valor`,
|
|
184
|
+
key: (e) => `línea ${e.line}: «${e.key}» va en MAYUSCULAS_CON_GUION_BAJO`,
|
|
185
|
+
novalue: (e) => `línea ${e.line}: ${e.key} no tiene valor`,
|
|
186
|
+
dup: (e) => `línea ${e.line}: ${e.key} ya venía en la línea ${e.first}`,
|
|
187
|
+
empty: () => 'No hay ninguna variable que cargar'
|
|
188
|
+
},
|
|
189
|
+
loadNothing: 'No se cargó nada:',
|
|
190
|
+
varPublic: 'pública',
|
|
191
|
+
newVarPublicAsk: '¿Que su valor se pueda VER desde la consola remota? (las demás no salen de esta máquina)',
|
|
192
|
+
makePublicConfirm: '¿Dejar que su valor se vea desde la consola remota?',
|
|
193
|
+
changingVisibility: 'Cambiando visibilidad…',
|
|
194
|
+
nowPublic: 'Ahora su valor se puede ver desde la consola remota',
|
|
195
|
+
nowPrivate: 'Ahora su valor no sale de esta máquina',
|
|
196
|
+
|
|
197
|
+
// variables de UN aparato (Dispositivos → tecla e). Las del scope las comparten todos
|
|
198
|
+
// los aparatos que sirven ese namespace; estas las lee solo él, y le ganan.
|
|
199
|
+
titleDevVars: 'Variables del dispositivo',
|
|
200
|
+
devVarsFor: (id, name) => `Variables de ${id}${name ? ' · ' + name : ''}`,
|
|
201
|
+
devVarsService: (cn) => `servicio «${cn}» — solo las lee este aparato, y pisan a las del scope`,
|
|
202
|
+
noDevVars: '(sin variables propias — pulsa N para agregar la primera)',
|
|
203
|
+
devVarsOnlyServices: 'Solo un servicio lee variables, y este aparato no lo es',
|
|
204
|
+
devVarsElsewhere: 'Las variables de UN aparato se ponen en Dispositivos (tecla e).',
|
|
205
|
+
removeDevVarConfirm: (id, key) => `¿Quitar la variable ${key} de ${id}?`,
|
|
206
|
+
|
|
173
207
|
// emparejamiento — la PREGUNTA es del vault, que es quien lo inicia
|
|
174
208
|
pairModeIntro: 'Un dispositivo puede entrar a una cuenta que ya vive aquí, o estrenar una.',
|
|
175
209
|
pairModeHere: (name) => `Entrar a esta cuenta: ${name}`,
|
|
176
210
|
pairModeHereHint: 'el dispositivo pasa a ver y firmar lo de esta cuenta',
|
|
177
211
|
pairModeNew: 'Estrenar una cuenta nueva en este vault',
|
|
178
212
|
pairModeNewHint: 'se crea aquí, vacía, y el dispositivo entra a ELLA (las otras no se tocan)',
|
|
213
|
+
pairModeService: 'Conectar un servicio (proxy, geo…)',
|
|
214
|
+
pairModeServiceHint: 'entra a esta cuenta pero solo lee SUS variables: no firma ni ve tu contenido',
|
|
179
215
|
pairModeAdopt: 'Adoptar la cuenta que trae el dispositivo',
|
|
180
216
|
pairModeAdoptSoon: 'todavía no: el dispositivo aún no sabe entregar la suya',
|
|
217
|
+
serviceNsLabel: '¿Qué servicio es? (proxy, geo, results…)',
|
|
218
|
+
serviceNsHint: 'minúsculas, sin espacios; es el nombre con el que ese programa pide su configuración',
|
|
219
|
+
serviceNsBad: 'Nombre no válido: minúsculas, números y guiones (hasta 32)',
|
|
220
|
+
pairService: (ns) => `Este QR entrega un SERVICIO «${ns}»: solo podrá leer las variables de ${ns}.`,
|
|
181
221
|
newAccountLabel: 'Nombre de la cuenta nueva',
|
|
182
222
|
newAccountHint: 'nace vacía; el dispositivo será su primer invitado',
|
|
183
223
|
accountCreated: (name) => `Cuenta creada: ${name}`,
|
|
224
|
+
discardingAccount: 'Descartando la cuenta…',
|
|
225
|
+
accountDiscarded: 'Cuenta descartada: nadie llegó a entrar en ella',
|
|
226
|
+
confirmDiscardAccount: 'La cuenta se creó para este emparejamiento y quedó vacía. ¿La descarto?',
|
|
184
227
|
// Cuenta + vigencia en UNA línea: cada línea de cabecera es una fila menos de QR
|
|
185
228
|
// visible antes de tener que hacer scroll.
|
|
186
229
|
pairAccount: (name, min) => `Cuenta que se comparte: ${name} · válido ~${min} min`,
|
|
@@ -205,21 +248,36 @@ const es = {
|
|
|
205
248
|
// La barra dice lo que se PUEDE hacer AHORA, no todo lo que existe: aprobar/rechazar solo
|
|
206
249
|
// valen si hay alguien esperando, y renombrar/revocar solo si hay un aparato seleccionado.
|
|
207
250
|
// Anunciar teclas muertas confunde y además las quema para otros usos.
|
|
208
|
-
|
|
251
|
+
// `e variables` solo en un SERVICIO: es el único que las lee, así que en un teléfono
|
|
252
|
+
// era una tecla que solo sabía decir que no.
|
|
253
|
+
helpDevices: ({ pending, hasDevices, isService } = {}) => [
|
|
209
254
|
'←→ pestaña', '↑↓', 'p emparejar',
|
|
210
|
-
...(
|
|
211
|
-
...(
|
|
255
|
+
...(pending ? ['a aprobar', 'x rechazar'] : []),
|
|
256
|
+
...(hasDevices ? ['r renombrar', 'c permisos'] : []),
|
|
257
|
+
...(isService ? ['e variables'] : []),
|
|
258
|
+
...(hasDevices ? ['v revocar'] : []),
|
|
212
259
|
'F5 refrescar', 'Esc bóvedas', 'l English', 'q salir'
|
|
213
260
|
],
|
|
214
261
|
renameDeviceLabel: (id) => `¿Cómo quieres llamar a ${id}?`,
|
|
215
262
|
renameDeviceHint: 'el nombre con el que lo reconoces (Esc cancela)',
|
|
216
|
-
renaming: 'Renombrando…',
|
|
217
263
|
deviceRenamed: (n) => `Ahora se llama «${n}»`,
|
|
218
|
-
helpSecrets: ({
|
|
219
|
-
'←→ pestaña', '↑↓', 'n nueva variable',
|
|
220
|
-
...(
|
|
264
|
+
helpSecrets: ({ hasSecrets } = {}) => [
|
|
265
|
+
'←→ pestaña', '↑↓', 'n nueva variable', 'i cargar varias',
|
|
266
|
+
...(hasSecrets ? ['v ver valor', 't pública/privada', 'x quitar (variable/scope)'] : []),
|
|
221
267
|
'F5 refrescar', 'Esc bóvedas', 'l English', 'q salir'
|
|
222
268
|
],
|
|
269
|
+
helpDevVars: ({ hasVars } = {}) => [
|
|
270
|
+
'↑↓', 'n nueva variable', 'i cargar varias',
|
|
271
|
+
...(hasVars ? ['v ver valor', 't pública/privada', 'x quitar'] : []),
|
|
272
|
+
'F5 refrescar', 'Esc dispositivos', 'l English', 'q salir'
|
|
273
|
+
],
|
|
274
|
+
// Ver el valor de una privada: lo único que la contraseña guarda en esta máquina.
|
|
275
|
+
revealTitle: 'Ver el valor',
|
|
276
|
+
revealAsk: 'Contraseña del perfil (para ver el valor)',
|
|
277
|
+
revealHint: 'sin ella no se puede abrir: es lo único que la guarda (Esc cancela)',
|
|
278
|
+
revealing: 'abriendo…',
|
|
279
|
+
revealed: (k, v) => `${k} = ${v}`,
|
|
280
|
+
revealNoPwd: 'Este perfil no tiene contraseña: se abre con la llave de esta máquina.',
|
|
223
281
|
helpPairing: ['a aprobar', 'x rechazar', 'r reiniciar', '↑↓ scroll', 'Esc atrás', 'l English'],
|
|
224
282
|
helpPairMode: ['↑↓', 'Enter elegir', 'Esc atrás', 'l English', 'q salir'],
|
|
225
283
|
|
|
@@ -246,6 +304,13 @@ const es = {
|
|
|
246
304
|
errNotApplied: 'El daemon no aplicó el cambio (revisa los logs del servicio).',
|
|
247
305
|
errNotDeleted: 'El daemon no borró la variable (revisa los logs del servicio).',
|
|
248
306
|
errPairFailed: 'El daemon no inició el emparejamiento.',
|
|
307
|
+
// El código NO es la contraseña de la bóveda: son los seis dígitos que el aparato
|
|
308
|
+
// enseña en su pantalla. Si no coincide, la bóveda no firma nada y el aparato sigue
|
|
309
|
+
// esperando ahí, así que se puede volver a intentar con A.
|
|
310
|
+
errWrongCode: 'El código no coincide con el que muestra el dispositivo: no se emitió ningún certificado. Míralo otra vez y pulsa A.',
|
|
311
|
+
errProfileLocked: 'Bóveda bloqueada: ábrela con su contraseña',
|
|
312
|
+
errWrongPassword: (n) => `Contraseña incorrecta${n ? ` — van ${n} intentos fallidos` : ''}`,
|
|
313
|
+
errTooManyTries: (s) => `Demasiados intentos: espera ${s || '?'} s antes de volver a probar`,
|
|
249
314
|
errMasterWithMembers: 'Esta bóveda es el Master de esta cuenta y hay otros dispositivos: pásale primero el Master a uno que esté conectado. Si la borras así, se quedan con su llave y sin nadie que pueda volver a firmar el acta.'
|
|
250
315
|
}
|
|
251
316
|
|
|
@@ -260,7 +325,6 @@ const en = {
|
|
|
260
325
|
daemonRunning: 'running',
|
|
261
326
|
daemonStopped: 'STOPPED',
|
|
262
327
|
activeVault: 'Active vault: ',
|
|
263
|
-
noName: '(unnamed)',
|
|
264
328
|
tooSmall: 'Terminal too small',
|
|
265
329
|
tooSmallHint: (cols, rows) => `Resize to ≥ 24×9 (now ${cols}×${rows}).`,
|
|
266
330
|
|
|
@@ -268,7 +332,7 @@ const en = {
|
|
|
268
332
|
tabSecrets: 'Scopes & variables',
|
|
269
333
|
tabMe: 'Profile',
|
|
270
334
|
titleCaps: 'Device permissions',
|
|
271
|
-
capsFor: (id,
|
|
335
|
+
capsFor: (id, name) => `Permissions for ${id}${name ? ' · ' + name : ''}`,
|
|
272
336
|
capsNoMember: ' (this device is no longer in the record)',
|
|
273
337
|
capsApplyHint: 'Enter ticks or unticks. Each change applies and your other devices are told.',
|
|
274
338
|
capName: {
|
|
@@ -292,7 +356,7 @@ const en = {
|
|
|
292
356
|
loadingProfile: 'Loading profile…',
|
|
293
357
|
noProfile: ' (this vault has no profile yet)',
|
|
294
358
|
noProfileHint: ' Edit your name or photo on a paired device and press F5.',
|
|
295
|
-
profileUpdated: (
|
|
359
|
+
profileUpdated: (when) => ` updated ${when}`,
|
|
296
360
|
fieldName: 'name',
|
|
297
361
|
fieldPhoto: 'photo',
|
|
298
362
|
fieldFirstName: 'first name',
|
|
@@ -312,10 +376,12 @@ const en = {
|
|
|
312
376
|
titlePairMode: 'Pairing: which account does it join?',
|
|
313
377
|
|
|
314
378
|
noPassword: 'no password',
|
|
379
|
+
noPasswordWarn: 'This profile has no password: a copy of this disk opens the private variables.',
|
|
380
|
+
pendingSeal: (owner, kind, who) => kind === 'rotate' ? `${owner}: not rotated (a device left). Save a variable with the password.` : `${owner}: no key yet on ${who}. It is handed out by another device of the group that is on, or when the vault is opened.`,
|
|
315
381
|
locked: '🔒 locked',
|
|
316
382
|
unlocked: '🔓 unlocked',
|
|
317
383
|
passwordOf: (name) => `Password for "${name}"`,
|
|
318
|
-
passwordToEdit: 'needed to
|
|
384
|
+
passwordToEdit: 'needed to open this vault: without it, nothing is shown or touched',
|
|
319
385
|
unlocking: 'Unlocking…',
|
|
320
386
|
loading: 'Loading…',
|
|
321
387
|
loadingDevices: 'Loading devices…',
|
|
@@ -338,7 +404,7 @@ const en = {
|
|
|
338
404
|
deletingVault: 'Deleting vault…',
|
|
339
405
|
vaultDeleted: 'Vault deleted',
|
|
340
406
|
newPasswordLabel: (name) => `New password for "${name}" (min. 4)`,
|
|
341
|
-
passwordTooShort: 'The password must be at least
|
|
407
|
+
passwordTooShort: 'The password must be at least 12 characters: use several random words',
|
|
342
408
|
repeatPassword: 'Repeat the password',
|
|
343
409
|
passwordMismatch: 'The passwords do not match',
|
|
344
410
|
savingPassword: 'Saving password…',
|
|
@@ -356,6 +422,7 @@ const en = {
|
|
|
356
422
|
noDevices: ' (no devices enrolled — press P to pair one)',
|
|
357
423
|
noLabel: '(no label)',
|
|
358
424
|
deviceNoAccess: 'NO ACCESS — it is on the record but cannot get in',
|
|
425
|
+
deviceDebt: (n) => `cannot open ${n}`,
|
|
359
426
|
thisVault: 'this vault (it is the Master)',
|
|
360
427
|
cantRemoveMaster: 'This vault is the Master: it does not remove itself.',
|
|
361
428
|
revokedCount: (n) => ` Revoked: ${n}`,
|
|
@@ -395,16 +462,54 @@ const en = {
|
|
|
395
462
|
savingVar: 'Saving variable…',
|
|
396
463
|
varSaved: (ns, key) => `Saved ${ns}/${key}`,
|
|
397
464
|
|
|
465
|
+
loadLabel: (ns) => `Load several into "${ns}"`,
|
|
466
|
+
loadHint: 'KEY=value KEY2=value2 · or the path to a .env file',
|
|
467
|
+
loadNoFile: (f) => `Could not read ${f}`,
|
|
468
|
+
loadingVars: 'Loading variables…',
|
|
469
|
+
loadedVars: (n, ns) => `${n} variables loaded into ${ns} · a single change notice`,
|
|
470
|
+
envErr: {
|
|
471
|
+
shape: (e) => `line ${e.line}: not in the form KEY=value`,
|
|
472
|
+
key: (e) => `line ${e.line}: "${e.key}" must be UPPERCASE_WITH_UNDERSCORES`,
|
|
473
|
+
novalue: (e) => `line ${e.line}: ${e.key} has no value`,
|
|
474
|
+
dup: (e) => `line ${e.line}: ${e.key} already came on line ${e.first}`,
|
|
475
|
+
empty: () => 'There is no variable to load'
|
|
476
|
+
},
|
|
477
|
+
loadNothing: 'Nothing was loaded:',
|
|
478
|
+
varPublic: 'public',
|
|
479
|
+
newVarPublicAsk: 'Let its value be SEEN from the remote console? (the rest never leave this machine)',
|
|
480
|
+
makePublicConfirm: 'Let its value be seen from the remote console?',
|
|
481
|
+
changingVisibility: 'Changing visibility…',
|
|
482
|
+
nowPublic: 'Its value can now be seen from the remote console',
|
|
483
|
+
nowPrivate: 'Its value no longer leaves this machine',
|
|
484
|
+
|
|
485
|
+
// variables de UN aparato (Dispositivos → tecla e)
|
|
486
|
+
titleDevVars: 'Device variables',
|
|
487
|
+
devVarsFor: (id, name) => `Variables of ${id}${name ? ' · ' + name : ''}`,
|
|
488
|
+
devVarsService: (cn) => `“${cn}” service — only this device reads them, and they override the scope ones`,
|
|
489
|
+
noDevVars: '(no variables of its own — press N to add the first one)',
|
|
490
|
+
devVarsOnlyServices: 'Only a service reads variables, and this device is not one',
|
|
491
|
+
devVarsElsewhere: 'Variables for ONE device are set in Devices (key e).',
|
|
492
|
+
removeDevVarConfirm: (id, key) => `Remove variable ${key} from ${id}?`,
|
|
493
|
+
|
|
398
494
|
pairModeIntro: 'A device can join an account that already lives here, or start a new one.',
|
|
399
495
|
pairModeHere: (name) => `Join this account: ${name}`,
|
|
400
496
|
pairModeHereHint: 'the device gets to see and sign for this account',
|
|
401
497
|
pairModeNew: 'Start a new account in this vault',
|
|
402
498
|
pairModeNewHint: 'created here, empty, and the device joins THAT one (the others are untouched)',
|
|
499
|
+
pairModeService: 'Connect a service (proxy, geo…)',
|
|
500
|
+
pairModeServiceHint: 'joins this account but only reads ITS variables: it neither signs nor sees your content',
|
|
403
501
|
pairModeAdopt: 'Adopt the account the device brings',
|
|
404
502
|
pairModeAdoptSoon: 'not yet: the device cannot hand its own over',
|
|
503
|
+
serviceNsLabel: 'Which service is it? (proxy, geo, results…)',
|
|
504
|
+
serviceNsHint: 'lowercase, no spaces; it is the name that program uses to ask for its settings',
|
|
505
|
+
serviceNsBad: 'Invalid name: lowercase letters, digits and dashes (up to 32)',
|
|
506
|
+
pairService: (ns) => `This QR hands out a SERVICE “${ns}”: it will only read ${ns}’s variables.`,
|
|
405
507
|
newAccountLabel: 'Name of the new account',
|
|
406
508
|
newAccountHint: 'born empty; the device will be its first guest',
|
|
407
509
|
accountCreated: (name) => `Account created: ${name}`,
|
|
510
|
+
discardingAccount: 'Discarding the account…',
|
|
511
|
+
accountDiscarded: 'Account discarded: nobody got to join it',
|
|
512
|
+
confirmDiscardAccount: 'The account was created for this pairing and is empty. Discard it?',
|
|
408
513
|
pairAccount: (name, min) => `Account being shared: ${name} · valid ~${min} min`,
|
|
409
514
|
pairScan: 'Scan it, or open this address on the device:',
|
|
410
515
|
pairUrl: 'URL: ',
|
|
@@ -419,21 +524,33 @@ const en = {
|
|
|
419
524
|
helpConfirm: 'y confirm · n/Esc cancel',
|
|
420
525
|
|
|
421
526
|
helpProfiles: ['↑↓', 'Enter open', 'p pair', 'n new', 'r rename', 'd delete', 'c password', 'x drop-password', 'u unlock', 'k lock', 'l Español', 'q quit'],
|
|
422
|
-
helpDevices: ({
|
|
527
|
+
helpDevices: ({ pending, hasDevices, isService } = {}) => [
|
|
423
528
|
'←→ tab', '↑↓', 'p pair',
|
|
424
|
-
...(
|
|
425
|
-
...(
|
|
529
|
+
...(pending ? ['a approve', 'x reject'] : []),
|
|
530
|
+
...(hasDevices ? ['r rename', 'c permissions'] : []),
|
|
531
|
+
...(isService ? ['e variables'] : []),
|
|
532
|
+
...(hasDevices ? ['v revoke'] : []),
|
|
426
533
|
'F5 refresh', 'Esc vaults', 'l Español', 'q quit'
|
|
427
534
|
],
|
|
428
535
|
renameDeviceLabel: (id) => `What do you want to call ${id}?`,
|
|
429
536
|
renameDeviceHint: 'the name you recognise it by (Esc cancels)',
|
|
430
|
-
renaming: 'Renaming…',
|
|
431
537
|
deviceRenamed: (n) => `Now called "${n}"`,
|
|
432
|
-
helpSecrets: ({
|
|
433
|
-
'←→ tab', '↑↓', 'n new variable',
|
|
434
|
-
...(
|
|
538
|
+
helpSecrets: ({ hasSecrets } = {}) => [
|
|
539
|
+
'←→ tab', '↑↓', 'n new variable', 'i load several',
|
|
540
|
+
...(hasSecrets ? ['v show value', 't public/private', 'x remove (variable/scope)'] : []),
|
|
435
541
|
'F5 refresh', 'Esc vaults', 'l Español', 'q quit'
|
|
436
542
|
],
|
|
543
|
+
helpDevVars: ({ hasVars } = {}) => [
|
|
544
|
+
'↑↓', 'n new variable', 'i load several',
|
|
545
|
+
...(hasVars ? ['v show value', 't public/private', 'x remove'] : []),
|
|
546
|
+
'F5 refresh', 'Esc devices', 'l Español', 'q quit'
|
|
547
|
+
],
|
|
548
|
+
revealTitle: 'Show the value',
|
|
549
|
+
revealAsk: 'Profile password (to show the value)',
|
|
550
|
+
revealHint: 'without it there is no way to open it: it is the only thing guarding it (Esc cancels)',
|
|
551
|
+
revealing: 'opening…',
|
|
552
|
+
revealed: (k, v) => `${k} = ${v}`,
|
|
553
|
+
revealNoPwd: 'This profile has no password: it opens with this machine key.',
|
|
437
554
|
helpPairing: ['a approve', 'x reject', 'r restart', '↑↓ scroll', 'Esc back', 'l Español'],
|
|
438
555
|
helpPairMode: ['↑↓', 'Enter choose', 'Esc back', 'l Español', 'q quit'],
|
|
439
556
|
|
|
@@ -458,6 +575,10 @@ const en = {
|
|
|
458
575
|
errNotApplied: 'The daemon did not apply the change (check the service logs).',
|
|
459
576
|
errNotDeleted: 'The daemon did not delete the variable (check the service logs).',
|
|
460
577
|
errPairFailed: 'The daemon did not start the pairing.',
|
|
578
|
+
errWrongCode: 'The code does not match the one shown by the device: no certificate was issued. Check it and press A again.',
|
|
579
|
+
errProfileLocked: 'Vault locked: open it with its password',
|
|
580
|
+
errWrongPassword: (n) => `Wrong password${n ? ` — ${n} failed attempts so far` : ''}`,
|
|
581
|
+
errTooManyTries: (s) => `Too many attempts: wait ${s || '?'} s before trying again`,
|
|
461
582
|
errMasterWithMembers: 'This vault is the Master of this account and it has other devices: hand the Master over to one that is online first. If you delete it like this, they keep their key with nobody able to sign the record again.'
|
|
462
583
|
}
|
|
463
584
|
|