@dotrino/vault 0.51.0 → 0.52.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/src/atrest.js +47 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dotrino/vault",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.52.0",
|
|
4
4
|
"description": "Usa ESTE dispositivo (navegador) como bóveda/CA del ecosistema Dotrino: atiende enrolamientos por el proxy y firma certificados de delegación a tus máquinas. Incluye el cliente de SERVICIO (Node): un proyecto se enrola una vez y jala sus credenciales del vault en vez del .env (`import '@dotrino/vault/config'`).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
package/src/atrest.js
CHANGED
|
@@ -14,8 +14,14 @@
|
|
|
14
14
|
* · `secrets.json` secretos de servicios (tokens y llaves de producción)
|
|
15
15
|
* · `service-identity.json` en la máquina del SERVICIO (`@dotrino/vault/env`):
|
|
16
16
|
* lleva la llave privada de su dispositivo, así que va igual de cifrado.
|
|
17
|
-
*
|
|
18
|
-
*
|
|
17
|
+
* · `activity.log` la bitácora de auditoría, cifrada LÍNEA A LÍNEA (ver `LINE_FILES`)
|
|
18
|
+
* · `state.json`, `acta.json`, `secret-request.json`… el canal local con la CLI
|
|
19
|
+
* (`src/ipc.js`), por donde pasan la contraseña del perfil y los valores
|
|
20
|
+
* · `transport.json` el par de transporte de `@dotrino/proxy-client`, con su privada
|
|
21
|
+
*
|
|
22
|
+
* La bitácora estuvo fuera hasta 0.89, con el argumento de que «no guarda payloads». No
|
|
23
|
+
* guarda valores, pero sí el mapa de la cuenta —qué aparatos, con qué permisos, contra
|
|
24
|
+
* qué cajones y a qué hora—, que es lo que mira quien elige por dónde entrar.
|
|
19
25
|
*
|
|
20
26
|
* Qué NO resuelve, dicho sin adornos: **no protege contra alguien con acceso a esta misma
|
|
21
27
|
* máquina como tu usuario o como root** — puede leer el mismo material que leemos nosotros.
|
|
@@ -178,15 +184,31 @@ export function migrateFile (file, key) {
|
|
|
178
184
|
}
|
|
179
185
|
|
|
180
186
|
/** Los archivos de este directorio que están cifrados por nosotros. */
|
|
187
|
+
/**
|
|
188
|
+
* Archivos que van cifrados **línea a línea**, no de una pieza.
|
|
189
|
+
*
|
|
190
|
+
* La bitácora se ESCRIBE AÑADIENDO. Cifrarla entera obligaría a reescribir el archivo
|
|
191
|
+
* completo en cada anotación, así que cada entrada se cierra sola. Eso la deja fuera del
|
|
192
|
+
* barrido de abajo (una lectura de todo el archivo no descifra: son muchos textos pegados)
|
|
193
|
+
* y la mete en su propio camino al cambiar de proveedor.
|
|
194
|
+
*/
|
|
195
|
+
export const LINE_FILES = Object.freeze(['activity.log'])
|
|
196
|
+
|
|
181
197
|
export function encryptedFilesIn (dir) {
|
|
182
198
|
let names = []
|
|
183
199
|
try { names = fs.readdirSync(dir) } catch (_) { return [] }
|
|
184
200
|
return names.filter((n) => {
|
|
185
201
|
if (n === CONFIG_FILE || n === WRAPPED_FILE || n === SALT_FILE || n === MACHINE_FILE) return false
|
|
202
|
+
if (LINE_FILES.includes(n)) return false
|
|
186
203
|
try { return isEncrypted(fs.readFileSync(path.join(dir, n), 'utf8')) } catch (_) { return false }
|
|
187
204
|
})
|
|
188
205
|
}
|
|
189
206
|
|
|
207
|
+
/** Las bitácoras presentes en `dir`, con sus líneas. `[]` si no hay ninguna. */
|
|
208
|
+
export function lineFilesIn (dir) {
|
|
209
|
+
return LINE_FILES.filter((n) => { try { return fs.statSync(path.join(dir, n)).isFile() } catch (_) { return false } })
|
|
210
|
+
}
|
|
211
|
+
|
|
190
212
|
/**
|
|
191
213
|
* CAMBIAR DE PROVEEDOR: descifra todo con la clave vieja y lo vuelve a cifrar con la nueva.
|
|
192
214
|
*
|
|
@@ -219,6 +241,19 @@ export function rekeyDir (dir, newConfig, { password = '' } = {}) {
|
|
|
219
241
|
throw new KekError('kek-rekey', `cannot decrypt ${n} with the current provider (${oldCfg.provider}): ${e.message}`)
|
|
220
242
|
}
|
|
221
243
|
}
|
|
244
|
+
// Las bitácoras, por líneas. `decryptText` deja pasar el texto en claro, así que una
|
|
245
|
+
// mitad vieja sin cifrar cruza intacta y sale cifrada con la clave nueva.
|
|
246
|
+
const lineFiles = lineFilesIn(dir)
|
|
247
|
+
const plainLines = new Map()
|
|
248
|
+
for (const n of lineFiles) {
|
|
249
|
+
const p = path.join(dir, n)
|
|
250
|
+
try {
|
|
251
|
+
const lines = fs.readFileSync(p, 'utf8').split('\n')
|
|
252
|
+
plainLines.set(n, lines.map((l) => (l ? decryptText(l, oldKey) : l)))
|
|
253
|
+
} catch (e) {
|
|
254
|
+
throw new KekError('kek-rekey', `cannot decrypt ${n} with the current provider (${oldCfg.provider}): ${e.message}`)
|
|
255
|
+
}
|
|
256
|
+
}
|
|
222
257
|
|
|
223
258
|
// 2. La clave nueva, todavía sin escribir su envoltorio.
|
|
224
259
|
let newKey; let newBlob = null
|
|
@@ -236,6 +271,15 @@ export function rekeyDir (dir, newConfig, { password = '' } = {}) {
|
|
|
236
271
|
if (decryptText(blob, newKey) !== text) throw new KekError('kek-verify', `re-encryption check failed for ${n}: nothing was written`)
|
|
237
272
|
out.set(n, blob)
|
|
238
273
|
}
|
|
274
|
+
for (const [n, lines] of plainLines) {
|
|
275
|
+
const blobs = lines.map((l) => (l ? encryptText(l, newKey) : l))
|
|
276
|
+
for (let i = 0; i < lines.length; i++) {
|
|
277
|
+
if (lines[i] && decryptText(blobs[i], newKey) !== lines[i]) {
|
|
278
|
+
throw new KekError('kek-verify', `re-encryption check failed for ${n} (line ${i + 1}): nothing was written`)
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
out.set(n, blobs.join('\n'))
|
|
282
|
+
}
|
|
239
283
|
|
|
240
284
|
// 4. A disco. Copia de seguridad, temporal, renombrar.
|
|
241
285
|
const backups = []
|
|
@@ -266,6 +310,6 @@ export function rekeyDir (dir, newConfig, { password = '' } = {}) {
|
|
|
266
310
|
|
|
267
311
|
export default {
|
|
268
312
|
machineKey, kekFor, atRestFor, migrateFile, isEncrypted, encryptText, decryptText,
|
|
269
|
-
rekeyDir, encryptedFilesIn, readConfig, writeConfig, probe, KekError
|
|
313
|
+
rekeyDir, encryptedFilesIn, lineFilesIn, LINE_FILES, readConfig, writeConfig, probe, KekError
|
|
270
314
|
}
|
|
271
315
|
export { readConfig, writeConfig, probe, configFromEnv, KekError, CONFIG_FILE, WRAPPED_FILE }
|