@dotrino/vault 0.92.0 → 0.93.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/vault",
3
- "version": "0.92.0",
3
+ "version": "0.93.0",
4
4
  "description": "La bóveda de Dotrino como librería: el MISMO núcleo que el binario corriendo en el navegador (`@dotrino/vault/browser`), el mostrador de emparejamiento y 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
@@ -169,18 +169,18 @@ export function atRestFor (dir, { password = '' } = {}) {
169
169
  /**
170
170
  * Cifra AHORA un archivo que esté en claro, verificando antes de reemplazar: se escribe a un
171
171
  * temporal, se vuelve a leer y descifrar, se compara, y solo entonces se renombra encima.
172
- * Devuelve 'ya-cifrado' | 'migrado' | 'sin-archivo'.
172
+ * Devuelve 'already-encrypted' | 'migrated' | 'no-file'.
173
173
  */
174
174
  export function migrateFile (file, key) {
175
175
  let text
176
- try { text = fs.readFileSync(file, 'utf8') } catch (_) { return 'sin-archivo' }
177
- if (isEncrypted(text)) return 'ya-cifrado'
176
+ try { text = fs.readFileSync(file, 'utf8') } catch (_) { return 'no-file' }
177
+ if (isEncrypted(text)) return 'already-encrypted'
178
178
  const blob = encryptText(text, key)
179
179
  if (decryptText(blob, key) !== text) throw new Error('at-rest: verification failed, the original is untouched')
180
180
  const tmp = file + '.atrest.tmp'
181
181
  fs.writeFileSync(tmp, blob, { mode: 0o600 })
182
182
  fs.renameSync(tmp, file)
183
- return 'migrado'
183
+ return 'migrated'
184
184
  }
185
185
 
186
186
  /** Los archivos de este directorio que están cifrados por nosotros. */
@@ -5,4 +5,4 @@
5
5
  * si no coincide con la del paquete: una versión anunciada que no es la que corre es peor
6
6
  * que no anunciar ninguna.
7
7
  */
8
- export const LIB_VERSION = '0.92.0'
8
+ export const LIB_VERSION = '0.93.0'
@@ -75,12 +75,12 @@ export function openSubacta (disk) {
75
75
  * aparatos se cuentan lo mismo.
76
76
  */
77
77
  async add (e) {
78
- if (!(await isAcceptable(e))) return { ok: false, reason: 'no-aceptable' }
78
+ if (!(await isAcceptable(e))) return { ok: false, reason: 'not-acceptable' }
79
79
  const id = idOf(e)
80
- if (data.entries.some((x) => idOf(x) === id)) return { ok: false, reason: 'ya-estaba' }
80
+ if (data.entries.some((x) => idOf(x) === id)) return { ok: false, reason: 'already-present' }
81
81
  data.entries = [...data.entries, e]
82
82
  guardar()
83
- return { ok: true, reason: 'nueva' }
83
+ return { ok: true, reason: 'new' }
84
84
  },
85
85
 
86
86
  /**
package/src/core/vault.js CHANGED
@@ -872,13 +872,13 @@ export async function startVault ({ platform, proxyUrl, log = console.log, onEnr
872
872
  // acta falta justo cuando algo se rompió (un archivo a medias, un `catch` que devolvió
873
873
  // null), que es cuando menos hay que fiarse. Toda cuenta tiene acta desde hace versiones.
874
874
  if (!record) {
875
- audit('rejected', { what, reason: 'sin-acta' })
875
+ audit('rejected', { what, reason: 'no-record' })
876
876
  reply(from, { type: MSG.ERROR, error: 'unauthorized: this vault has no record to decide with' })
877
877
  return false
878
878
  }
879
879
  if (Acta.memberCanScope(record, chk.device, scope)) return true
880
- audit('rejected', { what, reason: 'acta' })
881
- reply(from, { type: MSG.ERROR, error: 'unauthorized: acta — this member no longer has that permission' })
880
+ audit('rejected', { what, reason: 'record' })
881
+ reply(from, { type: MSG.ERROR, error: 'unauthorized: record — this member no longer has that permission' })
882
882
  return false
883
883
  }
884
884
 
@@ -976,14 +976,14 @@ export async function startVault ({ platform, proxyUrl, log = console.log, onEnr
976
976
  const t = Date.now()
977
977
  for (const [n, v] of aperturas) if (v.exp <= t) aperturas.delete(n)
978
978
  const eph = await makeEphemeralKey()
979
- aperturas.set('pendiente', { privateKey: eph.privateKey, exp: t + EPHEMERAL_TTL_MS })
979
+ aperturas.set('pending', { privateKey: eph.privateKey, exp: t + EPHEMERAL_TTL_MS })
980
980
  audit('unlock.begin', { by })
981
981
  return { ...params, ek: eph.ek }
982
982
  },
983
983
 
984
984
  async open ({ nonce, enc, by }) {
985
- const guardada = aperturas.get('pendiente')
986
- aperturas.delete('pendiente')
985
+ const guardada = aperturas.get('pending')
986
+ aperturas.delete('pending')
987
987
  if (!guardada || guardada.exp <= Date.now()) {
988
988
  return { ok: false, error: 'unlock: ask for a key first, and use it within a minute' }
989
989
  }
@@ -992,7 +992,7 @@ export async function startVault ({ platform, proxyUrl, log = console.log, onEnr
992
992
  // EL NONCE VA DENTRO DEL SOBRE. Si fuera solo por fuera, un sobre capturado se
993
993
  // reenvía con un nonce nuevo y el candado del nonce no sirve de nada.
994
994
  if (!payload || payload.nonce !== nonce || typeof payload.key !== 'string') {
995
- audit('rejected', { what: 'unlock', by, reason: 'sobre' })
995
+ audit('rejected', { what: 'unlock', by, reason: 'envelope' })
996
996
  return { ok: false, error: 'unlock: the envelope does not check out' }
997
997
  }
998
998
  const derivada = b64ToBytes(payload.key)
@@ -1314,10 +1314,10 @@ export async function startVault ({ platform, proxyUrl, log = console.log, onEnr
1314
1314
  const { issued, revoked } = await identity.listDelegations()
1315
1315
  if (!puedeVerTodo) {
1316
1316
  if (!record) {
1317
- audit('rejected', { what: 'devices', reason: 'sin-acta' })
1317
+ audit('rejected', { what: 'devices', reason: 'no-record' })
1318
1318
  return reply(from, { type: MSG.ERROR, error: 'unauthorized: this vault has no record to decide with' })
1319
1319
  }
1320
- audit('devices', { device: await deviceIdOf(chk.device).catch(() => null), solo: 'revocaciones' })
1320
+ audit('devices', { device: await deviceIdOf(chk.device).catch(() => null), only: 'revocations' })
1321
1321
  return reply(from, { type: MSG.DEVICES_RESULT, devices: [], revoked, blocked: blocked.pubs(), acta: record, sealerChain: await sealerChainOf() })
1322
1322
  }
1323
1323
  // El acta viaja con la lista: así cada dispositivo se entera de los cambios de
@@ -1401,7 +1401,7 @@ export async function startVault ({ platform, proxyUrl, log = console.log, onEnr
1401
1401
  // Sin acta no se renueva: caer al scope del papel viejo es reconceder a ciegas lo que
1402
1402
  // el acta ya no dice. Un repliegue así no protege de nada, tapa.
1403
1403
  if (!record) {
1404
- audit('rejected', { what: 'renew', device: await deviceIdOf(p.cert.sub), reason: 'sin-acta' })
1404
+ audit('rejected', { what: 'renew', device: await deviceIdOf(p.cert.sub), reason: 'no-record' })
1405
1405
  return reply(from, { type: MSG.ERROR, error: 'unauthorized: this vault has no record to decide with' })
1406
1406
  }
1407
1407
  const scope = Acta.memberScopes(record, p.cert.sub)
@@ -1460,7 +1460,7 @@ export async function startVault ({ platform, proxyUrl, log = console.log, onEnr
1460
1460
  // que se cerró en `handleSign`, en otro mostrador.
1461
1461
  const record = (await identity.profileActa?.().catch(() => null))?.acta
1462
1462
  if (!record || !Acta.memberCanReadSecrets(record, chk.device, ns)) {
1463
- audit('rejected', { what: 'enckey', ns, reason: record ? 'cn' : 'sin-acta' })
1463
+ audit('rejected', { what: 'enckey', ns, reason: record ? 'cn' : 'no-record' })
1464
1464
  return reply(from, { type: MSG.ERROR, error: `unauthorized: cn — the record does not recognise this member as the "${ns}" service` })
1465
1465
  }
1466
1466
  try {
@@ -1545,7 +1545,7 @@ export async function startVault ({ platform, proxyUrl, log = console.log, onEnr
1545
1545
  if (!chk.ok) return denyChain(from, chk, p, 'digest')
1546
1546
  const record = (await identity.profileActa?.().catch(() => null))?.acta
1547
1547
  if (!record || !Acta.memberCanReadSecrets(record, chk.device, ns)) {
1548
- audit('rejected', { what: 'digest', ns, reason: record ? 'cn' : 'sin-acta' })
1548
+ audit('rejected', { what: 'digest', ns, reason: record ? 'cn' : 'no-record' })
1549
1549
  return reply(from, { type: MSG.ERROR, error: `unauthorized: cn — the record does not recognise this member as the "${ns}" service` })
1550
1550
  }
1551
1551
  const body = { op: 'secrets.digest', ns, digest: drawerDigest(ns, chk.device), ts: Date.now() }
@@ -1578,8 +1578,8 @@ export async function startVault ({ platform, proxyUrl, log = console.log, onEnr
1578
1578
  if (!chk.ok) return denyChain(from, chk, p, 'update-ask')
1579
1579
  const record = (await identity.profileActa?.().catch(() => null))?.acta
1580
1580
  if (!record || !(record.members || []).some((m) => m.pub === chk.device)) {
1581
- audit('rejected', { what: 'update-ask', reason: record ? 'acta' : 'sin-acta' })
1582
- return reply(from, { type: MSG.ERROR, error: 'unauthorized: acta — this device is not in the record' })
1581
+ audit('rejected', { what: 'update-ask', reason: record ? 'record' : 'no-record' })
1582
+ return reply(from, { type: MSG.ERROR, error: 'unauthorized: record — this device is not in the record' })
1583
1583
  }
1584
1584
  const product = cut(p.data?.product, 128)
1585
1585
  const version = cut(p.data?.version, 64)
@@ -1656,8 +1656,8 @@ export async function startVault ({ platform, proxyUrl, log = console.log, onEnr
1656
1656
  const record = (await identity.profileActa?.().catch(() => null))?.acta
1657
1657
  const member = (record?.members || []).find((m) => m.pub === chk.device)
1658
1658
  if (!member) {
1659
- audit('rejected', { what: op, reason: record ? 'acta' : 'sin-acta' })
1660
- return reply(from, { type: MSG.ERROR, error: 'unauthorized: acta — this device is not in the record' })
1659
+ audit('rejected', { what: op, reason: record ? 'record' : 'no-record' })
1660
+ return reply(from, { type: MSG.ERROR, error: 'unauthorized: record — this device is not in the record' })
1661
1661
  }
1662
1662
  const product = cut(p.data?.product, 128)
1663
1663
  const version = cut(p.data?.version, 64)
@@ -1685,7 +1685,7 @@ export async function startVault ({ platform, proxyUrl, log = console.log, onEnr
1685
1685
  if (!chk.ok) return denyChain(from, chk, p, op)
1686
1686
  const record = (await identity.profileActa?.().catch(() => null))?.acta
1687
1687
  if (!record || !Acta.memberCanReadSecrets(record, chk.device, ns)) {
1688
- audit('rejected', { what: op, ns, reason: record ? 'cn' : 'sin-acta' })
1688
+ audit('rejected', { what: op, ns, reason: record ? 'cn' : 'no-record' })
1689
1689
  return reply(from, { type: MSG.ERROR, error: `unauthorized: cn — the record does not recognise this member as the "${ns}" service` })
1690
1690
  }
1691
1691
  const deviceId = await deviceIdOf(chk.device).catch(() => null)
@@ -1756,7 +1756,7 @@ export async function startVault ({ platform, proxyUrl, log = console.log, onEnr
1756
1756
  // llave del proxy no ve nada que no sea del proxy, y está escrito donde se puede comprobar.
1757
1757
  const record = (await identity.profileActa?.().catch(() => null))?.acta
1758
1758
  if (!record || !Acta.memberCanReadSecrets(record, chk.device, ns)) {
1759
- audit('rejected', { what: 'secrets', ns, reason: record ? 'cn' : 'sin-acta' })
1759
+ audit('rejected', { what: 'secrets', ns, reason: record ? 'cn' : 'no-record' })
1760
1760
  return reply(from, { type: MSG.ERROR, error: `unauthorized: cn — the record does not recognise this member as the "${ns}" service` })
1761
1761
  }
1762
1762
  // APROBACIÓN: si este APARATO está marcado (`dotrino-vault approval <ID> on`), liberarle
@@ -1908,8 +1908,8 @@ export async function startVault ({ platform, proxyUrl, log = console.log, onEnr
1908
1908
  if (!chk.ok) return denyChain(from, chk, p, 'approval')
1909
1909
  const record = (await identity.profileActa?.().catch(() => null))?.acta
1910
1910
  if (!record || !Acta.memberCan(record, chk.device, 'approve')) {
1911
- audit('rejected', { what: 'approval', reason: record ? 'acta' : 'sin-acta' })
1912
- return reply(from, { type: MSG.ERROR, error: 'unauthorized: acta — this member does not approve' })
1911
+ audit('rejected', { what: 'approval', reason: record ? 'record' : 'no-record' })
1912
+ return reply(from, { type: MSG.ERROR, error: 'unauthorized: record — this member does not approve' })
1913
1913
  }
1914
1914
  const by = await deviceIdOf(chk.device).catch(() => null)
1915
1915
  const answer = async (body) => {
@@ -2157,8 +2157,8 @@ export async function startVault ({ platform, proxyUrl, log = console.log, onEnr
2157
2157
  if (!chk.ok) return denyChain(from, chk, p, 'incident')
2158
2158
  const record = await refreshActa()
2159
2159
  if (!record || !Acta.memberCan(record, chk.device, 'sign')) {
2160
- audit('rejected', { what: 'incident', reason: record ? 'acta' : 'sin-acta' })
2161
- return reply(from, { type: MSG.ERROR, error: 'unauthorized: acta — this member cannot report incidents' })
2160
+ audit('rejected', { what: 'incident', reason: record ? 'record' : 'no-record' })
2161
+ return reply(from, { type: MSG.ERROR, error: 'unauthorized: record — this member cannot report incidents' })
2162
2162
  }
2163
2163
  const d = p.data || {}
2164
2164
  const kind = typeof d.kind === 'string' ? d.kind.slice(0, 32) : ''
@@ -2913,7 +2913,7 @@ export async function startVault ({ platform, proxyUrl, log = console.log, onEnr
2913
2913
  return chk
2914
2914
  }
2915
2915
  const record = (await identity.profileActa?.().catch(() => null))?.acta
2916
- if (!record || !Acta.memberCan(record, chk.device, 'admin')) return { ok: false, reason: record ? 'acta' : 'sin-acta' }
2916
+ if (!record || !Acta.memberCan(record, chk.device, 'admin')) return { ok: false, reason: record ? 'record' : 'no-record' }
2917
2917
  return chk
2918
2918
  }
2919
2919
  })
@@ -2949,12 +2949,12 @@ export async function startVault ({ platform, proxyUrl, log = console.log, onEnr
2949
2949
  // la fecha de la última renuncia por miembro y rechace las que no sean posteriores.
2950
2950
  const actual = (await identity.profileActa?.().catch(() => null))?.acta || null
2951
2951
  if (!actual) {
2952
- audit('rejected', { what: 'renounce', reason: 'sin-acta' })
2952
+ audit('rejected', { what: 'renounce', reason: 'no-record' })
2953
2953
  return reply(from, { type: MSG.ERROR, error: 'renounce: this vault has no record to apply it to' })
2954
2954
  }
2955
2955
  const tiene = new Set(Acta.effectiveCaps(actual, record.member) || [])
2956
2956
  if (!(record.caps || []).some((c) => tiene.has(c))) {
2957
- audit('rejected', { what: 'renounce', reason: 'nada-que-quitar' })
2957
+ audit('rejected', { what: 'renounce', reason: 'nothing-to-remove' })
2958
2958
  return reply(from, { type: MSG.ERROR, error: 'renounce: that member no longer holds any of those capabilities' })
2959
2959
  }
2960
2960
  try {
@@ -2963,8 +2963,8 @@ export async function startVault ({ platform, proxyUrl, log = console.log, onEnr
2963
2963
  // de la maestra, y con el perfil cerrado la renuncia se perdía con un error — en el
2964
2964
  // único momento en que de verdad hace falta.
2965
2965
  const guardada = await subacta.add(record)
2966
- if (!guardada.ok && guardada.reason === 'no-aceptable') {
2967
- audit('rejected', { what: 'renounce', reason: 'no-aceptable' })
2966
+ if (!guardada.ok && guardada.reason === 'not-acceptable') {
2967
+ audit('rejected', { what: 'renounce', reason: 'not-acceptable' })
2968
2968
  return reply(from, { type: MSG.ERROR, error: 'renounce: the entry is not one this vault accepts' })
2969
2969
  }
2970
2970
  const device = await deviceIdOf(record.member).catch(() => null)
package/src/enroll.js CHANGED
@@ -272,7 +272,7 @@ export function createEnrollDesk ({
272
272
  return { ignored: true }
273
273
  }
274
274
  if (!pend || Date.now() > pend.exp) {
275
- audit('rejected', { what: 'hello', reason: 'sin-sesion' })
275
+ audit('rejected', { what: 'hello', reason: 'no-session' })
276
276
  return fail(from, 'no pairing session open for that code', String(p?.sn || ''))
277
277
  }
278
278
  // La respuesta va FIRMADA por la maestra y el `sn` va dentro de lo firmado. Eso ata
package/src/index.js CHANGED
@@ -261,7 +261,7 @@ export async function startDeviceVault (identity, { proxyUrl, client: injectedCl
261
261
  if (expectedScope) {
262
262
  const record = (await identity.profileActa?.().catch(() => null))?.acta || null
263
263
  if (record && !memberCanScope(record, chk.device, expectedScope)) {
264
- send(from, { type: MSG.ERROR, error: 'unauthorized: acta — this member no longer has that permission' })
264
+ send(from, { type: MSG.ERROR, error: 'unauthorized: record — this member no longer has that permission' })
265
265
  return null
266
266
  }
267
267
  }
@@ -356,7 +356,7 @@ export async function startDeviceVault (identity, { proxyUrl, client: injectedCl
356
356
  if (p.type === MSG.HELLO) handle('hello', desk.handleHello(_from, p), _from)
357
357
  else if (p.type === MSG.ENROLL) handle('enroll', desk.handleEnroll(_from, p), _from)
358
358
  // Camino A: el aparato devuelve su acta sellada admitiendo a esta bóveda.
359
- else if (p.type === MSG.ACTA_SEALED) handle('acta', desk.handleActaSealed(_from, p), _from)
359
+ else if (p.type === MSG.ACTA_SEALED) handle('record-sealed', desk.handleActaSealed(_from, p), _from)
360
360
  else if (p.type === MSG.RENEW) handle('renew', handleRenew(_from, p), _from)
361
361
  else if (p.type === MSG.DEVICES) handle('devices', handleDevices(_from, p), _from)
362
362
  // Lo que faltaba para que un aparato enrolado aquí pueda hacer lo mismo que contra
@@ -67,7 +67,7 @@ export const loginAddress = (user, fingerprint) => `${user}@${accountCode(finger
67
67
  */
68
68
  export async function accountFingerprint (identity) {
69
69
  const pid = (await identity?.profileActa?.().catch(() => null))?.acta?.profileId
70
- if (!pid) throw err('no-acta', 'this vault has no account record yet: there is no address to build')
70
+ if (!pid) throw err('no-record', 'this vault has no account record yet: there is no address to build')
71
71
  return (await pubkeyId(pid)).slice(0, 16)
72
72
  }
73
73