soulprint 0.1.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/dist/index.d.ts +6 -0
- package/dist/index.js +255 -0
- package/package.json +49 -0
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* @soulprint/cli
|
|
5
|
+
* npx soulprint <command> [options]
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
const soulprint_verify_1 = require("soulprint-verify");
|
|
9
|
+
const soulprint_core_1 = require("soulprint-core");
|
|
10
|
+
const node_fs_1 = require("node:fs");
|
|
11
|
+
const node_path_1 = require("node:path");
|
|
12
|
+
const node_os_1 = require("node:os");
|
|
13
|
+
const SOULPRINT_DIR = (0, node_path_1.join)((0, node_os_1.homedir)(), ".soulprint");
|
|
14
|
+
const TOKEN_FILE = (0, node_path_1.join)(SOULPRINT_DIR, "token.spt");
|
|
15
|
+
const args = process.argv.slice(2);
|
|
16
|
+
const cmd = args[0];
|
|
17
|
+
async function main() {
|
|
18
|
+
switch (cmd) {
|
|
19
|
+
case "verify-me": return await cmdVerifyMe();
|
|
20
|
+
case "show": return cmdShow();
|
|
21
|
+
case "node": return await cmdNode();
|
|
22
|
+
case "renew": return await cmdRenew();
|
|
23
|
+
case "install-deps": return await cmdInstallDeps();
|
|
24
|
+
case "help":
|
|
25
|
+
default: return cmdHelp();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// ── verify-me ─────────────────────────────────────────────────────────────────
|
|
29
|
+
async function cmdVerifyMe() {
|
|
30
|
+
const selfie = getArg("--selfie");
|
|
31
|
+
const document = getArg("--document");
|
|
32
|
+
const verbose = args.includes("--verbose");
|
|
33
|
+
const liveness = args.includes("--liveness");
|
|
34
|
+
const noZKP = args.includes("--no-zkp");
|
|
35
|
+
const minSim = parseFloat(getArg("--min-sim") ?? "0.65");
|
|
36
|
+
if (!selfie || !document) {
|
|
37
|
+
console.error("❌ Uso: soulprint verify-me --selfie <foto.jpg> --document <cedula.jpg>");
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
console.log("");
|
|
41
|
+
console.log("🔐 Soulprint — Verificación de identidad");
|
|
42
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
|
43
|
+
console.log("📂 Tus datos NUNCA salen de este dispositivo");
|
|
44
|
+
console.log("🧠 Los modelos de IA se cargan y borran de RAM automáticamente");
|
|
45
|
+
console.log("");
|
|
46
|
+
const t0 = Date.now();
|
|
47
|
+
const result = await (0, soulprint_verify_1.verifyIdentity)({
|
|
48
|
+
selfiePhoto: selfie,
|
|
49
|
+
documentPhoto: document,
|
|
50
|
+
verbose,
|
|
51
|
+
minFaceSim: minSim,
|
|
52
|
+
checkLiveness: liveness,
|
|
53
|
+
withZKP: !noZKP,
|
|
54
|
+
});
|
|
55
|
+
const elapsed = ((Date.now() - t0) / 1000).toFixed(1);
|
|
56
|
+
console.log("");
|
|
57
|
+
console.log("Pasos de verificación:");
|
|
58
|
+
const icons = { ok: "✅", fail: "❌", skip: "⏭" };
|
|
59
|
+
const labels = {
|
|
60
|
+
image_check: "Validación de imágenes",
|
|
61
|
+
ocr: "OCR del documento",
|
|
62
|
+
face_match: "Coincidencia facial",
|
|
63
|
+
nullifier_derived: "Derivación de nullifier",
|
|
64
|
+
zk_proof: "Generación de ZK proof",
|
|
65
|
+
token_created: "Emisión del token SPT",
|
|
66
|
+
};
|
|
67
|
+
for (const [step, status] of Object.entries(result.steps)) {
|
|
68
|
+
console.log(` ${icons[status]} ${labels[step] ?? step}`);
|
|
69
|
+
}
|
|
70
|
+
if (!result.success) {
|
|
71
|
+
console.log("");
|
|
72
|
+
console.log("❌ Verificación fallida:");
|
|
73
|
+
result.errors.forEach(e => console.log(` • ${e}`));
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
if (!(0, node_fs_1.existsSync)(SOULPRINT_DIR))
|
|
77
|
+
(0, node_fs_1.mkdirSync)(SOULPRINT_DIR, { recursive: true, mode: 0o700 });
|
|
78
|
+
(0, node_fs_1.writeFileSync)(TOKEN_FILE, result.token, "utf8");
|
|
79
|
+
console.log("");
|
|
80
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
|
81
|
+
console.log("✅ Identidad verificada exitosamente");
|
|
82
|
+
console.log("");
|
|
83
|
+
console.log(` DID: ${result.did}`);
|
|
84
|
+
console.log(` Trust Score: ${result.score}/100`);
|
|
85
|
+
console.log(` ZK Proof: ${result.zkProof ? "✅ incluido" : "⏭ omitido"}`);
|
|
86
|
+
console.log(` Token: ${TOKEN_FILE}`);
|
|
87
|
+
console.log(` Tiempo: ${elapsed}s`);
|
|
88
|
+
console.log("");
|
|
89
|
+
console.log("Tu identidad está verificada. Los servicios compatibles con");
|
|
90
|
+
console.log("Soulprint pueden confirmar que hay un humano real detrás de tu bot.");
|
|
91
|
+
console.log("");
|
|
92
|
+
console.log("Para ver tu token: soulprint show");
|
|
93
|
+
console.log("Para correr un nodo validador: soulprint node");
|
|
94
|
+
console.log("");
|
|
95
|
+
}
|
|
96
|
+
// ── show ──────────────────────────────────────────────────────────────────────
|
|
97
|
+
function cmdShow() {
|
|
98
|
+
if (!(0, node_fs_1.existsSync)(TOKEN_FILE)) {
|
|
99
|
+
console.error("❌ No tienes token. Ejecuta: soulprint verify-me --selfie yo.jpg --document cedula.jpg");
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
const raw = (0, node_fs_1.readFileSync)(TOKEN_FILE, "utf8").trim();
|
|
103
|
+
const token = (0, soulprint_core_1.decodeToken)(raw);
|
|
104
|
+
if (!token) {
|
|
105
|
+
console.error("❌ Token inválido o expirado. Ejecuta: soulprint renew o soulprint verify-me ...");
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
const expiresIn = Math.floor((token.expires * 1000 - Date.now()) / 1000 / 3600);
|
|
109
|
+
console.log("");
|
|
110
|
+
console.log("📋 Tu Soulprint Token");
|
|
111
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
|
112
|
+
console.log(` DID: ${token.did}`);
|
|
113
|
+
console.log(` Trust Score: ${token.score}/100`);
|
|
114
|
+
console.log(` Nivel: ${token.level}`);
|
|
115
|
+
console.log(` País: ${token.country ?? "—"}`);
|
|
116
|
+
console.log(` Credenciales: ${token.credentials.join(", ")}`);
|
|
117
|
+
console.log(` ZK Proof: ${token.zkp ? "✅ incluido" : "❌ no incluido"}`);
|
|
118
|
+
console.log(` Expira en: ${expiresIn}h`);
|
|
119
|
+
console.log(` Nullifier: ${token.nullifier.slice(0, 18)}...`);
|
|
120
|
+
console.log("");
|
|
121
|
+
console.log("Token (para copiar/pegar en la configuración de tu agente):");
|
|
122
|
+
console.log("");
|
|
123
|
+
console.log(raw);
|
|
124
|
+
console.log("");
|
|
125
|
+
}
|
|
126
|
+
// ── node ──────────────────────────────────────────────────────────────────────
|
|
127
|
+
async function cmdNode() {
|
|
128
|
+
const port = parseInt(getArg("--port") ?? "4888");
|
|
129
|
+
const verbose = args.includes("--verbose");
|
|
130
|
+
console.log("");
|
|
131
|
+
console.log("🌐 Soulprint Validator Node");
|
|
132
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
|
133
|
+
console.log(`Corriendo nodo validador en el puerto ${port}...`);
|
|
134
|
+
console.log("Para detener: Ctrl+C");
|
|
135
|
+
console.log("");
|
|
136
|
+
try {
|
|
137
|
+
const { startValidatorNode } = await import("soulprint-network");
|
|
138
|
+
startValidatorNode(port);
|
|
139
|
+
}
|
|
140
|
+
catch (e) {
|
|
141
|
+
if (e.code === "ERR_MODULE_NOT_FOUND") {
|
|
142
|
+
console.error("❌ soulprint-network no está instalado.");
|
|
143
|
+
console.error(" Instala con: npm install -g soulprint");
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
throw e;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// ── renew ─────────────────────────────────────────────────────────────────────
|
|
151
|
+
async function cmdRenew() {
|
|
152
|
+
console.log("");
|
|
153
|
+
console.log("🔄 Renovando token Soulprint...");
|
|
154
|
+
if (!(0, node_fs_1.existsSync)(TOKEN_FILE)) {
|
|
155
|
+
console.error("❌ No hay token para renovar. Ejecuta: soulprint verify-me ...");
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
const raw = (0, node_fs_1.readFileSync)(TOKEN_FILE, "utf8").trim();
|
|
159
|
+
const token = (0, soulprint_core_1.decodeToken)(raw);
|
|
160
|
+
if (!token) {
|
|
161
|
+
console.error("❌ Token muy expirado. Debes volver a verificar con: soulprint verify-me ...");
|
|
162
|
+
process.exit(1);
|
|
163
|
+
}
|
|
164
|
+
// Re-emitir el token con las mismas credenciales por 24h más
|
|
165
|
+
// (sin re-verificar cara/documento — solo extiende el lifetime)
|
|
166
|
+
const { keypairFromPrivateKey, createToken } = await import("soulprint-core");
|
|
167
|
+
const keyFile = (0, node_path_1.join)(SOULPRINT_DIR, "identity.json");
|
|
168
|
+
if (!(0, node_fs_1.existsSync)(keyFile)) {
|
|
169
|
+
console.error("❌ Keypair no encontrado. Debes verificar de nuevo: soulprint verify-me ...");
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
const stored = JSON.parse((0, node_fs_1.readFileSync)(keyFile, "utf8"));
|
|
173
|
+
const keypair = keypairFromPrivateKey(new Uint8Array(Buffer.from(stored.privateKey, "hex")));
|
|
174
|
+
const newToken = createToken(keypair, token.nullifier, token.credentials, {
|
|
175
|
+
country: token.country,
|
|
176
|
+
lifetimeSeconds: 86400,
|
|
177
|
+
});
|
|
178
|
+
(0, node_fs_1.writeFileSync)(TOKEN_FILE, newToken, "utf8");
|
|
179
|
+
const exp = new Date(Date.now() + 86400000).toLocaleString();
|
|
180
|
+
console.log(`✅ Token renovado hasta: ${exp}`);
|
|
181
|
+
}
|
|
182
|
+
// ── install-deps ──────────────────────────────────────────────────────────────
|
|
183
|
+
async function cmdInstallDeps() {
|
|
184
|
+
const { spawnSync } = await import("node:child_process");
|
|
185
|
+
console.log("");
|
|
186
|
+
console.log("📦 Instalando dependencias Python para verificación facial...");
|
|
187
|
+
console.log(" (insightface, opencv-python-headless, onnxruntime)");
|
|
188
|
+
console.log("");
|
|
189
|
+
const result = spawnSync("pip3", ["install", "insightface", "opencv-python-headless", "onnxruntime", "--quiet"], { stdio: "inherit" });
|
|
190
|
+
if (result.status === 0) {
|
|
191
|
+
console.log("\n✅ Dependencias instaladas correctamente.");
|
|
192
|
+
console.log("Ahora puedes ejecutar: soulprint verify-me --selfie yo.jpg --document cedula.jpg");
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
console.error("\n❌ Error instalando dependencias.");
|
|
196
|
+
console.error("Intenta manualmente: pip3 install insightface opencv-python-headless onnxruntime");
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// ── help ──────────────────────────────────────────────────────────────────────
|
|
200
|
+
function cmdHelp() {
|
|
201
|
+
console.log(`
|
|
202
|
+
🔐 Soulprint — Identidad verificable para bots de IA
|
|
203
|
+
|
|
204
|
+
"Every bot has a soul behind it."
|
|
205
|
+
|
|
206
|
+
COMANDOS:
|
|
207
|
+
|
|
208
|
+
verify-me Verifica tu identidad con cédula + selfie
|
|
209
|
+
--selfie <ruta> Foto tuya (selfie)
|
|
210
|
+
--document <ruta> Foto de tu cédula de ciudadanía
|
|
211
|
+
--verbose Mostrar progreso detallado
|
|
212
|
+
--liveness Verificar que la selfie es real (no foto de foto)
|
|
213
|
+
--no-zkp Omitir ZK proof (más rápido, menor privacidad)
|
|
214
|
+
--min-sim <float> Similitud mínima requerida (default: 0.65)
|
|
215
|
+
|
|
216
|
+
show Muestra tu token Soulprint actual
|
|
217
|
+
|
|
218
|
+
renew Renueva tu token por 24h sin reverificar
|
|
219
|
+
|
|
220
|
+
node Corre un nodo validador local
|
|
221
|
+
--port <número> Puerto (default: 4888)
|
|
222
|
+
|
|
223
|
+
install-deps Instala dependencias Python (InsightFace)
|
|
224
|
+
|
|
225
|
+
EJEMPLOS:
|
|
226
|
+
|
|
227
|
+
npx soulprint install-deps
|
|
228
|
+
npx soulprint verify-me --selfie yo.jpg --document cedula.jpg --verbose
|
|
229
|
+
npx soulprint show
|
|
230
|
+
npx soulprint node --port 4888
|
|
231
|
+
npx soulprint renew
|
|
232
|
+
|
|
233
|
+
INTEGRACIÓN (3 líneas):
|
|
234
|
+
|
|
235
|
+
// MCP Server
|
|
236
|
+
import { soulprint } from "soulprint-mcp";
|
|
237
|
+
server.use(soulprint({ minScore: 60 }));
|
|
238
|
+
|
|
239
|
+
// Express / REST API
|
|
240
|
+
import { soulprint } from "soulprint-express";
|
|
241
|
+
app.use(soulprint({ minScore: 40 }));
|
|
242
|
+
|
|
243
|
+
MÁS INFORMACIÓN:
|
|
244
|
+
https://github.com/manuelariasfz/soulprint
|
|
245
|
+
`);
|
|
246
|
+
}
|
|
247
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
248
|
+
function getArg(name) {
|
|
249
|
+
const idx = args.indexOf(name);
|
|
250
|
+
return idx !== -1 ? args[idx + 1] : undefined;
|
|
251
|
+
}
|
|
252
|
+
main().catch(err => {
|
|
253
|
+
console.error("❌ Error:", err.message);
|
|
254
|
+
process.exit(1);
|
|
255
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "soulprint",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Soulprint CLI — npx soulprint verify-me: verify your identity, run a validator node",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"soulprint": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/manuelariasfz/soulprint",
|
|
20
|
+
"directory": "packages/cli"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://github.com/manuelariasfz/soulprint#readme",
|
|
23
|
+
"keywords": [
|
|
24
|
+
"soulprint",
|
|
25
|
+
"cli",
|
|
26
|
+
"kyc",
|
|
27
|
+
"identity",
|
|
28
|
+
"cedula",
|
|
29
|
+
"colombia",
|
|
30
|
+
"zero-knowledge"
|
|
31
|
+
],
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"soulprint-core": "0.1.0",
|
|
35
|
+
"soulprint-network": "0.1.0",
|
|
36
|
+
"soulprint-verify": "0.1.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"typescript": "^5.4.0",
|
|
40
|
+
"@types/node": "^20.0.0"
|
|
41
|
+
},
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=18.0.0"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsc",
|
|
47
|
+
"postbuild": "chmod +x dist/index.js"
|
|
48
|
+
}
|
|
49
|
+
}
|