@nekzus/liop 2.4.0-alpha.7 → 2.4.0-alpha.8
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/NOTICE +19 -0
- package/README.md +36 -17
- package/dist/bin/agent.js +674 -82
- package/dist/bin/agent.js.map +1 -1
- package/dist/bridge.d.ts +2 -2
- package/dist/bridge.js +3 -3
- package/dist/{chunk-T5IUZF47.js → chunk-3L2O2XKG.js} +12 -5
- package/dist/chunk-3L2O2XKG.js.map +1 -0
- package/dist/{chunk-SONUORBT.js → chunk-7BSCUYUE.js} +2 -2
- package/dist/chunk-7BSCUYUE.js.map +1 -0
- package/dist/{chunk-QLCOEP5J.js → chunk-7PITYWOV.js} +2 -2
- package/dist/chunk-7PITYWOV.js.map +1 -0
- package/dist/{chunk-74CISO2I.js → chunk-7RXOIDXP.js} +28 -4
- package/dist/chunk-7RXOIDXP.js.map +1 -0
- package/dist/{chunk-GA3Q2S7O.js → chunk-BOISQ45Z.js} +5 -5
- package/dist/chunk-BOISQ45Z.js.map +1 -0
- package/dist/{chunk-547TYL27.js → chunk-DZ2FQGJD.js} +26 -1423
- package/dist/chunk-DZ2FQGJD.js.map +1 -0
- package/dist/{chunk-PYKRQAER.js → chunk-EG46XMJT.js} +2 -2
- package/dist/chunk-EG46XMJT.js.map +1 -0
- package/dist/chunk-ESRXG36Y.js +115 -0
- package/dist/chunk-ESRXG36Y.js.map +1 -0
- package/dist/chunk-FTF6AMF6.js +3 -0
- package/dist/{chunk-RWRRBYG4.js.map → chunk-FTF6AMF6.js.map} +1 -1
- package/dist/{chunk-72MNYFR6.js → chunk-HA6YZ42O.js} +2 -2
- package/dist/chunk-HA6YZ42O.js.map +1 -0
- package/dist/{chunk-WCCGE4QR.js → chunk-HD2N3IJX.js} +144 -30
- package/dist/chunk-HD2N3IJX.js.map +1 -0
- package/dist/{chunk-OUUTDSOW.js → chunk-IK7CGWAZ.js} +3 -3
- package/dist/chunk-IK7CGWAZ.js.map +1 -0
- package/dist/chunk-L6J72C5X.js +1477 -0
- package/dist/chunk-L6J72C5X.js.map +1 -0
- package/dist/{chunk-U5BZ66VX.js → chunk-PAICJCKJ.js} +60 -175
- package/dist/chunk-PAICJCKJ.js.map +1 -0
- package/dist/{chunk-32ADSAJS.js → chunk-PEN3KFLF.js} +14 -4
- package/dist/chunk-PEN3KFLF.js.map +1 -0
- package/dist/{chunk-CRZBVFDV.js → chunk-T7R5HUFD.js} +225 -66
- package/dist/chunk-T7R5HUFD.js.map +1 -0
- package/dist/{chunk-WSW6YJNY.js → chunk-TKRX6CFI.js} +3 -3
- package/dist/chunk-TKRX6CFI.js.map +1 -0
- package/dist/chunk-UCVP3XAL.js +279 -0
- package/dist/chunk-UCVP3XAL.js.map +1 -0
- package/dist/chunk-VH4K4U45.js +180 -0
- package/dist/chunk-VH4K4U45.js.map +1 -0
- package/dist/{chunk-JIJPZFR2.js → chunk-Y62GORQF.js} +2 -2
- package/dist/chunk-Y62GORQF.js.map +1 -0
- package/dist/chunk-ZP3VVXOI.js +66 -0
- package/dist/chunk-ZP3VVXOI.js.map +1 -0
- package/dist/client.d.ts +2 -2
- package/dist/client.js +11 -8
- package/dist/gateway.d.ts +3 -3
- package/dist/gateway.js +11 -9
- package/dist/{hybrid-CF__0YnC.d.ts → hybrid-CrKB50nh.d.ts} +2 -2
- package/dist/{index-cMV0_yD9.d.ts → index-CX43dvMs.d.ts} +2 -32
- package/dist/{index-BW95kAL4.d.ts → index-DoW2gzBZ.d.ts} +3 -21
- package/dist/index.d.ts +170 -46
- package/dist/index.js +20 -15
- package/dist/index.js.map +1 -1
- package/dist/kyber-CGOA7Q6A.js +3 -0
- package/dist/{kyber-3ULIJSE3.js.map → kyber-CGOA7Q6A.js.map} +1 -1
- package/dist/mesh.d.ts +27 -143
- package/dist/mesh.js +4 -3
- package/dist/node-B0b2vUFS.d.ts +164 -0
- package/dist/protocol/liop_core.proto +3 -0
- package/dist/server.d.ts +2 -2
- package/dist/server.js +7 -6
- package/dist/types.js +1 -1
- package/dist/verifier-HRFXBKT5.js +6 -0
- package/dist/{verifier-3FAKCFNN.js.map → verifier-HRFXBKT5.js.map} +1 -1
- package/dist/workers/logic-execution.js +3 -3
- package/dist/workers/logic-execution.js.map +1 -1
- package/dist/workers/zk-verifier.js +1 -1
- package/dist/workers/zk-verifier.js.map +1 -1
- package/package.json +8 -2
- package/dist/chunk-32ADSAJS.js.map +0 -1
- package/dist/chunk-547TYL27.js.map +0 -1
- package/dist/chunk-72MNYFR6.js.map +0 -1
- package/dist/chunk-74CISO2I.js.map +0 -1
- package/dist/chunk-CRZBVFDV.js.map +0 -1
- package/dist/chunk-GA3Q2S7O.js.map +0 -1
- package/dist/chunk-JIJPZFR2.js.map +0 -1
- package/dist/chunk-OUUTDSOW.js.map +0 -1
- package/dist/chunk-PYKRQAER.js.map +0 -1
- package/dist/chunk-QLCOEP5J.js.map +0 -1
- package/dist/chunk-RWRRBYG4.js +0 -3
- package/dist/chunk-SONUORBT.js.map +0 -1
- package/dist/chunk-T5IUZF47.js.map +0 -1
- package/dist/chunk-U5BZ66VX.js.map +0 -1
- package/dist/chunk-WCCGE4QR.js.map +0 -1
- package/dist/chunk-WSW6YJNY.js.map +0 -1
- package/dist/kyber-3ULIJSE3.js +0 -3
- package/dist/verifier-3FAKCFNN.js +0 -5
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { ml_dsa65 } from '@noble/post-quantum/ml-dsa.js';
|
|
2
|
+
|
|
3
|
+
// src/rpc/crypto/dilithium.ts
|
|
4
|
+
var DILITHIUM65_CONSTANTS = {
|
|
5
|
+
PUBLIC_KEY_BYTES: 1952,
|
|
6
|
+
SECRET_KEY_BYTES: 4032,
|
|
7
|
+
SIGNATURE_BYTES: 3309,
|
|
8
|
+
DEFAULT_CONTEXT: new TextEncoder().encode("LIOP-FIPS204-ML-DSA-65")
|
|
9
|
+
};
|
|
10
|
+
function normalizeMessage(message) {
|
|
11
|
+
if (typeof message === "string") {
|
|
12
|
+
return new TextEncoder().encode(message);
|
|
13
|
+
}
|
|
14
|
+
return message;
|
|
15
|
+
}
|
|
16
|
+
function canonicalizeJson(obj) {
|
|
17
|
+
if (obj === null || typeof obj !== "object") {
|
|
18
|
+
return JSON.stringify(obj);
|
|
19
|
+
}
|
|
20
|
+
if (Array.isArray(obj)) {
|
|
21
|
+
return `[${obj.map(canonicalizeJson).join(",")}]`;
|
|
22
|
+
}
|
|
23
|
+
const sortedKeys = Object.keys(obj).sort();
|
|
24
|
+
const entries = sortedKeys.map(
|
|
25
|
+
(key) => `${JSON.stringify(key)}:${canonicalizeJson(obj[key])}`
|
|
26
|
+
);
|
|
27
|
+
return `{${entries.join(",")}}`;
|
|
28
|
+
}
|
|
29
|
+
var Dilithium65Wrapper = {
|
|
30
|
+
/** Constants */
|
|
31
|
+
PUBLIC_KEY_BYTES: DILITHIUM65_CONSTANTS.PUBLIC_KEY_BYTES,
|
|
32
|
+
SECRET_KEY_BYTES: DILITHIUM65_CONSTANTS.SECRET_KEY_BYTES,
|
|
33
|
+
SIGNATURE_BYTES: DILITHIUM65_CONSTANTS.SIGNATURE_BYTES,
|
|
34
|
+
/**
|
|
35
|
+
* Generates a new ML-DSA-65 (FIPS 204) key pair.
|
|
36
|
+
* Optionally accepts a 32-byte seed for deterministic key generation.
|
|
37
|
+
*/
|
|
38
|
+
generateKeyPair(seed) {
|
|
39
|
+
if (seed && seed.length !== 32) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`ML-DSA-65 seed must be exactly 32 bytes (Received: ${seed.length})`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
const keys = ml_dsa65.keygen(seed);
|
|
45
|
+
return {
|
|
46
|
+
publicKey: keys.publicKey,
|
|
47
|
+
secretKey: keys.secretKey
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
/**
|
|
51
|
+
* Validates and imports a raw ML-DSA-65 public key.
|
|
52
|
+
*/
|
|
53
|
+
importPublicKey(buffer) {
|
|
54
|
+
if (buffer.length !== DILITHIUM65_CONSTANTS.PUBLIC_KEY_BYTES) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
`ML-DSA-65 Public Key must be exactly ${DILITHIUM65_CONSTANTS.PUBLIC_KEY_BYTES} bytes (Received: ${buffer.length})`
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return buffer;
|
|
60
|
+
},
|
|
61
|
+
/**
|
|
62
|
+
* Signs a message using the post-quantum secret key.
|
|
63
|
+
* Supports optional domain separation context (up to 255 bytes).
|
|
64
|
+
*/
|
|
65
|
+
sign(message, secretKey, context) {
|
|
66
|
+
if (secretKey.length !== DILITHIUM65_CONSTANTS.SECRET_KEY_BYTES) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
`ML-DSA-65 Secret Key must be exactly ${DILITHIUM65_CONSTANTS.SECRET_KEY_BYTES} bytes (Received: ${secretKey.length})`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
const msgBytes = normalizeMessage(message);
|
|
72
|
+
const ctx = context ?? DILITHIUM65_CONSTANTS.DEFAULT_CONTEXT;
|
|
73
|
+
return ml_dsa65.sign(msgBytes, secretKey, { context: ctx });
|
|
74
|
+
},
|
|
75
|
+
/**
|
|
76
|
+
* Verifies an ML-DSA-65 post-quantum digital signature.
|
|
77
|
+
*/
|
|
78
|
+
verify(signature, message, publicKey, context) {
|
|
79
|
+
if (signature.length !== DILITHIUM65_CONSTANTS.SIGNATURE_BYTES) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
if (publicKey.length !== DILITHIUM65_CONSTANTS.PUBLIC_KEY_BYTES) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
const msgBytes = normalizeMessage(message);
|
|
87
|
+
const ctx = context ?? DILITHIUM65_CONSTANTS.DEFAULT_CONTEXT;
|
|
88
|
+
return ml_dsa65.verify(signature, msgBytes, publicKey, { context: ctx });
|
|
89
|
+
} catch {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
/**
|
|
94
|
+
* Signs a structured manifest (LiopManifest) using canonical JSON serialization.
|
|
95
|
+
* Returns base64-encoded signature and public key for transport over gRPC/MCP.
|
|
96
|
+
*/
|
|
97
|
+
signManifest(manifest, secretKey, publicKey) {
|
|
98
|
+
const { pqcSignature: _sig, pqcPublicKey: _pub, ...unsigned } = manifest;
|
|
99
|
+
const canonicalStr = canonicalizeJson(unsigned);
|
|
100
|
+
const sig = this.sign(canonicalStr, secretKey);
|
|
101
|
+
return {
|
|
102
|
+
signature: Buffer.from(sig).toString("base64"),
|
|
103
|
+
publicKey: Buffer.from(publicKey).toString("base64")
|
|
104
|
+
};
|
|
105
|
+
},
|
|
106
|
+
/**
|
|
107
|
+
* Verifies the post-quantum signature of a structured manifest.
|
|
108
|
+
*/
|
|
109
|
+
verifyManifest(manifest, signatureBase64, publicKeyBase64) {
|
|
110
|
+
try {
|
|
111
|
+
const sig = Buffer.from(signatureBase64, "base64");
|
|
112
|
+
const pub = Buffer.from(publicKeyBase64, "base64");
|
|
113
|
+
const { pqcSignature: _sig, pqcPublicKey: _pub, ...unsigned } = manifest;
|
|
114
|
+
const canonicalStr = canonicalizeJson(unsigned);
|
|
115
|
+
return this.verify(sig, canonicalStr, pub);
|
|
116
|
+
} catch {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
// src/security/rbac.ts
|
|
123
|
+
var SCOPE_MAP = {
|
|
124
|
+
// Protocol lifecycle — unauthenticated (MCP spec compliance)
|
|
125
|
+
initialize: [],
|
|
126
|
+
"notifications/initialized": [],
|
|
127
|
+
"notifications/cancelled": [],
|
|
128
|
+
ping: [],
|
|
129
|
+
"server/discover": [],
|
|
130
|
+
"subscriptions/listen": [],
|
|
131
|
+
// Tool operations — require explicit authorization
|
|
132
|
+
"tools/list": ["liop:tools:list"],
|
|
133
|
+
"tools/call": ["liop:tools:call"],
|
|
134
|
+
// Resource operations — read-level access
|
|
135
|
+
"resources/list": ["liop:resources:read"],
|
|
136
|
+
"resources/read": ["liop:resources:read"],
|
|
137
|
+
"resources/templates/list": ["liop:resources:read"],
|
|
138
|
+
// Prompt/schema operations — schema-level access
|
|
139
|
+
"prompts/list": ["liop:schema:read"],
|
|
140
|
+
"prompts/get": ["liop:schema:read"]
|
|
141
|
+
};
|
|
142
|
+
function authorizeRequest(method, auth, additionalScopes) {
|
|
143
|
+
const methodScopes = SCOPE_MAP[method];
|
|
144
|
+
if (methodScopes !== void 0 && methodScopes.length === 0) {
|
|
145
|
+
return { allowed: true };
|
|
146
|
+
}
|
|
147
|
+
if (!auth) {
|
|
148
|
+
return {
|
|
149
|
+
allowed: false,
|
|
150
|
+
reason: `Authentication required for method: ${method}`
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
const needed = [...methodScopes ?? [], ...additionalScopes ?? []];
|
|
154
|
+
if (needed.length === 0) {
|
|
155
|
+
return {
|
|
156
|
+
allowed: false,
|
|
157
|
+
reason: `Unknown method: ${method}. Access denied (fail-closed).`
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
const clientScopes = new Set(auth.scopes);
|
|
161
|
+
const missing = needed.filter((s) => !clientScopes.has(s));
|
|
162
|
+
if (missing.length > 0) {
|
|
163
|
+
return {
|
|
164
|
+
allowed: false,
|
|
165
|
+
reason: `Insufficient scopes for ${method}. Missing: ${missing.join(", ")}`
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
return { allowed: true };
|
|
169
|
+
}
|
|
170
|
+
var LIOP_SCOPES = [
|
|
171
|
+
"liop:tools:list",
|
|
172
|
+
"liop:tools:call",
|
|
173
|
+
"liop:resources:read",
|
|
174
|
+
"liop:schema:read",
|
|
175
|
+
"liop:mesh:query"
|
|
176
|
+
];
|
|
177
|
+
|
|
178
|
+
export { DILITHIUM65_CONSTANTS, Dilithium65Wrapper, LIOP_SCOPES, authorizeRequest };
|
|
179
|
+
//# sourceMappingURL=chunk-VH4K4U45.js.map
|
|
180
|
+
//# sourceMappingURL=chunk-VH4K4U45.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/rpc/crypto/dilithium.ts","../src/security/rbac.ts"],"names":[],"mappings":"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","file":"chunk-VH4K4U45.js","sourcesContent":["// Copyright 2026 Nekzus Solutions and contributors\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * LIOP Post-Quantum Digital Signature Wrapper\n * Implements ML-DSA-65 (CRYSTALS-Dilithium, NIST FIPS 204) for quantum-resistant\n * manifest attestation, node revocation receipts, and cryptographic integrity.\n *\n * Characteristics:\n * - Security Category: NIST Level 3 (~AES-192 equivalent quantum resistance)\n * - Public Key Length: 1952 bytes\n * - Secret Key Length: 4032 bytes\n * - Signature Length: 3309 bytes\n * - Implementation: Pure TypeScript/JS via @noble/post-quantum\n */\n\nimport { ml_dsa65 } from \"@noble/post-quantum/ml-dsa.js\";\n\nexport const DILITHIUM65_CONSTANTS = {\n\tPUBLIC_KEY_BYTES: 1952,\n\tSECRET_KEY_BYTES: 4032,\n\tSIGNATURE_BYTES: 3309,\n\tDEFAULT_CONTEXT: new TextEncoder().encode(\"LIOP-FIPS204-ML-DSA-65\"),\n} as const;\n\n/**\n * Deterministically normalizes a message into a Uint8Array.\n */\nfunction normalizeMessage(message: Uint8Array | string): Uint8Array {\n\tif (typeof message === \"string\") {\n\t\treturn new TextEncoder().encode(message);\n\t}\n\treturn message;\n}\n\n/**\n * Deterministic canonical JSON serializer to ensure stable cryptographic hashing\n * regardless of key ordering in JavaScript objects.\n */\nfunction canonicalizeJson(obj: unknown): string {\n\tif (obj === null || typeof obj !== \"object\") {\n\t\treturn JSON.stringify(obj);\n\t}\n\tif (Array.isArray(obj)) {\n\t\treturn `[${obj.map(canonicalizeJson).join(\",\")}]`;\n\t}\n\tconst sortedKeys = Object.keys(obj as Record<string, unknown>).sort();\n\tconst entries = sortedKeys.map(\n\t\t(key) =>\n\t\t\t`${JSON.stringify(key)}:${canonicalizeJson((obj as Record<string, unknown>)[key])}`,\n\t);\n\treturn `{${entries.join(\",\")}}`;\n}\n\nexport const Dilithium65Wrapper = {\n\t/** Constants */\n\tPUBLIC_KEY_BYTES: DILITHIUM65_CONSTANTS.PUBLIC_KEY_BYTES,\n\tSECRET_KEY_BYTES: DILITHIUM65_CONSTANTS.SECRET_KEY_BYTES,\n\tSIGNATURE_BYTES: DILITHIUM65_CONSTANTS.SIGNATURE_BYTES,\n\n\t/**\n\t * Generates a new ML-DSA-65 (FIPS 204) key pair.\n\t * Optionally accepts a 32-byte seed for deterministic key generation.\n\t */\n\tgenerateKeyPair(seed?: Uint8Array): {\n\t\tpublicKey: Uint8Array;\n\t\tsecretKey: Uint8Array;\n\t} {\n\t\tif (seed && seed.length !== 32) {\n\t\t\tthrow new Error(\n\t\t\t\t`ML-DSA-65 seed must be exactly 32 bytes (Received: ${seed.length})`,\n\t\t\t);\n\t\t}\n\t\tconst keys = ml_dsa65.keygen(seed);\n\t\treturn {\n\t\t\tpublicKey: keys.publicKey,\n\t\t\tsecretKey: keys.secretKey,\n\t\t};\n\t},\n\n\t/**\n\t * Validates and imports a raw ML-DSA-65 public key.\n\t */\n\timportPublicKey(buffer: Uint8Array): Uint8Array {\n\t\tif (buffer.length !== DILITHIUM65_CONSTANTS.PUBLIC_KEY_BYTES) {\n\t\t\tthrow new Error(\n\t\t\t\t`ML-DSA-65 Public Key must be exactly ${DILITHIUM65_CONSTANTS.PUBLIC_KEY_BYTES} bytes (Received: ${buffer.length})`,\n\t\t\t);\n\t\t}\n\t\treturn buffer;\n\t},\n\n\t/**\n\t * Signs a message using the post-quantum secret key.\n\t * Supports optional domain separation context (up to 255 bytes).\n\t */\n\tsign(\n\t\tmessage: Uint8Array | string,\n\t\tsecretKey: Uint8Array,\n\t\tcontext?: Uint8Array,\n\t): Uint8Array {\n\t\tif (secretKey.length !== DILITHIUM65_CONSTANTS.SECRET_KEY_BYTES) {\n\t\t\tthrow new Error(\n\t\t\t\t`ML-DSA-65 Secret Key must be exactly ${DILITHIUM65_CONSTANTS.SECRET_KEY_BYTES} bytes (Received: ${secretKey.length})`,\n\t\t\t);\n\t\t}\n\t\tconst msgBytes = normalizeMessage(message);\n\t\tconst ctx = context ?? DILITHIUM65_CONSTANTS.DEFAULT_CONTEXT;\n\t\treturn ml_dsa65.sign(msgBytes, secretKey, { context: ctx });\n\t},\n\n\t/**\n\t * Verifies an ML-DSA-65 post-quantum digital signature.\n\t */\n\tverify(\n\t\tsignature: Uint8Array,\n\t\tmessage: Uint8Array | string,\n\t\tpublicKey: Uint8Array,\n\t\tcontext?: Uint8Array,\n\t): boolean {\n\t\tif (signature.length !== DILITHIUM65_CONSTANTS.SIGNATURE_BYTES) {\n\t\t\treturn false;\n\t\t}\n\t\tif (publicKey.length !== DILITHIUM65_CONSTANTS.PUBLIC_KEY_BYTES) {\n\t\t\treturn false;\n\t\t}\n\t\ttry {\n\t\t\tconst msgBytes = normalizeMessage(message);\n\t\t\tconst ctx = context ?? DILITHIUM65_CONSTANTS.DEFAULT_CONTEXT;\n\t\t\treturn ml_dsa65.verify(signature, msgBytes, publicKey, { context: ctx });\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t},\n\n\t/**\n\t * Signs a structured manifest (LiopManifest) using canonical JSON serialization.\n\t * Returns base64-encoded signature and public key for transport over gRPC/MCP.\n\t */\n\tsignManifest(\n\t\tmanifest: Record<string, unknown>,\n\t\tsecretKey: Uint8Array,\n\t\tpublicKey: Uint8Array,\n\t): { signature: string; publicKey: string } {\n\t\tconst { pqcSignature: _sig, pqcPublicKey: _pub, ...unsigned } = manifest;\n\t\tconst canonicalStr = canonicalizeJson(unsigned);\n\t\tconst sig = this.sign(canonicalStr, secretKey);\n\t\treturn {\n\t\t\tsignature: Buffer.from(sig).toString(\"base64\"),\n\t\t\tpublicKey: Buffer.from(publicKey).toString(\"base64\"),\n\t\t};\n\t},\n\n\t/**\n\t * Verifies the post-quantum signature of a structured manifest.\n\t */\n\tverifyManifest(\n\t\tmanifest: Record<string, unknown>,\n\t\tsignatureBase64: string,\n\t\tpublicKeyBase64: string,\n\t): boolean {\n\t\ttry {\n\t\t\tconst sig = Buffer.from(signatureBase64, \"base64\");\n\t\t\tconst pub = Buffer.from(publicKeyBase64, \"base64\");\n\t\t\tconst { pqcSignature: _sig, pqcPublicKey: _pub, ...unsigned } = manifest;\n\t\t\tconst canonicalStr = canonicalizeJson(unsigned);\n\t\t\treturn this.verify(sig, canonicalStr, pub);\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t},\n};\n","// Copyright 2026 Nekzus Solutions and contributors\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * LIOP RBAC Engine — Scope-Based Authorization\n *\n * Maps MCP JSON-RPC methods to required LIOP OAuth scopes.\n * Enforces least-privilege access at the router level before\n * any tool execution or resource read occurs.\n *\n * Standards: NIST SP 800-207 §4.3 (least privilege), OWASP LLM06 (Excessive Agency),\n * OWASP API-A01 (Broken Access Control)\n */\n\nimport type { AuthInfo } from \"./jwt-validator.js\";\n\n/**\n * Maps MCP JSON-RPC methods to the LIOP scopes required to invoke them.\n * Empty array = no authentication required (public endpoints).\n */\nconst SCOPE_MAP: Readonly<Record<string, readonly string[]>> = {\n\t// Protocol lifecycle — unauthenticated (MCP spec compliance)\n\tinitialize: [],\n\t\"notifications/initialized\": [],\n\t\"notifications/cancelled\": [],\n\tping: [],\n\t\"server/discover\": [],\n\t\"subscriptions/listen\": [],\n\n\t// Tool operations — require explicit authorization\n\t\"tools/list\": [\"liop:tools:list\"],\n\t\"tools/call\": [\"liop:tools:call\"],\n\n\t// Resource operations — read-level access\n\t\"resources/list\": [\"liop:resources:read\"],\n\t\"resources/read\": [\"liop:resources:read\"],\n\t\"resources/templates/list\": [\"liop:resources:read\"],\n\n\t// Prompt/schema operations — schema-level access\n\t\"prompts/list\": [\"liop:schema:read\"],\n\t\"prompts/get\": [\"liop:schema:read\"],\n};\n\n/**\n * Authorization result with optional denial reason for audit logging.\n */\nexport interface AuthorizationResult {\n\tallowed: boolean;\n\treason?: string;\n}\n\n/**\n * Evaluates whether a request is authorized based on JWT scopes.\n *\n * Decision logic:\n * 1. Methods with no required scopes (initialize, ping) → always allowed.\n * 2. Methods with required scopes but no auth → denied.\n * 3. Methods with required scopes → all scopes must be present in the JWT.\n * 4. Unknown methods with no auth → denied (fail-closed per NIST SP 800-207).\n *\n * @param method - MCP JSON-RPC method name (e.g., \"tools/call\")\n * @param auth - Validated JWT context, or null if unauthenticated\n * @param additionalScopes - Extra scopes required by specific node configuration\n */\nexport function authorizeRequest(\n\tmethod: string,\n\tauth: AuthInfo | null,\n\tadditionalScopes?: readonly string[],\n): AuthorizationResult {\n\tconst methodScopes = SCOPE_MAP[method];\n\n\t// Methods explicitly marked as public (empty scope array) pass freely\n\tif (methodScopes !== undefined && methodScopes.length === 0) {\n\t\treturn { allowed: true };\n\t}\n\n\t// If no auth context and method requires scopes → deny\n\tif (!auth) {\n\t\treturn {\n\t\t\tallowed: false,\n\t\t\treason: `Authentication required for method: ${method}`,\n\t\t};\n\t}\n\n\t// Merge method-level scopes with node-level additional scopes\n\tconst needed = [...(methodScopes ?? []), ...(additionalScopes ?? [])];\n\n\t// If no scopes needed (unknown method, no additional) → fail-closed\n\tif (needed.length === 0) {\n\t\treturn {\n\t\t\tallowed: false,\n\t\t\treason: `Unknown method: ${method}. Access denied (fail-closed).`,\n\t\t};\n\t}\n\n\t// Verify all required scopes are present in the JWT\n\tconst clientScopes = new Set(auth.scopes);\n\tconst missing = needed.filter((s) => !clientScopes.has(s));\n\n\tif (missing.length > 0) {\n\t\treturn {\n\t\t\tallowed: false,\n\t\t\treason: `Insufficient scopes for ${method}. Missing: ${missing.join(\", \")}`,\n\t\t};\n\t}\n\n\treturn { allowed: true };\n}\n\n/**\n * All LIOP OAuth scopes supported by the protocol.\n * Used for PRM metadata and client registration.\n */\nexport const LIOP_SCOPES = [\n\t\"liop:tools:list\",\n\t\"liop:tools:call\",\n\t\"liop:resources:read\",\n\t\"liop:schema:read\",\n\t\"liop:mesh:query\",\n] as const;\n\nexport type LiopScope = (typeof LIOP_SCOPES)[number];\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server/output-sanitizer.ts"],"names":[],"mappings":";AAkBA,IAAM,cAAA,GAAkD;AAAA,EACvD,gBAAA,EAAkB,CAAA;AAAA,EAClB,gBAAA,EAAkB;AACnB,CAAA;AASO,SAAS,cAAA,CACf,QACA,MAAA,EACU;AACV,EAAA,MAAM,MAAA,GAAS,EAAE,GAAG,cAAA,EAAgB,GAAG,MAAA,EAAO;AAC9C,EAAA,MAAM,IAAA,uBAAW,OAAA,EAAgB;AAEjC,EAAA,SAAS,KAAK,IAAA,EAAwB;AACrC,IAAA,IAAI,IAAA,KAAS,IAAA,IAAQ,IAAA,KAAS,MAAA,EAAW;AACxC,MAAA,OAAO,IAAA;AAAA,IACR;AAEA,IAAA,IAAI,OAAO,SAAS,QAAA,EAAU;AAC7B,MAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,IAAI,CAAA,EAAG;AAC3B,QAAA,OAAO,IAAA;AAAA,MACR;AAEA,MAAA,IAAI,KAAA,GAAQ,IAAA;AAGZ,MAAA,IAAI,MAAA,CAAO,gBAAA,IAAoB,KAAA,GAAQ,CAAA,EAAG;AACzC,QAAA,KAAA,GAAQ,CAAA;AAAA,MACT;AAGA,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,gBAAA;AAC5B,MAAA,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,KAAA,GAAQ,MAAM,CAAA,GAAI,MAAA;AAErC,MAAA,OAAO,KAAA;AAAA,IACR;AAEA,IAAA,IAAI,OAAO,IAAA,KAAS,QAAA,IAAY,OAAO,SAAS,SAAA,EAAW;AAC1D,MAAA,OAAO,IAAA;AAAA,IACR;AAEA,IAAA,IAAI,OAAO,SAAS,QAAA,EAAU;AAE7B,MAAA,IAAI,IAAA,CAAK,GAAA,CAAI,IAAc,CAAA,EAAG;AAC7B,QAAA,OAAO,IAAA;AAAA,MACR;AACA,MAAA,IAAA,CAAK,IAAI,IAAc,CAAA;AAEvB,MAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,EAAG;AACxB,QAAA,OAAO,KAAK,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,MACrC;AAEA,MAAA,MAAM,SAAkC,EAAC;AACzC,MAAA,KAAA,MAAW,CAAC,GAAA,EAAK,GAAG,CAAA,IAAK,MAAA,CAAO,OAAA;AAAA,QAC/B;AAAA,OACD,EAAG;AACF,QAAA,MAAA,CAAO,GAAG,CAAA,GAAI,IAAA,CAAK,GAAG,CAAA;AAAA,MACvB;AACA,MAAA,OAAO,MAAA;AAAA,IACR;AAEA,IAAA,OAAO,IAAA;AAAA,EACR;AAEA,EAAA,OAAO,KAAK,MAAM,CAAA;AACnB","file":"chunk-Y62GORQF.js","sourcesContent":["// Copyright 2026 Nekzus Solutions and contributors\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * LIOP Egress Shield Output Sanitizer (NIST SP 800-226 and OWASP DLP 2025 compliant)\n * Recursively sanitizes execution outputs by rounding floating-point numbers\n * and clamping negative values to zero floor where appropriate.\n *\n * Implements absolute immutability, returning a fresh copy of the data.\n */\n\nexport interface OutputSanitizerConfig {\n\t/** Maximum decimal places for floating-point values (default: 4) */\n\tmaxDecimalPlaces?: number;\n\t/** Clamp negative values to zero floor (default: true) */\n\tclampNonNegative?: boolean;\n}\n\nconst DEFAULT_CONFIG: Required<OutputSanitizerConfig> = {\n\tmaxDecimalPlaces: 4,\n\tclampNonNegative: true,\n};\n\n/**\n * Recursively walks a JSON-like tree, rounding floats and clamping negative values.\n *\n * @param output - The raw or DP-modified output object/value to sanitize\n * @param config - Sanitization parameters (rounding depth, negative clamping)\n * @returns A sanitized deep copy of the output\n */\nexport function sanitizeOutput(\n\toutput: unknown,\n\tconfig?: OutputSanitizerConfig,\n): unknown {\n\tconst merged = { ...DEFAULT_CONFIG, ...config };\n\tconst seen = new WeakSet<object>();\n\n\tfunction walk(node: unknown): unknown {\n\t\tif (node === null || node === undefined) {\n\t\t\treturn node;\n\t\t}\n\n\t\tif (typeof node === \"number\") {\n\t\t\tif (!Number.isFinite(node)) {\n\t\t\t\treturn node;\n\t\t\t}\n\n\t\t\tlet value = node;\n\n\t\t\t// 1. Clamp negative values to 0 if configured\n\t\t\tif (merged.clampNonNegative && value < 0) {\n\t\t\t\tvalue = 0;\n\t\t\t}\n\n\t\t\t// 2. Round to maximum decimal places\n\t\t\tconst factor = 10 ** merged.maxDecimalPlaces;\n\t\t\tvalue = Math.round(value * factor) / factor;\n\n\t\t\treturn value;\n\t\t}\n\n\t\tif (typeof node === \"string\" || typeof node === \"boolean\") {\n\t\t\treturn node;\n\t\t}\n\n\t\tif (typeof node === \"object\") {\n\t\t\t// Circular reference protection\n\t\t\tif (seen.has(node as object)) {\n\t\t\t\treturn node;\n\t\t\t}\n\t\t\tseen.add(node as object);\n\n\t\t\tif (Array.isArray(node)) {\n\t\t\t\treturn node.map((item) => walk(item));\n\t\t\t}\n\n\t\t\tconst result: Record<string, unknown> = {};\n\t\t\tfor (const [key, val] of Object.entries(\n\t\t\t\tnode as Record<string, unknown>,\n\t\t\t)) {\n\t\t\t\tresult[key] = walk(val);\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\treturn node;\n\t}\n\n\treturn walk(output);\n}\n"]}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
import { mkdir, writeFile, readFile } from 'fs/promises';
|
|
3
|
+
import { dirname } from 'path';
|
|
4
|
+
import { generateKey } from '@libp2p/pnet';
|
|
5
|
+
|
|
6
|
+
// src/mesh/swarm-key.ts
|
|
7
|
+
var SWARM_KEY_BYTE_LENGTH = 95;
|
|
8
|
+
function createSwarmKey() {
|
|
9
|
+
const psk = new Uint8Array(SWARM_KEY_BYTE_LENGTH);
|
|
10
|
+
generateKey(psk);
|
|
11
|
+
return psk;
|
|
12
|
+
}
|
|
13
|
+
function serializeSwarmKey(psk) {
|
|
14
|
+
if (psk.length !== SWARM_KEY_BYTE_LENGTH) {
|
|
15
|
+
throw new Error(
|
|
16
|
+
`Invalid Swarm Key length: expected ${SWARM_KEY_BYTE_LENGTH} bytes, got ${psk.length}`
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
return Buffer.from(psk).toString("base64");
|
|
20
|
+
}
|
|
21
|
+
function deserializeSwarmKey(base64Str) {
|
|
22
|
+
const trimmed = base64Str.trim();
|
|
23
|
+
const buf = Buffer.from(trimmed, "base64");
|
|
24
|
+
if (buf.length !== SWARM_KEY_BYTE_LENGTH) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`Invalid deserialized Swarm Key: expected ${SWARM_KEY_BYTE_LENGTH} bytes, got ${buf.length}`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
30
|
+
}
|
|
31
|
+
function parseSwarmKey(rawText) {
|
|
32
|
+
const trimmed = rawText.trim();
|
|
33
|
+
if (trimmed.startsWith("/key/swarm/psk/")) {
|
|
34
|
+
const normalized = trimmed.replace(/\r\n/g, "\n").trimEnd();
|
|
35
|
+
const bytes = new TextEncoder().encode(normalized);
|
|
36
|
+
if (bytes.length === SWARM_KEY_BYTE_LENGTH) {
|
|
37
|
+
return bytes;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return deserializeSwarmKey(trimmed);
|
|
41
|
+
}
|
|
42
|
+
async function saveSwarmKey(psk, filePath) {
|
|
43
|
+
if (psk.length !== SWARM_KEY_BYTE_LENGTH) {
|
|
44
|
+
throw new Error(
|
|
45
|
+
`Cannot save invalid Swarm Key: expected ${SWARM_KEY_BYTE_LENGTH} bytes, got ${psk.length}`
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
await mkdir(dirname(filePath), { recursive: true });
|
|
49
|
+
await writeFile(filePath, psk);
|
|
50
|
+
}
|
|
51
|
+
async function loadSwarmKey(filePath) {
|
|
52
|
+
const fileBuffer = await readFile(filePath);
|
|
53
|
+
if (fileBuffer.length === SWARM_KEY_BYTE_LENGTH) {
|
|
54
|
+
return new Uint8Array(
|
|
55
|
+
fileBuffer.buffer,
|
|
56
|
+
fileBuffer.byteOffset,
|
|
57
|
+
fileBuffer.byteLength
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
const text = fileBuffer.toString("utf-8");
|
|
61
|
+
return parseSwarmKey(text);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export { SWARM_KEY_BYTE_LENGTH, createSwarmKey, deserializeSwarmKey, loadSwarmKey, parseSwarmKey, saveSwarmKey, serializeSwarmKey };
|
|
65
|
+
//# sourceMappingURL=chunk-ZP3VVXOI.js.map
|
|
66
|
+
//# sourceMappingURL=chunk-ZP3VVXOI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mesh/swarm-key.ts"],"names":[],"mappings":";;;;;;AAQO,IAAM,qBAAA,GAAwB;AAM9B,SAAS,cAAA,GAA6B;AAC5C,EAAA,MAAM,GAAA,GAAM,IAAI,UAAA,CAAW,qBAAqB,CAAA;AAChD,EAAA,WAAA,CAAY,GAAG,CAAA;AACf,EAAA,OAAO,GAAA;AACR;AAKO,SAAS,kBAAkB,GAAA,EAAyB;AAC1D,EAAA,IAAI,GAAA,CAAI,WAAW,qBAAA,EAAuB;AACzC,IAAA,MAAM,IAAI,KAAA;AAAA,MACT,CAAA,mCAAA,EAAsC,qBAAqB,CAAA,YAAA,EAAe,GAAA,CAAI,MAAM,CAAA;AAAA,KACrF;AAAA,EACD;AACA,EAAA,OAAO,MAAA,CAAO,IAAA,CAAK,GAAG,CAAA,CAAE,SAAS,QAAQ,CAAA;AAC1C;AAKO,SAAS,oBAAoB,SAAA,EAA+B;AAClE,EAAA,MAAM,OAAA,GAAU,UAAU,IAAA,EAAK;AAC/B,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,IAAA,CAAK,OAAA,EAAS,QAAQ,CAAA;AACzC,EAAA,IAAI,GAAA,CAAI,WAAW,qBAAA,EAAuB;AACzC,IAAA,MAAM,IAAI,KAAA;AAAA,MACT,CAAA,yCAAA,EAA4C,qBAAqB,CAAA,YAAA,EAAe,GAAA,CAAI,MAAM,CAAA;AAAA,KAC3F;AAAA,EACD;AACA,EAAA,OAAO,IAAI,UAAA,CAAW,GAAA,CAAI,QAAQ,GAAA,CAAI,UAAA,EAAY,IAAI,UAAU,CAAA;AACjE;AAMO,SAAS,cAAc,OAAA,EAA6B;AAC1D,EAAA,MAAM,OAAA,GAAU,QAAQ,IAAA,EAAK;AAE7B,EAAA,IAAI,OAAA,CAAQ,UAAA,CAAW,iBAAiB,CAAA,EAAG;AAC1C,IAAA,MAAM,aAAa,OAAA,CAAQ,OAAA,CAAQ,OAAA,EAAS,IAAI,EAAE,OAAA,EAAQ;AAC1D,IAAA,MAAM,KAAA,GAAQ,IAAI,WAAA,EAAY,CAAE,OAAO,UAAU,CAAA;AACjD,IAAA,IAAI,KAAA,CAAM,WAAW,qBAAA,EAAuB;AAC3C,MAAA,OAAO,KAAA;AAAA,IACR;AAAA,EACD;AAEA,EAAA,OAAO,oBAAoB,OAAO,CAAA;AACnC;AAKA,eAAsB,YAAA,CACrB,KACA,QAAA,EACgB;AAChB,EAAA,IAAI,GAAA,CAAI,WAAW,qBAAA,EAAuB;AACzC,IAAA,MAAM,IAAI,KAAA;AAAA,MACT,CAAA,wCAAA,EAA2C,qBAAqB,CAAA,YAAA,EAAe,GAAA,CAAI,MAAM,CAAA;AAAA,KAC1F;AAAA,EACD;AACA,EAAA,MAAM,MAAM,OAAA,CAAQ,QAAQ,GAAG,EAAE,SAAA,EAAW,MAAM,CAAA;AAClD,EAAA,MAAM,SAAA,CAAU,UAAU,GAAG,CAAA;AAC9B;AAMA,eAAsB,aAAa,QAAA,EAAuC;AACzE,EAAA,MAAM,UAAA,GAAa,MAAM,QAAA,CAAS,QAAQ,CAAA;AAC1C,EAAA,IAAI,UAAA,CAAW,WAAW,qBAAA,EAAuB;AAChD,IAAA,OAAO,IAAI,UAAA;AAAA,MACV,UAAA,CAAW,MAAA;AAAA,MACX,UAAA,CAAW,UAAA;AAAA,MACX,UAAA,CAAW;AAAA,KACZ;AAAA,EACD;AACA,EAAA,MAAM,IAAA,GAAO,UAAA,CAAW,QAAA,CAAS,OAAO,CAAA;AACxC,EAAA,OAAO,cAAc,IAAI,CAAA;AAC1B","file":"chunk-ZP3VVXOI.js","sourcesContent":["// Copyright 2026 Nekzus Solutions and contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport { Buffer } from \"node:buffer\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { generateKey } from \"@libp2p/pnet\";\n\nexport const SWARM_KEY_BYTE_LENGTH = 95;\n\n/**\n * Creates a freshly generated 95-byte Pre-Shared Key (PSK) for libp2p Private Networks (pnet).\n * Follows the canonical format `/key/swarm/psk/1.0.0/\\n/base16/\\n<hex>\\n`.\n */\nexport function createSwarmKey(): Uint8Array {\n\tconst psk = new Uint8Array(SWARM_KEY_BYTE_LENGTH);\n\tgenerateKey(psk);\n\treturn psk;\n}\n\n/**\n * Serializes a 95-byte PSK into a Base64 string for safe environment variable passing or JSON config.\n */\nexport function serializeSwarmKey(psk: Uint8Array): string {\n\tif (psk.length !== SWARM_KEY_BYTE_LENGTH) {\n\t\tthrow new Error(\n\t\t\t`Invalid Swarm Key length: expected ${SWARM_KEY_BYTE_LENGTH} bytes, got ${psk.length}`,\n\t\t);\n\t}\n\treturn Buffer.from(psk).toString(\"base64\");\n}\n\n/**\n * Deserializes a Base64-encoded string into a 95-byte PSK Uint8Array.\n */\nexport function deserializeSwarmKey(base64Str: string): Uint8Array {\n\tconst trimmed = base64Str.trim();\n\tconst buf = Buffer.from(trimmed, \"base64\");\n\tif (buf.length !== SWARM_KEY_BYTE_LENGTH) {\n\t\tthrow new Error(\n\t\t\t`Invalid deserialized Swarm Key: expected ${SWARM_KEY_BYTE_LENGTH} bytes, got ${buf.length}`,\n\t\t);\n\t}\n\treturn new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);\n}\n\n/**\n * Parses raw text format PSK or Base64 string into a 95-byte PSK Uint8Array.\n * Allows loading either the canonical multiline text (`/key/swarm/psk/1.0.0/...`) or Base64.\n */\nexport function parseSwarmKey(rawText: string): Uint8Array {\n\tconst trimmed = rawText.trim();\n\t// Check if this is canonical raw text format\n\tif (trimmed.startsWith(\"/key/swarm/psk/\")) {\n\t\tconst normalized = trimmed.replace(/\\r\\n/g, \"\\n\").trimEnd();\n\t\tconst bytes = new TextEncoder().encode(normalized);\n\t\tif (bytes.length === SWARM_KEY_BYTE_LENGTH) {\n\t\t\treturn bytes;\n\t\t}\n\t}\n\t// Fallback to Base64 deserialization\n\treturn deserializeSwarmKey(trimmed);\n}\n\n/**\n * Saves a 95-byte Swarm Key to a file on disk (written as canonical text).\n */\nexport async function saveSwarmKey(\n\tpsk: Uint8Array,\n\tfilePath: string,\n): Promise<void> {\n\tif (psk.length !== SWARM_KEY_BYTE_LENGTH) {\n\t\tthrow new Error(\n\t\t\t`Cannot save invalid Swarm Key: expected ${SWARM_KEY_BYTE_LENGTH} bytes, got ${psk.length}`,\n\t\t);\n\t}\n\tawait mkdir(dirname(filePath), { recursive: true });\n\tawait writeFile(filePath, psk);\n}\n\n/**\n * Loads a 95-byte Swarm Key from a file on disk.\n * Supports both raw binary/canonical format and Base64-encoded text.\n */\nexport async function loadSwarmKey(filePath: string): Promise<Uint8Array> {\n\tconst fileBuffer = await readFile(filePath);\n\tif (fileBuffer.length === SWARM_KEY_BYTE_LENGTH) {\n\t\treturn new Uint8Array(\n\t\t\tfileBuffer.buffer,\n\t\t\tfileBuffer.byteOffset,\n\t\t\tfileBuffer.byteLength,\n\t\t);\n\t}\n\tconst text = fileBuffer.toString(\"utf-8\");\n\treturn parseSwarmKey(text);\n}\n"]}
|
package/dist/client.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import './verifier-COnid_dg.js';
|
|
2
|
-
import './
|
|
3
|
-
export { c as LiopClient } from './index-
|
|
2
|
+
import './node-B0b2vUFS.js';
|
|
3
|
+
export { c as LiopClient } from './index-CX43dvMs.js';
|
|
4
4
|
import './types-lJIxBlWF.js';
|
|
5
5
|
import 'node:events';
|
|
6
6
|
import 'zod';
|
package/dist/client.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
export { LiopClient } from './chunk-
|
|
2
|
-
import './chunk-
|
|
3
|
-
import './chunk-
|
|
4
|
-
import './chunk-
|
|
5
|
-
import './chunk-
|
|
6
|
-
import './chunk-
|
|
7
|
-
import './chunk-
|
|
8
|
-
import './chunk-
|
|
1
|
+
export { LiopClient } from './chunk-T7R5HUFD.js';
|
|
2
|
+
import './chunk-ESRXG36Y.js';
|
|
3
|
+
import './chunk-DZ2FQGJD.js';
|
|
4
|
+
import './chunk-PEN3KFLF.js';
|
|
5
|
+
import './chunk-IK7CGWAZ.js';
|
|
6
|
+
import './chunk-7PITYWOV.js';
|
|
7
|
+
import './chunk-TKRX6CFI.js';
|
|
8
|
+
import './chunk-PAICJCKJ.js';
|
|
9
|
+
import './chunk-EG46XMJT.js';
|
|
10
|
+
import './chunk-7RXOIDXP.js';
|
|
11
|
+
import './chunk-HA6YZ42O.js';
|
|
9
12
|
//# sourceMappingURL=client.js.map
|
|
10
13
|
//# sourceMappingURL=client.js.map
|
package/dist/gateway.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import './
|
|
2
|
-
import './index-
|
|
3
|
-
export { L as LiopHybridGateway } from './hybrid-
|
|
1
|
+
import './node-B0b2vUFS.js';
|
|
2
|
+
import './index-DoW2gzBZ.js';
|
|
3
|
+
export { L as LiopHybridGateway } from './hybrid-CrKB50nh.js';
|
|
4
4
|
import 'zod';
|
|
5
5
|
import './types-lJIxBlWF.js';
|
|
6
6
|
import 'jose';
|
package/dist/gateway.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
export { LiopHybridGateway } from './chunk-
|
|
2
|
-
import './chunk-
|
|
3
|
-
import './chunk-
|
|
4
|
-
import './chunk-
|
|
5
|
-
import './chunk-
|
|
6
|
-
import './chunk-
|
|
7
|
-
import './chunk-
|
|
8
|
-
import './chunk-
|
|
9
|
-
import './chunk-
|
|
1
|
+
export { LiopHybridGateway } from './chunk-3L2O2XKG.js';
|
|
2
|
+
import './chunk-L6J72C5X.js';
|
|
3
|
+
import './chunk-DZ2FQGJD.js';
|
|
4
|
+
import './chunk-PEN3KFLF.js';
|
|
5
|
+
import './chunk-IK7CGWAZ.js';
|
|
6
|
+
import './chunk-7PITYWOV.js';
|
|
7
|
+
import './chunk-VH4K4U45.js';
|
|
8
|
+
import './chunk-TKRX6CFI.js';
|
|
9
|
+
import './chunk-PAICJCKJ.js';
|
|
10
|
+
import './chunk-EG46XMJT.js';
|
|
11
|
+
import './chunk-HA6YZ42O.js';
|
|
10
12
|
//# sourceMappingURL=gateway.js.map
|
|
11
13
|
//# sourceMappingURL=gateway.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { MeshNode } from './
|
|
2
|
-
import { L as LiopServer } from './index-
|
|
1
|
+
import { a as MeshNode } from './node-B0b2vUFS.js';
|
|
2
|
+
import { L as LiopServer } from './index-DoW2gzBZ.js';
|
|
3
3
|
import { L as LiopVerifier } from './verifier-COnid_dg.js';
|
|
4
4
|
import { b as McpRequest, M as McpEra, A as AuthInfo, c as McpResponse } from './types-lJIxBlWF.js';
|
|
5
5
|
|
|
@@ -1,18 +1,8 @@
|
|
|
1
1
|
import { L as LiopVerifier } from './verifier-COnid_dg.js';
|
|
2
|
-
import { MeshNodeConfig } from './
|
|
2
|
+
import { M as MeshNodeConfig } from './node-B0b2vUFS.js';
|
|
3
3
|
import { EventEmitter } from 'node:events';
|
|
4
4
|
import { M as McpEra, C as CallToolRequest, a as CallToolResult } from './types-lJIxBlWF.js';
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* LIOP Certificate Manager (CertManager)
|
|
8
|
-
* Provides automated certificate monitoring, X.509 validity inspection,
|
|
9
|
-
* and hot-reloading for mutual TLS (mTLS) without node restarts.
|
|
10
|
-
*
|
|
11
|
-
* Compliance:
|
|
12
|
-
* - NIST SP 800-52 Rev. 2: Guidelines for the Selection and Use of TLS
|
|
13
|
-
* - Zero-Trust Architecture (NIST SP 800-207): Continuous cryptographic verification
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
6
|
interface CertManagerOptions {
|
|
17
7
|
/** Path to the root CA certificate (PEM format) */
|
|
18
8
|
rootCertPath?: string;
|
|
@@ -77,23 +67,6 @@ declare class CertManager extends EventEmitter {
|
|
|
77
67
|
dispose(): void;
|
|
78
68
|
}
|
|
79
69
|
|
|
80
|
-
/**
|
|
81
|
-
* LIOP TLS Configuration
|
|
82
|
-
*
|
|
83
|
-
* Provides conditional TLS credential factories for gRPC connections.
|
|
84
|
-
* When TLS options are provided, connections are secured with mutual TLS.
|
|
85
|
-
* Otherwise, falls back to insecure credentials (alpha/development mode).
|
|
86
|
-
*
|
|
87
|
-
* Production Hardening (Phase 128):
|
|
88
|
-
* - When NODE_ENV=production and TLS is configured but certificate loading
|
|
89
|
-
* fails, the system throws a fatal error instead of silently degrading
|
|
90
|
-
* to insecure credentials. This prevents MITM/eavesdropping attacks
|
|
91
|
-
* caused by misconfigured certificate paths going unnoticed.
|
|
92
|
-
* - Reference: gRPC-node official docs — "Using insecure credentials in
|
|
93
|
-
* production poses significant security risks including eavesdropping,
|
|
94
|
-
* MITM attacks, and lack of authentication."
|
|
95
|
-
*/
|
|
96
|
-
|
|
97
70
|
interface LiopTlsOptions {
|
|
98
71
|
/** Path to the root CA certificate (PEM format) */
|
|
99
72
|
rootCert?: string;
|
|
@@ -119,15 +92,12 @@ declare class LiopClient {
|
|
|
119
92
|
private serverInfo?;
|
|
120
93
|
verifier: LiopVerifier;
|
|
121
94
|
private oauthToken?;
|
|
95
|
+
private tokenManager?;
|
|
122
96
|
/** Protocol negotiation era */
|
|
123
97
|
era: McpEra;
|
|
124
98
|
/** Negotiated protocol version */
|
|
125
99
|
protocolVersion: string;
|
|
126
100
|
constructor(tls?: LiopTlsOptions);
|
|
127
|
-
/**
|
|
128
|
-
* Requests an M2M access token from the Nexus Authorization Server using Client Credentials.
|
|
129
|
-
*/
|
|
130
|
-
private acquireM2MToken;
|
|
131
101
|
/**
|
|
132
102
|
* Discovers and connects to the target server or mesh capability.
|
|
133
103
|
* If address is omitted, it sets up the MeshNode to act purely dynamically.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { MeshNode } from './
|
|
2
|
+
import { M as MeshNodeConfig, a as MeshNode } from './node-B0b2vUFS.js';
|
|
3
3
|
import { J as JwtValidator, S as ServerInfo, a as CallToolResult, P as Prompt, G as GetPromptRequest, d as GetPromptResult, C as CallToolRequest, T as Tool, R as Resource } from './types-lJIxBlWF.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -100,11 +100,6 @@ declare const AUTH_DEFAULTS: {
|
|
|
100
100
|
readonly signingAlgorithm: "EdDSA";
|
|
101
101
|
};
|
|
102
102
|
|
|
103
|
-
/**
|
|
104
|
-
* LIOP Immutable Audit Logger (Phase Beta-3)
|
|
105
|
-
* SOC 2 Type II & HIPAA compliant audit trail with cryptographic Hash-Chain.
|
|
106
|
-
* Guarantees tamper-evidence and non-repudiation for all Logic-on-Origin executions.
|
|
107
|
-
*/
|
|
108
103
|
type AuditStatus = "SUCCESS" | "BLOCKED_EGRESS" | "ERROR" | "POLICY_VIOLATION";
|
|
109
104
|
interface AuditEntry {
|
|
110
105
|
id: string;
|
|
@@ -211,11 +206,6 @@ interface OutputSanitizerConfig {
|
|
|
211
206
|
*/
|
|
212
207
|
declare function sanitizeOutput(output: unknown, config?: OutputSanitizerConfig): unknown;
|
|
213
208
|
|
|
214
|
-
/**
|
|
215
|
-
* LIOP Professional PII Engine (The Shield V2 - Tier-1 Military Edition)
|
|
216
|
-
* Implements high-fidelity detection based on NIST and OWASP standards.
|
|
217
|
-
* Features Multi-Layer Verification (Regex + Algorithmic Validators).
|
|
218
|
-
*/
|
|
219
209
|
type PiiRuleDefinition = {
|
|
220
210
|
name: string;
|
|
221
211
|
pattern: string | RegExp;
|
|
@@ -458,11 +448,7 @@ declare class LiopServer {
|
|
|
458
448
|
*/
|
|
459
449
|
connect(options?: {
|
|
460
450
|
port?: number;
|
|
461
|
-
meshConfig?:
|
|
462
|
-
listenAddresses?: string[];
|
|
463
|
-
bootstrapNodes?: string[];
|
|
464
|
-
identityPath?: string;
|
|
465
|
-
};
|
|
451
|
+
meshConfig?: MeshNodeConfig;
|
|
466
452
|
}): Promise<void>;
|
|
467
453
|
/**
|
|
468
454
|
* Register a new Tool
|
|
@@ -548,11 +534,7 @@ declare class LiopServer {
|
|
|
548
534
|
*/
|
|
549
535
|
connectToMesh(options?: {
|
|
550
536
|
port?: number;
|
|
551
|
-
meshConfig?:
|
|
552
|
-
listenAddresses?: string[];
|
|
553
|
-
bootstrapNodes?: string[];
|
|
554
|
-
identityPath?: string;
|
|
555
|
-
};
|
|
537
|
+
meshConfig?: MeshNodeConfig;
|
|
556
538
|
}): Promise<void>;
|
|
557
539
|
/**
|
|
558
540
|
* Internal worker execution with Egress Filtering logic.
|