soulprint-express 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 +60 -0
- package/dist/index.js +116 -0
- package/dist/verify.d.ts +14 -0
- package/dist/verify.js +46 -0
- package/package.json +52 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { SoulprintToken } from "soulprint-core";
|
|
2
|
+
import { verifySPT, SoulprintOptions } from "./verify.js";
|
|
3
|
+
export { verifySPT, SoulprintOptions };
|
|
4
|
+
/**
|
|
5
|
+
* soulprint() — Express/Connect middleware for Soulprint identity verification.
|
|
6
|
+
*
|
|
7
|
+
* USAGE:
|
|
8
|
+
*
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import express from "express";
|
|
11
|
+
* import { soulprint } from "soulprint-express";
|
|
12
|
+
*
|
|
13
|
+
* const app = express();
|
|
14
|
+
*
|
|
15
|
+
* // Protect entire API — require KYC verified humans
|
|
16
|
+
* app.use(soulprint({ minScore: 60 }));
|
|
17
|
+
*
|
|
18
|
+
* // Protect specific route — require full biometric KYC
|
|
19
|
+
* app.post("/sensitive", soulprint({ require: ["DocumentVerified", "FaceMatch"] }), handler);
|
|
20
|
+
*
|
|
21
|
+
* // Inside a handler — get the verified identity
|
|
22
|
+
* app.get("/me", soulprint({ minScore: 20 }), (req, res) => {
|
|
23
|
+
* const identity = req.soulprint; // SoulprintToken
|
|
24
|
+
* res.json({ nullifier: identity.nullifier, score: identity.score });
|
|
25
|
+
* });
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* Token is read from:
|
|
29
|
+
* - HTTP header: X-Soulprint: <SPT>
|
|
30
|
+
* - Query param: ?spt=<SPT>
|
|
31
|
+
* - Bearer token: Authorization: Bearer <SPT>
|
|
32
|
+
*/
|
|
33
|
+
export declare function soulprint(opts?: SoulprintOptions): (req: any, res: any, next: Function) => void;
|
|
34
|
+
/**
|
|
35
|
+
* soulprintFastify() — Fastify plugin for Soulprint verification.
|
|
36
|
+
*
|
|
37
|
+
* USAGE:
|
|
38
|
+
*
|
|
39
|
+
* ```typescript
|
|
40
|
+
* import Fastify from "fastify";
|
|
41
|
+
* import { soulprintFastify } from "soulprint-express";
|
|
42
|
+
*
|
|
43
|
+
* const fastify = Fastify();
|
|
44
|
+
* await fastify.register(soulprintFastify, { minScore: 60 });
|
|
45
|
+
*
|
|
46
|
+
* fastify.get("/me", async (request) => {
|
|
47
|
+
* const identity = request.soulprint;
|
|
48
|
+
* return { nullifier: identity?.nullifier };
|
|
49
|
+
* });
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare function soulprintFastify(fastify: any, opts?: SoulprintOptions): Promise<void>;
|
|
53
|
+
declare global {
|
|
54
|
+
namespace Express {
|
|
55
|
+
interface Request {
|
|
56
|
+
soulprint?: SoulprintToken;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export { decodeToken, SoulprintToken, TrustLevel, CredentialType } from "soulprint-core";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.decodeToken = exports.verifySPT = void 0;
|
|
4
|
+
exports.soulprint = soulprint;
|
|
5
|
+
exports.soulprintFastify = soulprintFastify;
|
|
6
|
+
const verify_js_1 = require("./verify.js");
|
|
7
|
+
Object.defineProperty(exports, "verifySPT", { enumerable: true, get: function () { return verify_js_1.verifySPT; } });
|
|
8
|
+
// ── Express Middleware ────────────────────────────────────────────────────────
|
|
9
|
+
/**
|
|
10
|
+
* soulprint() — Express/Connect middleware for Soulprint identity verification.
|
|
11
|
+
*
|
|
12
|
+
* USAGE:
|
|
13
|
+
*
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import express from "express";
|
|
16
|
+
* import { soulprint } from "soulprint-express";
|
|
17
|
+
*
|
|
18
|
+
* const app = express();
|
|
19
|
+
*
|
|
20
|
+
* // Protect entire API — require KYC verified humans
|
|
21
|
+
* app.use(soulprint({ minScore: 60 }));
|
|
22
|
+
*
|
|
23
|
+
* // Protect specific route — require full biometric KYC
|
|
24
|
+
* app.post("/sensitive", soulprint({ require: ["DocumentVerified", "FaceMatch"] }), handler);
|
|
25
|
+
*
|
|
26
|
+
* // Inside a handler — get the verified identity
|
|
27
|
+
* app.get("/me", soulprint({ minScore: 20 }), (req, res) => {
|
|
28
|
+
* const identity = req.soulprint; // SoulprintToken
|
|
29
|
+
* res.json({ nullifier: identity.nullifier, score: identity.score });
|
|
30
|
+
* });
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* Token is read from:
|
|
34
|
+
* - HTTP header: X-Soulprint: <SPT>
|
|
35
|
+
* - Query param: ?spt=<SPT>
|
|
36
|
+
* - Bearer token: Authorization: Bearer <SPT>
|
|
37
|
+
*/
|
|
38
|
+
function soulprint(opts = {}) {
|
|
39
|
+
return function soulprintMiddleware(req, res, next) {
|
|
40
|
+
const spt = extractSPT(req);
|
|
41
|
+
const result = (0, verify_js_1.verifySPT)(spt, opts);
|
|
42
|
+
if (!result.allowed) {
|
|
43
|
+
opts.onRejected?.(result.reason);
|
|
44
|
+
res.status(403).json({
|
|
45
|
+
error: "soulprint_required",
|
|
46
|
+
message: opts.rejectMessage ?? result.reason,
|
|
47
|
+
docs: "https://github.com/manuelariasfz/soulprint",
|
|
48
|
+
required: {
|
|
49
|
+
minScore: opts.minScore ?? 40,
|
|
50
|
+
require: opts.require,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
opts.onVerified?.(result.token);
|
|
56
|
+
// Attach to req for downstream handlers
|
|
57
|
+
req.soulprint = result.token;
|
|
58
|
+
next();
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function extractSPT(req) {
|
|
62
|
+
// 1. Header dedicado
|
|
63
|
+
const header = req.headers?.["x-soulprint"] ?? req.headers?.["X-Soulprint"];
|
|
64
|
+
if (header)
|
|
65
|
+
return header;
|
|
66
|
+
// 2. Authorization: Bearer <SPT>
|
|
67
|
+
const auth = req.headers?.authorization ?? "";
|
|
68
|
+
if (auth.startsWith("Bearer ")) {
|
|
69
|
+
const token = auth.slice(7);
|
|
70
|
+
// Solo si parece un SPT (base64url largo) — no interferir con JWTs normales
|
|
71
|
+
if (token.length > 200)
|
|
72
|
+
return token;
|
|
73
|
+
}
|
|
74
|
+
// 3. Query param: ?spt=...
|
|
75
|
+
if (req.query?.spt)
|
|
76
|
+
return req.query.spt;
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
// ── Fastify Plugin ────────────────────────────────────────────────────────────
|
|
80
|
+
/**
|
|
81
|
+
* soulprintFastify() — Fastify plugin for Soulprint verification.
|
|
82
|
+
*
|
|
83
|
+
* USAGE:
|
|
84
|
+
*
|
|
85
|
+
* ```typescript
|
|
86
|
+
* import Fastify from "fastify";
|
|
87
|
+
* import { soulprintFastify } from "soulprint-express";
|
|
88
|
+
*
|
|
89
|
+
* const fastify = Fastify();
|
|
90
|
+
* await fastify.register(soulprintFastify, { minScore: 60 });
|
|
91
|
+
*
|
|
92
|
+
* fastify.get("/me", async (request) => {
|
|
93
|
+
* const identity = request.soulprint;
|
|
94
|
+
* return { nullifier: identity?.nullifier };
|
|
95
|
+
* });
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
async function soulprintFastify(fastify, opts = {}) {
|
|
99
|
+
fastify.addHook("preHandler", async (request, reply) => {
|
|
100
|
+
const spt = extractSPT(request);
|
|
101
|
+
const result = (0, verify_js_1.verifySPT)(spt, opts);
|
|
102
|
+
if (!result.allowed) {
|
|
103
|
+
opts.onRejected?.(result.reason);
|
|
104
|
+
reply.status(403).send({
|
|
105
|
+
error: "soulprint_required",
|
|
106
|
+
message: opts.rejectMessage ?? result.reason,
|
|
107
|
+
docs: "https://github.com/manuelariasfz/soulprint",
|
|
108
|
+
});
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
opts.onVerified?.(result.token);
|
|
112
|
+
request.soulprint = result.token;
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
var soulprint_core_1 = require("soulprint-core");
|
|
116
|
+
Object.defineProperty(exports, "decodeToken", { enumerable: true, get: function () { return soulprint_core_1.decodeToken; } });
|
package/dist/verify.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SoulprintToken, TrustLevel, CredentialType } from "soulprint-core";
|
|
2
|
+
export interface SoulprintOptions {
|
|
3
|
+
minScore?: number;
|
|
4
|
+
minLevel?: TrustLevel;
|
|
5
|
+
require?: CredentialType | CredentialType[];
|
|
6
|
+
rejectMessage?: string;
|
|
7
|
+
onVerified?: (token: SoulprintToken) => void;
|
|
8
|
+
onRejected?: (reason: string) => void;
|
|
9
|
+
}
|
|
10
|
+
export declare function verifySPT(spt: string | undefined | null, opts?: SoulprintOptions): {
|
|
11
|
+
allowed: boolean;
|
|
12
|
+
token?: SoulprintToken;
|
|
13
|
+
reason?: string;
|
|
14
|
+
};
|
package/dist/verify.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.verifySPT = verifySPT;
|
|
4
|
+
const soulprint_core_1 = require("soulprint-core");
|
|
5
|
+
const LEVEL_SCORES = {
|
|
6
|
+
Unverified: 0, EmailVerified: 10, PhoneVerified: 25, KYCLite: 45, KYCFull: 80,
|
|
7
|
+
};
|
|
8
|
+
function verifySPT(spt, opts = {}) {
|
|
9
|
+
if (!spt) {
|
|
10
|
+
const result = { allowed: false, reason: "No Soulprint token provided" };
|
|
11
|
+
opts.onRejected?.(result.reason);
|
|
12
|
+
return result;
|
|
13
|
+
}
|
|
14
|
+
const token = (0, soulprint_core_1.decodeToken)(spt);
|
|
15
|
+
if (!token) {
|
|
16
|
+
const result = { allowed: false, reason: "Invalid or expired Soulprint token" };
|
|
17
|
+
opts.onRejected?.(result.reason);
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
const minScore = opts.minScore ?? 40;
|
|
21
|
+
if (token.score < minScore) {
|
|
22
|
+
const result = { allowed: false, reason: `Trust score too low: ${token.score} < ${minScore}` };
|
|
23
|
+
opts.onRejected?.(result.reason);
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
if (opts.minLevel) {
|
|
27
|
+
const req = LEVEL_SCORES[opts.minLevel] ?? 0;
|
|
28
|
+
const got = LEVEL_SCORES[token.level] ?? 0;
|
|
29
|
+
if (got < req) {
|
|
30
|
+
const result = { allowed: false, reason: `Trust level too low: ${token.level} < ${opts.minLevel}` };
|
|
31
|
+
opts.onRejected?.(result.reason);
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (opts.require) {
|
|
36
|
+
const required = Array.isArray(opts.require) ? opts.require : [opts.require];
|
|
37
|
+
const missing = required.filter(c => !token.credentials.includes(c));
|
|
38
|
+
if (missing.length > 0) {
|
|
39
|
+
const result = { allowed: false, reason: `Missing credentials: ${missing.join(", ")}` };
|
|
40
|
+
opts.onRejected?.(result.reason);
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
opts.onVerified?.(token);
|
|
45
|
+
return { allowed: true, token };
|
|
46
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "soulprint-express",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Soulprint Express/Fastify middleware — app.use(soulprint({ minScore: 40 }))",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public"
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/manuelariasfz/soulprint",
|
|
17
|
+
"directory": "packages/express"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://github.com/manuelariasfz/soulprint#readme",
|
|
20
|
+
"keywords": [
|
|
21
|
+
"soulprint",
|
|
22
|
+
"express",
|
|
23
|
+
"fastify",
|
|
24
|
+
"middleware",
|
|
25
|
+
"kyc",
|
|
26
|
+
"identity",
|
|
27
|
+
"ai-agents"
|
|
28
|
+
],
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"soulprint-core": "0.1.0"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"express": ">=4.0.0"
|
|
35
|
+
},
|
|
36
|
+
"peerDependenciesMeta": {
|
|
37
|
+
"express": {
|
|
38
|
+
"optional": true
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"typescript": "^5.4.0",
|
|
43
|
+
"@types/node": "^20.0.0",
|
|
44
|
+
"@types/express": "^4.17.0"
|
|
45
|
+
},
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=18.0.0"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "tsc"
|
|
51
|
+
}
|
|
52
|
+
}
|