@dotrino/identity 0.106.0 → 0.107.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/vault/content.js +59 -3
package/package.json
CHANGED
package/vault/content.js
CHANGED
|
@@ -106,12 +106,68 @@ export async function myContentKey ({ keyring, myPub, myEncPrivateKey }) {
|
|
|
106
106
|
return null
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
/**
|
|
109
|
+
/**
|
|
110
|
+
* La marca de un sobre de la llave de la cuenta. La lleva todo sobre de `encryptWithCek`
|
|
111
|
+
* para que quien guarda datos ajenos —la bóveda con el almacén de las apps— lo RECONOZCA
|
|
112
|
+
* dentro de un JSON cualquiera sin adivinar por la forma, y pueda volver a cerrarlo con la
|
|
113
|
+
* generación vigente cuando la llave rota (`resealStale`).
|
|
114
|
+
*/
|
|
115
|
+
export const CEK_ENVELOPE = 'dotrino-cek'
|
|
116
|
+
|
|
117
|
+
/** ¿Es un sobre de la llave de la cuenta? */
|
|
118
|
+
export const isCekEnvelope = (v) => !!v && typeof v === 'object' && v.t === CEK_ENVELOPE &&
|
|
119
|
+
Number.isInteger(v.gen) && typeof v.iv === 'string' && typeof v.ct === 'string'
|
|
120
|
+
|
|
121
|
+
/** Cifra con la CEK. Devuelve un sobre `{ t, gen, iv, ct }` (el `gen` dice con cuál se cifró). */
|
|
110
122
|
export async function encryptWithCek ({ cek, gen, plaintext }) {
|
|
111
123
|
const k = await subtle.importKey('raw', fromB64(cek), { name: 'AES-GCM' }, false, ['encrypt'])
|
|
112
124
|
const iv = globalThis.crypto.getRandomValues(new Uint8Array(12))
|
|
113
125
|
const ct = await subtle.encrypt({ name: 'AES-GCM', iv }, k, new TextEncoder().encode(plaintext))
|
|
114
|
-
return { gen, iv: b64(iv), ct: b64(ct) }
|
|
126
|
+
return { t: CEK_ENVELOPE, gen, iv: b64(iv), ct: b64(ct) }
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* VUELVE A CERRAR con la generación vigente todo sobre de una generación anterior que haya
|
|
131
|
+
* dentro de `value`, a cualquier profundidad. Devuelve una copia (no toca el original) y
|
|
132
|
+
* cuántos sobres cambió.
|
|
133
|
+
*
|
|
134
|
+
* Es lo que hace la bóveda al abrirse después de una rotación (dueño, 2026-09-30): lo que
|
|
135
|
+
* sirve va SIEMPRE con la llave vigente, así que un aparato que entra después —que solo
|
|
136
|
+
* recibe esa generación— abre todo, y la llave vieja deja de abrir nada porque ya no se
|
|
137
|
+
* le sirve nada cerrado con ella.
|
|
138
|
+
*
|
|
139
|
+
* `reseal(envelope)` abre y vuelve a cerrar un sobre; lo pone quien tiene las llaves. Si
|
|
140
|
+
* un sobre no se puede abrir, se PARA: no se deja a medias ni se salta en silencio.
|
|
141
|
+
*
|
|
142
|
+
* @param {any} value
|
|
143
|
+
* @param {{ gen: number, reseal: (env: object) => Promise<object> }} o
|
|
144
|
+
* @returns {Promise<{ value: any, changed: number }>}
|
|
145
|
+
*/
|
|
146
|
+
export async function resealStale (value, { gen, reseal }) {
|
|
147
|
+
if (!Number.isInteger(gen)) throw new Error('resealStale: the current generation is required')
|
|
148
|
+
let changed = 0
|
|
149
|
+
const walk = async (v) => {
|
|
150
|
+
if (isCekEnvelope(v)) {
|
|
151
|
+
if (v.gen === gen) return v
|
|
152
|
+
const nuevo = await reseal(v)
|
|
153
|
+
if (!isCekEnvelope(nuevo) || nuevo.gen !== gen) throw new Error(`resealStale: reseal did not return an envelope of generation ${gen}`)
|
|
154
|
+
changed++
|
|
155
|
+
return nuevo
|
|
156
|
+
}
|
|
157
|
+
if (Array.isArray(v)) {
|
|
158
|
+
const out = []
|
|
159
|
+
for (const x of v) out.push(await walk(x))
|
|
160
|
+
return out
|
|
161
|
+
}
|
|
162
|
+
if (v && typeof v === 'object') {
|
|
163
|
+
const out = {}
|
|
164
|
+
for (const [k, x] of Object.entries(v)) out[k] = await walk(x)
|
|
165
|
+
return out
|
|
166
|
+
}
|
|
167
|
+
return v
|
|
168
|
+
}
|
|
169
|
+
const out = await walk(value)
|
|
170
|
+
return { value: out, changed }
|
|
115
171
|
}
|
|
116
172
|
|
|
117
173
|
/**
|
|
@@ -144,5 +200,5 @@ export async function decryptWithKeyring ({ envelope, keyring, myPub, myEncPriva
|
|
|
144
200
|
|
|
145
201
|
export default {
|
|
146
202
|
makeContentKey, wrapForMember, openWrap, makeGeneration, myContentKey,
|
|
147
|
-
encryptWithCek, decryptWithCek, decryptWithKeyring
|
|
203
|
+
encryptWithCek, decryptWithCek, decryptWithKeyring, CEK_ENVELOPE, isCekEnvelope, resealStale
|
|
148
204
|
}
|