@dotrino/vaultd 0.132.0 → 0.133.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/lib/src/deviceInfo.js +70 -0
- package/package.json +1 -1
- package/src/ctl.js +5 -2
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* deviceInfo.js — QUÉ APARATO SOY, dicho igual en todos los comandos del ecosistema.
|
|
3
|
+
*
|
|
4
|
+
* Regla del dueño (2026-09-29): todo comando que se enrola en una bóveda tiene un `info`
|
|
5
|
+
* que enseña la información del aparato, **sobre todo su id**. El id (`AB12-CD34`) es lo que
|
|
6
|
+
* sale en `dotrino-vault members` y lo que pide `dotrino-vault caps <ID>`: sin verlo aquí no
|
|
7
|
+
* hay forma de saber qué fila del acta es esta máquina. `dotrino-env status` enseñaba la
|
|
8
|
+
* llave de la bóveda en crudo (`{"key_ops":["verify"],…`) y ningún id.
|
|
9
|
+
*
|
|
10
|
+
* Una sola pieza para todos: `dotrino-env`, los agentes de remote-agent (terminal, ia) y lo
|
|
11
|
+
* que venga. Local y sin red: lee el enlace que ya está en el disco, así que responde con
|
|
12
|
+
* la bóveda apagada, que es justo cuando más falta hace saber quién eres.
|
|
13
|
+
*
|
|
14
|
+
* Sirve cualquier enlace con la forma común `{ device: { publickey }, cert, iss, proxy }`
|
|
15
|
+
* (el de remote-agent y el de un servicio de dotrino-env).
|
|
16
|
+
*/
|
|
17
|
+
import { pubkeyId } from '@dotrino/identity/capabilities'
|
|
18
|
+
|
|
19
|
+
/** El id corto de una llave, como lo enseña la bóveda: `AB12-CD34`. */
|
|
20
|
+
export async function shortId (publickey) {
|
|
21
|
+
return (await pubkeyId(publickey)).slice(0, 8).toUpperCase().replace(/(.{4})(.{4})/, '$1-$2')
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* La información del aparato a partir de su enlace.
|
|
26
|
+
* @param {{ device?: { publickey?: string }, cert?: object, iss?: string, proxy?: string }} link
|
|
27
|
+
* @param {Record<string, any>} [extra] lo propio de cada comando (nombre, versión, carpeta…).
|
|
28
|
+
*/
|
|
29
|
+
export async function deviceInfo (link, extra = {}) {
|
|
30
|
+
const pub = link?.device?.publickey
|
|
31
|
+
if (!pub) throw Object.assign(new Error('this link has no device key: enroll first'), { code: 'not-enrolled' })
|
|
32
|
+
const cert = link.cert || null
|
|
33
|
+
return {
|
|
34
|
+
id: await shortId(pub),
|
|
35
|
+
vault: link.iss ? await shortId(link.iss) : null,
|
|
36
|
+
scope: Array.isArray(cert?.scope) ? cert.scope : [],
|
|
37
|
+
// El papel se describe por el acta a la que se ató; uno del modelo viejo, por su fecha,
|
|
38
|
+
// porque eso sí importa: es lo único que todavía caduca.
|
|
39
|
+
record: typeof cert?.seq === 'number' ? cert.seq : null,
|
|
40
|
+
legacyExpires: typeof cert?.seq !== 'number' && typeof cert?.exp === 'number' ? cert.exp : null,
|
|
41
|
+
proxy: link.proxy || null,
|
|
42
|
+
publickey: pub,
|
|
43
|
+
...extra
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const LABELS = {
|
|
48
|
+
id: 'Aparato', vault: 'Bóveda', kind: 'Tipo', name: 'Nombre', ns: 'Cajón', version: 'Versión',
|
|
49
|
+
scope: 'Permisos', record: 'Papel', dir: 'Enlace', proxy: 'Proxio'
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* El texto que imprime `info`. El id va primero y con la pista de dónde buscarlo: es lo que
|
|
54
|
+
* se viene a mirar.
|
|
55
|
+
* @param {Awaited<ReturnType<typeof deviceInfo>>} info
|
|
56
|
+
*/
|
|
57
|
+
export function formatDeviceInfo (info) {
|
|
58
|
+
const rows = []
|
|
59
|
+
const put = (k, v) => { if (v != null && v !== '') rows.push([LABELS[k] || k, v]) }
|
|
60
|
+
put('id', `${info.id} (así sale en \`dotrino-vault members\`)`)
|
|
61
|
+
put('vault', info.vault)
|
|
62
|
+
put('kind', info.kind); put('name', info.name); put('ns', info.ns); put('version', info.version)
|
|
63
|
+
put('scope', info.scope?.length ? info.scope.join(', ') : null)
|
|
64
|
+
put('record', info.record != null
|
|
65
|
+
? `acta #${info.record}`
|
|
66
|
+
: (info.legacyExpires ? `modelo viejo, vence ${new Date(info.legacyExpires).toISOString().slice(0, 10)}` : null))
|
|
67
|
+
put('dir', info.dir); put('proxy', info.proxy)
|
|
68
|
+
const w = Math.max(...rows.map(([k]) => k.length))
|
|
69
|
+
return rows.map(([k, v]) => `${(k + ':').padEnd(w + 2)}${v}`).join('\n')
|
|
70
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dotrino/vaultd",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.133.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Certificador personal de Dotrino: daemon headless que custodia la clave maestra y delega capacidades a tus dispositivos por el proxy. Tu CA propia.",
|
|
6
6
|
"bin": {
|
package/src/ctl.js
CHANGED
|
@@ -1971,7 +1971,7 @@ function help () {
|
|
|
1971
1971
|
console.log(`dotrino-vault — control del certificador personal
|
|
1972
1972
|
|
|
1973
1973
|
tui interfaz de terminal a pantalla completa (bóvedas, pares, secretos)
|
|
1974
|
-
status
|
|
1974
|
+
status | info estado del servicio + fingerprint + el id de cada perfil
|
|
1975
1975
|
pair [--save <f>] inicia un emparejamiento (QR + espera); --save escribe la invitación (.dpair)
|
|
1976
1976
|
pair --kms <config.json>
|
|
1977
1977
|
el sitio que se cree (--adopt o --new-account) NACE con su clave
|
|
@@ -2178,7 +2178,10 @@ export async function runCtl (argv) {
|
|
|
2178
2178
|
case 'profile': return cmdProfile(rest)
|
|
2179
2179
|
case 'unlock': return cmdUnlock()
|
|
2180
2180
|
case 'lock': return cmdLock()
|
|
2181
|
-
|
|
2181
|
+
// `info` es el comando común de todo el ecosistema para «qué aparato soy» (regla del
|
|
2182
|
+
// dueño, 2026-09-29); en la bóveda eso es su estado, que ya enseña el id de cada perfil.
|
|
2183
|
+
case 'status':
|
|
2184
|
+
case 'info': return cmdStatus()
|
|
2182
2185
|
case 'pair': return cmdPair(rest)
|
|
2183
2186
|
case 'join': return cmdJoin(rest)
|
|
2184
2187
|
case 'pending': return cmdPending()
|