@dotrino/vault 0.4.0 → 0.6.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 +2 -2
- package/src/enroll.js +27 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dotrino/vault",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.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",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"pairing"
|
|
43
43
|
],
|
|
44
44
|
"peerDependencies": {
|
|
45
|
-
"@dotrino/identity": ">=0.
|
|
45
|
+
"@dotrino/identity": ">=0.25.0",
|
|
46
46
|
"@dotrino/proxy-client": ">=0.6.0"
|
|
47
47
|
},
|
|
48
48
|
"license": "MIT",
|
package/src/enroll.js
CHANGED
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
* `docs/pairing-protocol.md`).
|
|
31
31
|
*/
|
|
32
32
|
import { verifyDeviceSig, pubkeyId, commitCode } from '@dotrino/identity/capabilities'
|
|
33
|
+
import { verifyContinuity } from '@dotrino/identity/acta'
|
|
33
34
|
|
|
34
35
|
/** Un token de emparejamiento vale 5 min. */
|
|
35
36
|
export const PAIRING_TTL_MS = 5 * 60 * 1000
|
|
@@ -44,6 +45,11 @@ export const MSG_ENROLLED = 'vault.enrolled'
|
|
|
44
45
|
export const MSG_REVOKED = 'vault.revoked'
|
|
45
46
|
export const MSG_ERROR = 'vault.error'
|
|
46
47
|
|
|
48
|
+
/** Los scopes del cert se corresponden 1:1 con las capacidades del acta (§D7). */
|
|
49
|
+
const SCOPE_TO_CAP = { 'vault:sign': 'sign', 'vault:store': 'store', 'vault:read': 'read' }
|
|
50
|
+
export const scopeToCaps = (scope) =>
|
|
51
|
+
(Array.isArray(scope) ? scope : [scope]).map((s) => SCOPE_TO_CAP[s]).filter(Boolean)
|
|
52
|
+
|
|
47
53
|
/** Token aleatorio de 128 bits en hex. */
|
|
48
54
|
export function randToken () {
|
|
49
55
|
const b = crypto.getRandomValues(new Uint8Array(16))
|
|
@@ -152,6 +158,12 @@ export function createEnrollDesk ({
|
|
|
152
158
|
pend.dpub = d.dpub
|
|
153
159
|
pend.deviceId = deviceId
|
|
154
160
|
pend.commit = d.commit
|
|
161
|
+
// Certificado de continuidad (opcional): lo firma la identidad que se une, con su
|
|
162
|
+
// propia llave. Se comprueba aquí y se guarda con el miembro al aprobar.
|
|
163
|
+
if (d.continuity) {
|
|
164
|
+
const okC = await verifyContinuity(d.continuity)
|
|
165
|
+
pend.continuity = (okC && d.continuity.member === d.dpub) ? d.continuity : null
|
|
166
|
+
}
|
|
155
167
|
pend.from = from // la bóveda NO conoce el código: lo aprende cuando lo tipeas
|
|
156
168
|
if (d.label) pend.label = String(d.label).slice(0, 60)
|
|
157
169
|
|
|
@@ -193,10 +205,24 @@ export function createEnrollDesk ({
|
|
|
193
205
|
}
|
|
194
206
|
|
|
195
207
|
const { cert } = await identity.signDelegation(pend.dpub, pend.scope, { ttlMs: pend.ttlMs, label: pend.label })
|
|
208
|
+
|
|
209
|
+
// Aprobar un emparejamiento ES admitir al dispositivo en el perfil: el cert es la
|
|
210
|
+
// credencial y el acta es la política, y no tiene sentido emitir una sin la otra.
|
|
211
|
+
// Las capacidades salen del scope que se pidió al emparejar (cert ∩ acta, §2.3).
|
|
212
|
+
let acta = null
|
|
213
|
+
try {
|
|
214
|
+
if (typeof identity.admitMember === 'function') {
|
|
215
|
+
const caps = scopeToCaps(pend.scope)
|
|
216
|
+
if (caps.length) await identity.admitMember({ pub: pend.dpub, label: pend.label || '', caps, cert, continuity: pend.continuity || null })
|
|
217
|
+
}
|
|
218
|
+
acta = (await identity.profileActa?.())?.acta || null
|
|
219
|
+
} catch (e) { log('[vault] no se pudo admitir en el acta:', e.message) }
|
|
220
|
+
|
|
196
221
|
audit('enroll', { device: pend.deviceId, label: pend.label || '', scope: pend.scope })
|
|
197
222
|
// Echamos el código tipeado junto al cert: el DISPOSITIVO acepta solo si coincide
|
|
198
223
|
// con el que generó → una bóveda falsa (que no lo conoce) no puede enrolarlo.
|
|
199
|
-
|
|
224
|
+
// El acta viaja con el cert: el dispositivo ya sabe de quién es el perfil al que entra.
|
|
225
|
+
reply(pend.from, { type: MSG_ENROLLED, code, cert, iss, acta })
|
|
200
226
|
pend.state = 'DONE'
|
|
201
227
|
pending.delete(pend.token)
|
|
202
228
|
fire(onPendingChange)
|