@sanctuary-framework/mcp-server 0.5.11 → 0.5.13
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/cli.cjs +108 -23
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +108 -23
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +278 -170
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -2
- package/dist/index.d.ts +9 -2
- package/dist/index.js +278 -170
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
import { randomBytes as randomBytes$1, createHmac } from 'crypto';
|
|
2
|
+
import { gcm } from '@noble/ciphers/aes.js';
|
|
1
3
|
import { sha256 } from '@noble/hashes/sha256';
|
|
2
4
|
import { hmac } from '@noble/hashes/hmac';
|
|
5
|
+
import { RistrettoPoint, ed25519 } from '@noble/curves/ed25519';
|
|
3
6
|
import { readFile, mkdir, writeFile, stat, unlink, readdir, chmod, access } from 'fs/promises';
|
|
4
7
|
import { join } from 'path';
|
|
5
8
|
import { platform, homedir } from 'os';
|
|
6
9
|
import { createRequire } from 'module';
|
|
7
|
-
import { randomBytes as randomBytes$1, createHmac } from 'crypto';
|
|
8
|
-
import { gcm } from '@noble/ciphers/aes.js';
|
|
9
|
-
import { RistrettoPoint, ed25519 } from '@noble/curves/ed25519';
|
|
10
10
|
import { argon2id } from 'hash-wasm';
|
|
11
11
|
import { hkdf } from '@noble/hashes/hkdf';
|
|
12
12
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
@@ -25,6 +25,26 @@ var __export = (target, all) => {
|
|
|
25
25
|
for (var name in all)
|
|
26
26
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
27
27
|
};
|
|
28
|
+
function randomBytes(length) {
|
|
29
|
+
if (length <= 0) {
|
|
30
|
+
throw new RangeError("Length must be positive");
|
|
31
|
+
}
|
|
32
|
+
const buf = randomBytes$1(length);
|
|
33
|
+
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
34
|
+
}
|
|
35
|
+
function generateIV() {
|
|
36
|
+
return randomBytes(12);
|
|
37
|
+
}
|
|
38
|
+
function generateSalt() {
|
|
39
|
+
return randomBytes(32);
|
|
40
|
+
}
|
|
41
|
+
function generateRandomKey() {
|
|
42
|
+
return randomBytes(32);
|
|
43
|
+
}
|
|
44
|
+
var init_random = __esm({
|
|
45
|
+
"src/core/random.ts"() {
|
|
46
|
+
}
|
|
47
|
+
});
|
|
28
48
|
|
|
29
49
|
// src/core/encoding.ts
|
|
30
50
|
var encoding_exports = {};
|
|
@@ -76,6 +96,42 @@ var init_encoding = __esm({
|
|
|
76
96
|
"src/core/encoding.ts"() {
|
|
77
97
|
}
|
|
78
98
|
});
|
|
99
|
+
function encrypt(plaintext, key, aad) {
|
|
100
|
+
if (key.length !== 32) {
|
|
101
|
+
throw new Error("Key must be exactly 32 bytes (256 bits)");
|
|
102
|
+
}
|
|
103
|
+
const iv = generateIV();
|
|
104
|
+
const cipher = gcm(key, iv, aad);
|
|
105
|
+
const ciphertext = cipher.encrypt(plaintext);
|
|
106
|
+
return {
|
|
107
|
+
v: 1,
|
|
108
|
+
alg: "aes-256-gcm",
|
|
109
|
+
iv: toBase64url(iv),
|
|
110
|
+
ct: toBase64url(ciphertext),
|
|
111
|
+
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function decrypt(payload, key, aad) {
|
|
115
|
+
if (key.length !== 32) {
|
|
116
|
+
throw new Error("Key must be exactly 32 bytes (256 bits)");
|
|
117
|
+
}
|
|
118
|
+
if (payload.v !== 1) {
|
|
119
|
+
throw new Error(`Unsupported payload version: ${payload.v}`);
|
|
120
|
+
}
|
|
121
|
+
if (payload.alg !== "aes-256-gcm") {
|
|
122
|
+
throw new Error(`Unsupported algorithm: ${payload.alg}`);
|
|
123
|
+
}
|
|
124
|
+
const iv = fromBase64url(payload.iv);
|
|
125
|
+
const ciphertext = fromBase64url(payload.ct);
|
|
126
|
+
const cipher = gcm(key, iv, aad);
|
|
127
|
+
return cipher.decrypt(ciphertext);
|
|
128
|
+
}
|
|
129
|
+
var init_encryption = __esm({
|
|
130
|
+
"src/core/encryption.ts"() {
|
|
131
|
+
init_random();
|
|
132
|
+
init_encoding();
|
|
133
|
+
}
|
|
134
|
+
});
|
|
79
135
|
|
|
80
136
|
// src/core/hashing.ts
|
|
81
137
|
var hashing_exports = {};
|
|
@@ -204,6 +260,123 @@ var init_hashing = __esm({
|
|
|
204
260
|
init_encoding();
|
|
205
261
|
}
|
|
206
262
|
});
|
|
263
|
+
|
|
264
|
+
// src/core/identity.ts
|
|
265
|
+
var identity_exports = {};
|
|
266
|
+
__export(identity_exports, {
|
|
267
|
+
createIdentity: () => createIdentity,
|
|
268
|
+
generateIdentityId: () => generateIdentityId,
|
|
269
|
+
generateKeypair: () => generateKeypair,
|
|
270
|
+
publicKeyToDid: () => publicKeyToDid,
|
|
271
|
+
rotateKeys: () => rotateKeys,
|
|
272
|
+
sign: () => sign,
|
|
273
|
+
verify: () => verify
|
|
274
|
+
});
|
|
275
|
+
function generateKeypair() {
|
|
276
|
+
const privateKey = randomBytes(32);
|
|
277
|
+
const publicKey = ed25519.getPublicKey(privateKey);
|
|
278
|
+
return { publicKey, privateKey };
|
|
279
|
+
}
|
|
280
|
+
function publicKeyToDid(publicKey) {
|
|
281
|
+
const multicodec = new Uint8Array([237, 1, ...publicKey]);
|
|
282
|
+
return `did:key:z${toBase64url(multicodec)}`;
|
|
283
|
+
}
|
|
284
|
+
function generateIdentityId(publicKey) {
|
|
285
|
+
const keyHash = hash(publicKey);
|
|
286
|
+
return Array.from(keyHash.slice(0, 16)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
287
|
+
}
|
|
288
|
+
function createIdentity(label, encryptionKey, keyProtection) {
|
|
289
|
+
const { publicKey, privateKey } = generateKeypair();
|
|
290
|
+
const identityId = generateIdentityId(publicKey);
|
|
291
|
+
const did = publicKeyToDid(publicKey);
|
|
292
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
293
|
+
const encryptedPrivateKey = encrypt(privateKey, encryptionKey);
|
|
294
|
+
privateKey.fill(0);
|
|
295
|
+
const publicIdentity = {
|
|
296
|
+
identity_id: identityId,
|
|
297
|
+
label,
|
|
298
|
+
public_key: toBase64url(publicKey),
|
|
299
|
+
did,
|
|
300
|
+
created_at: now,
|
|
301
|
+
key_type: "ed25519",
|
|
302
|
+
key_protection: keyProtection
|
|
303
|
+
};
|
|
304
|
+
const storedIdentity = {
|
|
305
|
+
...publicIdentity,
|
|
306
|
+
encrypted_private_key: encryptedPrivateKey,
|
|
307
|
+
rotation_history: []
|
|
308
|
+
};
|
|
309
|
+
return { publicIdentity, storedIdentity };
|
|
310
|
+
}
|
|
311
|
+
function sign(payload, encryptedPrivateKey, encryptionKey) {
|
|
312
|
+
const privateKey = decrypt(encryptedPrivateKey, encryptionKey);
|
|
313
|
+
try {
|
|
314
|
+
return ed25519.sign(payload, privateKey);
|
|
315
|
+
} finally {
|
|
316
|
+
privateKey.fill(0);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
function verify(payload, signature, publicKey) {
|
|
320
|
+
try {
|
|
321
|
+
return ed25519.verify(signature, payload, publicKey);
|
|
322
|
+
} catch {
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
function rotateKeys(storedIdentity, encryptionKey, reason) {
|
|
327
|
+
const { publicKey: newPublicKey, privateKey: newPrivateKey } = generateKeypair();
|
|
328
|
+
const newIdentityDid = publicKeyToDid(newPublicKey);
|
|
329
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
330
|
+
const eventData = JSON.stringify({
|
|
331
|
+
old_public_key: storedIdentity.public_key,
|
|
332
|
+
new_public_key: toBase64url(newPublicKey),
|
|
333
|
+
identity_id: storedIdentity.identity_id,
|
|
334
|
+
reason,
|
|
335
|
+
rotated_at: now
|
|
336
|
+
});
|
|
337
|
+
const eventBytes = new TextEncoder().encode(eventData);
|
|
338
|
+
const signature = sign(
|
|
339
|
+
eventBytes,
|
|
340
|
+
storedIdentity.encrypted_private_key,
|
|
341
|
+
encryptionKey
|
|
342
|
+
);
|
|
343
|
+
const rotationEvent = {
|
|
344
|
+
old_public_key: storedIdentity.public_key,
|
|
345
|
+
new_public_key: toBase64url(newPublicKey),
|
|
346
|
+
identity_id: storedIdentity.identity_id,
|
|
347
|
+
reason,
|
|
348
|
+
rotated_at: now,
|
|
349
|
+
signature: toBase64url(signature)
|
|
350
|
+
};
|
|
351
|
+
const encryptedNewPrivateKey = encrypt(newPrivateKey, encryptionKey);
|
|
352
|
+
newPrivateKey.fill(0);
|
|
353
|
+
const updatedIdentity = {
|
|
354
|
+
...storedIdentity,
|
|
355
|
+
public_key: toBase64url(newPublicKey),
|
|
356
|
+
did: newIdentityDid,
|
|
357
|
+
encrypted_private_key: encryptedNewPrivateKey,
|
|
358
|
+
rotation_history: [
|
|
359
|
+
...storedIdentity.rotation_history,
|
|
360
|
+
{
|
|
361
|
+
old_public_key: storedIdentity.public_key,
|
|
362
|
+
new_public_key: toBase64url(newPublicKey),
|
|
363
|
+
rotation_event: toBase64url(
|
|
364
|
+
new TextEncoder().encode(JSON.stringify(rotationEvent))
|
|
365
|
+
),
|
|
366
|
+
rotated_at: now
|
|
367
|
+
}
|
|
368
|
+
]
|
|
369
|
+
};
|
|
370
|
+
return { updatedIdentity, rotationEvent };
|
|
371
|
+
}
|
|
372
|
+
var init_identity = __esm({
|
|
373
|
+
"src/core/identity.ts"() {
|
|
374
|
+
init_encoding();
|
|
375
|
+
init_encryption();
|
|
376
|
+
init_hashing();
|
|
377
|
+
init_random();
|
|
378
|
+
}
|
|
379
|
+
});
|
|
207
380
|
var require2 = createRequire(import.meta.url);
|
|
208
381
|
var { version: PKG_VERSION } = require2("../package.json");
|
|
209
382
|
var SANCTUARY_VERSION = PKG_VERSION;
|
|
@@ -381,24 +554,9 @@ function deepMerge(base, override) {
|
|
|
381
554
|
}
|
|
382
555
|
return result;
|
|
383
556
|
}
|
|
384
|
-
function randomBytes(length) {
|
|
385
|
-
if (length <= 0) {
|
|
386
|
-
throw new RangeError("Length must be positive");
|
|
387
|
-
}
|
|
388
|
-
const buf = randomBytes$1(length);
|
|
389
|
-
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
390
|
-
}
|
|
391
|
-
function generateIV() {
|
|
392
|
-
return randomBytes(12);
|
|
393
|
-
}
|
|
394
|
-
function generateSalt() {
|
|
395
|
-
return randomBytes(32);
|
|
396
|
-
}
|
|
397
|
-
function generateRandomKey() {
|
|
398
|
-
return randomBytes(32);
|
|
399
|
-
}
|
|
400
557
|
|
|
401
558
|
// src/storage/filesystem.ts
|
|
559
|
+
init_random();
|
|
402
560
|
var FilesystemStorage = class {
|
|
403
561
|
basePath;
|
|
404
562
|
constructor(basePath) {
|
|
@@ -506,141 +664,14 @@ var FilesystemStorage = class {
|
|
|
506
664
|
return total;
|
|
507
665
|
}
|
|
508
666
|
};
|
|
509
|
-
init_encoding();
|
|
510
|
-
function encrypt(plaintext, key, aad) {
|
|
511
|
-
if (key.length !== 32) {
|
|
512
|
-
throw new Error("Key must be exactly 32 bytes (256 bits)");
|
|
513
|
-
}
|
|
514
|
-
const iv = generateIV();
|
|
515
|
-
const cipher = gcm(key, iv, aad);
|
|
516
|
-
const ciphertext = cipher.encrypt(plaintext);
|
|
517
|
-
return {
|
|
518
|
-
v: 1,
|
|
519
|
-
alg: "aes-256-gcm",
|
|
520
|
-
iv: toBase64url(iv),
|
|
521
|
-
ct: toBase64url(ciphertext),
|
|
522
|
-
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
523
|
-
};
|
|
524
|
-
}
|
|
525
|
-
function decrypt(payload, key, aad) {
|
|
526
|
-
if (key.length !== 32) {
|
|
527
|
-
throw new Error("Key must be exactly 32 bytes (256 bits)");
|
|
528
|
-
}
|
|
529
|
-
if (payload.v !== 1) {
|
|
530
|
-
throw new Error(`Unsupported payload version: ${payload.v}`);
|
|
531
|
-
}
|
|
532
|
-
if (payload.alg !== "aes-256-gcm") {
|
|
533
|
-
throw new Error(`Unsupported algorithm: ${payload.alg}`);
|
|
534
|
-
}
|
|
535
|
-
const iv = fromBase64url(payload.iv);
|
|
536
|
-
const ciphertext = fromBase64url(payload.ct);
|
|
537
|
-
const cipher = gcm(key, iv, aad);
|
|
538
|
-
return cipher.decrypt(ciphertext);
|
|
539
|
-
}
|
|
540
667
|
|
|
541
668
|
// src/l1-cognitive/state-store.ts
|
|
669
|
+
init_encryption();
|
|
542
670
|
init_hashing();
|
|
671
|
+
init_identity();
|
|
543
672
|
|
|
544
|
-
// src/core/
|
|
545
|
-
|
|
546
|
-
init_hashing();
|
|
547
|
-
function generateKeypair() {
|
|
548
|
-
const privateKey = randomBytes(32);
|
|
549
|
-
const publicKey = ed25519.getPublicKey(privateKey);
|
|
550
|
-
return { publicKey, privateKey };
|
|
551
|
-
}
|
|
552
|
-
function publicKeyToDid(publicKey) {
|
|
553
|
-
const multicodec = new Uint8Array([237, 1, ...publicKey]);
|
|
554
|
-
return `did:key:z${toBase64url(multicodec)}`;
|
|
555
|
-
}
|
|
556
|
-
function generateIdentityId(publicKey) {
|
|
557
|
-
const keyHash = hash(publicKey);
|
|
558
|
-
return Array.from(keyHash.slice(0, 16)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
559
|
-
}
|
|
560
|
-
function createIdentity(label, encryptionKey, keyProtection) {
|
|
561
|
-
const { publicKey, privateKey } = generateKeypair();
|
|
562
|
-
const identityId = generateIdentityId(publicKey);
|
|
563
|
-
const did = publicKeyToDid(publicKey);
|
|
564
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
565
|
-
const encryptedPrivateKey = encrypt(privateKey, encryptionKey);
|
|
566
|
-
privateKey.fill(0);
|
|
567
|
-
const publicIdentity = {
|
|
568
|
-
identity_id: identityId,
|
|
569
|
-
label,
|
|
570
|
-
public_key: toBase64url(publicKey),
|
|
571
|
-
did,
|
|
572
|
-
created_at: now,
|
|
573
|
-
key_type: "ed25519",
|
|
574
|
-
key_protection: keyProtection
|
|
575
|
-
};
|
|
576
|
-
const storedIdentity = {
|
|
577
|
-
...publicIdentity,
|
|
578
|
-
encrypted_private_key: encryptedPrivateKey,
|
|
579
|
-
rotation_history: []
|
|
580
|
-
};
|
|
581
|
-
return { publicIdentity, storedIdentity };
|
|
582
|
-
}
|
|
583
|
-
function sign(payload, encryptedPrivateKey, encryptionKey) {
|
|
584
|
-
const privateKey = decrypt(encryptedPrivateKey, encryptionKey);
|
|
585
|
-
try {
|
|
586
|
-
return ed25519.sign(payload, privateKey);
|
|
587
|
-
} finally {
|
|
588
|
-
privateKey.fill(0);
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
function verify(payload, signature, publicKey) {
|
|
592
|
-
try {
|
|
593
|
-
return ed25519.verify(signature, payload, publicKey);
|
|
594
|
-
} catch {
|
|
595
|
-
return false;
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
function rotateKeys(storedIdentity, encryptionKey, reason) {
|
|
599
|
-
const { publicKey: newPublicKey, privateKey: newPrivateKey } = generateKeypair();
|
|
600
|
-
const newIdentityDid = publicKeyToDid(newPublicKey);
|
|
601
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
602
|
-
const eventData = JSON.stringify({
|
|
603
|
-
old_public_key: storedIdentity.public_key,
|
|
604
|
-
new_public_key: toBase64url(newPublicKey),
|
|
605
|
-
identity_id: storedIdentity.identity_id,
|
|
606
|
-
reason,
|
|
607
|
-
rotated_at: now
|
|
608
|
-
});
|
|
609
|
-
const eventBytes = new TextEncoder().encode(eventData);
|
|
610
|
-
const signature = sign(
|
|
611
|
-
eventBytes,
|
|
612
|
-
storedIdentity.encrypted_private_key,
|
|
613
|
-
encryptionKey
|
|
614
|
-
);
|
|
615
|
-
const rotationEvent = {
|
|
616
|
-
old_public_key: storedIdentity.public_key,
|
|
617
|
-
new_public_key: toBase64url(newPublicKey),
|
|
618
|
-
identity_id: storedIdentity.identity_id,
|
|
619
|
-
reason,
|
|
620
|
-
rotated_at: now,
|
|
621
|
-
signature: toBase64url(signature)
|
|
622
|
-
};
|
|
623
|
-
const encryptedNewPrivateKey = encrypt(newPrivateKey, encryptionKey);
|
|
624
|
-
newPrivateKey.fill(0);
|
|
625
|
-
const updatedIdentity = {
|
|
626
|
-
...storedIdentity,
|
|
627
|
-
public_key: toBase64url(newPublicKey),
|
|
628
|
-
did: newIdentityDid,
|
|
629
|
-
encrypted_private_key: encryptedNewPrivateKey,
|
|
630
|
-
rotation_history: [
|
|
631
|
-
...storedIdentity.rotation_history,
|
|
632
|
-
{
|
|
633
|
-
old_public_key: storedIdentity.public_key,
|
|
634
|
-
new_public_key: toBase64url(newPublicKey),
|
|
635
|
-
rotation_event: toBase64url(
|
|
636
|
-
new TextEncoder().encode(JSON.stringify(rotationEvent))
|
|
637
|
-
),
|
|
638
|
-
rotated_at: now
|
|
639
|
-
}
|
|
640
|
-
]
|
|
641
|
-
};
|
|
642
|
-
return { updatedIdentity, rotationEvent };
|
|
643
|
-
}
|
|
673
|
+
// src/core/key-derivation.ts
|
|
674
|
+
init_random();
|
|
644
675
|
init_encoding();
|
|
645
676
|
var ARGON2_MEMORY_COST = 65536;
|
|
646
677
|
var ARGON2_TIME_COST = 3;
|
|
@@ -1238,7 +1269,9 @@ function toolResult(data) {
|
|
|
1238
1269
|
}
|
|
1239
1270
|
|
|
1240
1271
|
// src/l1-cognitive/tools.ts
|
|
1272
|
+
init_identity();
|
|
1241
1273
|
init_encoding();
|
|
1274
|
+
init_encryption();
|
|
1242
1275
|
init_encoding();
|
|
1243
1276
|
var RESERVED_NAMESPACE_PREFIXES2 = [
|
|
1244
1277
|
"_identities",
|
|
@@ -1275,9 +1308,13 @@ var IdentityManager = class {
|
|
|
1275
1308
|
get encryptionKey() {
|
|
1276
1309
|
return derivePurposeKey(this.masterKey, "identity-encryption");
|
|
1277
1310
|
}
|
|
1278
|
-
/** Load identities from storage on startup
|
|
1311
|
+
/** Load identities from storage on startup.
|
|
1312
|
+
* Returns { total: number of encrypted files found, loaded: number successfully decrypted }.
|
|
1313
|
+
* A mismatch (total > 0, loaded === 0) indicates a wrong master key / missing passphrase.
|
|
1314
|
+
*/
|
|
1279
1315
|
async load() {
|
|
1280
1316
|
const entries = await this.storage.list("_identities");
|
|
1317
|
+
let failed = 0;
|
|
1281
1318
|
for (const entry of entries) {
|
|
1282
1319
|
const raw = await this.storage.read("_identities", entry.key);
|
|
1283
1320
|
if (!raw) continue;
|
|
@@ -1290,8 +1327,10 @@ var IdentityManager = class {
|
|
|
1290
1327
|
this.primaryIdentityId = identity.identity_id;
|
|
1291
1328
|
}
|
|
1292
1329
|
} catch {
|
|
1330
|
+
failed++;
|
|
1293
1331
|
}
|
|
1294
1332
|
}
|
|
1333
|
+
return { total: entries.length, loaded: this.identities.size, failed };
|
|
1295
1334
|
}
|
|
1296
1335
|
/** Save an identity to storage */
|
|
1297
1336
|
async save(identity) {
|
|
@@ -1739,6 +1778,7 @@ function createL1Tools(stateStore, storage, masterKey, keyProtection, auditLog)
|
|
|
1739
1778
|
}
|
|
1740
1779
|
|
|
1741
1780
|
// src/l2-operational/audit-log.ts
|
|
1781
|
+
init_encryption();
|
|
1742
1782
|
init_encoding();
|
|
1743
1783
|
var AuditLog = class {
|
|
1744
1784
|
storage;
|
|
@@ -1836,6 +1876,8 @@ var AuditLog = class {
|
|
|
1836
1876
|
// src/l3-disclosure/commitments.ts
|
|
1837
1877
|
init_hashing();
|
|
1838
1878
|
init_encoding();
|
|
1879
|
+
init_random();
|
|
1880
|
+
init_encryption();
|
|
1839
1881
|
init_encoding();
|
|
1840
1882
|
function createCommitment(value, blindingFactor) {
|
|
1841
1883
|
const blindingBytes = blindingFactor ? fromBase64url(blindingFactor) : randomBytes(32);
|
|
@@ -1916,7 +1958,9 @@ var CommitmentStore = class {
|
|
|
1916
1958
|
};
|
|
1917
1959
|
|
|
1918
1960
|
// src/l3-disclosure/policies.ts
|
|
1961
|
+
init_encryption();
|
|
1919
1962
|
init_encoding();
|
|
1963
|
+
init_random();
|
|
1920
1964
|
function evaluateDisclosure(policy, context, requestedFields) {
|
|
1921
1965
|
return requestedFields.map((field) => {
|
|
1922
1966
|
const exactRule = policy.rules.find((r) => r.context === context);
|
|
@@ -2047,6 +2091,9 @@ var PolicyStore = class {
|
|
|
2047
2091
|
);
|
|
2048
2092
|
}
|
|
2049
2093
|
};
|
|
2094
|
+
|
|
2095
|
+
// src/l3-disclosure/zk-proofs.ts
|
|
2096
|
+
init_random();
|
|
2050
2097
|
init_encoding();
|
|
2051
2098
|
var G = RistrettoPoint.BASE;
|
|
2052
2099
|
var H_INPUT = concatBytes(
|
|
@@ -2724,7 +2771,10 @@ function createL3Tools(storage, masterKey, auditLog) {
|
|
|
2724
2771
|
}
|
|
2725
2772
|
|
|
2726
2773
|
// src/l4-reputation/reputation-store.ts
|
|
2774
|
+
init_encryption();
|
|
2727
2775
|
init_encoding();
|
|
2776
|
+
init_random();
|
|
2777
|
+
init_identity();
|
|
2728
2778
|
function computeMedian(values) {
|
|
2729
2779
|
if (values.length === 0) return 0;
|
|
2730
2780
|
const sorted = [...values].sort((a, b) => a - b);
|
|
@@ -3619,6 +3669,24 @@ function createL4Tools(storage, masterKey, identityManager, auditLog, handshakeR
|
|
|
3619
3669
|
}
|
|
3620
3670
|
const publishType = args.type;
|
|
3621
3671
|
const veracoreUrl = args.verascore_url || "https://verascore.ai";
|
|
3672
|
+
const ALLOWED_VERASCORE_HOSTS = ["verascore.ai", "www.verascore.ai", "api.verascore.ai"];
|
|
3673
|
+
try {
|
|
3674
|
+
const parsed = new URL(veracoreUrl);
|
|
3675
|
+
if (parsed.protocol !== "https:") {
|
|
3676
|
+
return toolResult({
|
|
3677
|
+
error: `verascore_url must use HTTPS. Got: ${parsed.protocol}`
|
|
3678
|
+
});
|
|
3679
|
+
}
|
|
3680
|
+
if (!ALLOWED_VERASCORE_HOSTS.includes(parsed.hostname)) {
|
|
3681
|
+
return toolResult({
|
|
3682
|
+
error: `verascore_url must point to a known Verascore domain (${ALLOWED_VERASCORE_HOSTS.join(", ")}). Got: ${parsed.hostname}`
|
|
3683
|
+
});
|
|
3684
|
+
}
|
|
3685
|
+
} catch {
|
|
3686
|
+
return toolResult({
|
|
3687
|
+
error: `verascore_url is not a valid URL: ${veracoreUrl}`
|
|
3688
|
+
});
|
|
3689
|
+
}
|
|
3622
3690
|
const agentId = args.verascore_agent_id || identity.did.replace(/[^a-zA-Z0-9-]/g, "-").toLowerCase();
|
|
3623
3691
|
let publishData;
|
|
3624
3692
|
if (args.data) {
|
|
@@ -3648,24 +3716,21 @@ function createL4Tools(storage, masterKey, identityManager, auditLog, handshakeR
|
|
|
3648
3716
|
return toolResult({ error: `Unknown publish type: ${publishType}` });
|
|
3649
3717
|
}
|
|
3650
3718
|
}
|
|
3651
|
-
const { sign:
|
|
3652
|
-
const payloadBytes =
|
|
3719
|
+
const { sign: identitySign } = await Promise.resolve().then(() => (init_identity(), identity_exports));
|
|
3720
|
+
const payloadBytes = new TextEncoder().encode(JSON.stringify(publishData));
|
|
3653
3721
|
let signatureB64;
|
|
3654
3722
|
try {
|
|
3655
|
-
const
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
]),
|
|
3662
|
-
format: "der",
|
|
3663
|
-
type: "pkcs8"
|
|
3664
|
-
});
|
|
3665
|
-
const sig = sign2(null, payloadBytes, privateKey);
|
|
3666
|
-
signatureB64 = sig.toString("base64url");
|
|
3723
|
+
const signingBytes = identitySign(
|
|
3724
|
+
payloadBytes,
|
|
3725
|
+
identity.encrypted_private_key,
|
|
3726
|
+
identityEncryptionKey
|
|
3727
|
+
);
|
|
3728
|
+
signatureB64 = toBase64url(signingBytes);
|
|
3667
3729
|
} catch (signError) {
|
|
3668
|
-
|
|
3730
|
+
return toolResult({
|
|
3731
|
+
error: "Failed to sign publish payload. Identity key may be corrupted.",
|
|
3732
|
+
details: signError instanceof Error ? signError.message : String(signError)
|
|
3733
|
+
});
|
|
3669
3734
|
}
|
|
3670
3735
|
const requestBody = {
|
|
3671
3736
|
agentId,
|
|
@@ -3744,7 +3809,9 @@ var DEFAULT_POLICY = {
|
|
|
3744
3809
|
"reputation_import",
|
|
3745
3810
|
"reputation_export",
|
|
3746
3811
|
"bootstrap_provide_guarantee",
|
|
3747
|
-
"decommission_certificate"
|
|
3812
|
+
"decommission_certificate",
|
|
3813
|
+
"reputation_publish"
|
|
3814
|
+
// SEC-039: Explicit Tier 1 — sends data to external API
|
|
3748
3815
|
],
|
|
3749
3816
|
tier2_anomaly: DEFAULT_TIER2,
|
|
3750
3817
|
tier3_always_allow: [
|
|
@@ -3796,7 +3863,9 @@ var DEFAULT_POLICY = {
|
|
|
3796
3863
|
"shr_gateway_export",
|
|
3797
3864
|
"bridge_commit",
|
|
3798
3865
|
"bridge_verify",
|
|
3799
|
-
"bridge_attest"
|
|
3866
|
+
"bridge_attest",
|
|
3867
|
+
"dashboard_open"
|
|
3868
|
+
// SEC-039: Explicit Tier 3 — only generates a URL
|
|
3800
3869
|
],
|
|
3801
3870
|
approval_channel: DEFAULT_CHANNEL
|
|
3802
3871
|
};
|
|
@@ -3904,6 +3973,7 @@ tier1_always_approve:
|
|
|
3904
3973
|
- reputation_import
|
|
3905
3974
|
- reputation_export
|
|
3906
3975
|
- bootstrap_provide_guarantee
|
|
3976
|
+
- reputation_publish
|
|
3907
3977
|
|
|
3908
3978
|
# \u2500\u2500\u2500 Tier 2: Behavioral Anomaly Detection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
3909
3979
|
# Triggers approval when agent behavior deviates from its baseline.
|
|
@@ -3966,6 +4036,7 @@ tier3_always_allow:
|
|
|
3966
4036
|
- bridge_commit
|
|
3967
4037
|
- bridge_verify
|
|
3968
4038
|
- bridge_attest
|
|
4039
|
+
- dashboard_open
|
|
3969
4040
|
|
|
3970
4041
|
# \u2500\u2500\u2500 Approval Channel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
3971
4042
|
# How Sanctuary reaches you when approval is needed.
|
|
@@ -3993,6 +4064,7 @@ async function loadPrincipalPolicy(storagePath) {
|
|
|
3993
4064
|
}
|
|
3994
4065
|
|
|
3995
4066
|
// src/principal-policy/baseline.ts
|
|
4067
|
+
init_encryption();
|
|
3996
4068
|
init_encoding();
|
|
3997
4069
|
var BASELINE_NAMESPACE = "_principal";
|
|
3998
4070
|
var BASELINE_KEY = "session-baseline";
|
|
@@ -4218,6 +4290,7 @@ function canonicalizeForSigning(body) {
|
|
|
4218
4290
|
}
|
|
4219
4291
|
|
|
4220
4292
|
// src/shr/generator.ts
|
|
4293
|
+
init_identity();
|
|
4221
4294
|
init_encoding();
|
|
4222
4295
|
var DEFAULT_VALIDITY_MS = 60 * 60 * 1e3;
|
|
4223
4296
|
function generateSHR(identityId, opts) {
|
|
@@ -5598,7 +5671,9 @@ function generateDashboardHTML(options) {
|
|
|
5598
5671
|
|
|
5599
5672
|
<script>
|
|
5600
5673
|
// Constants
|
|
5601
|
-
|
|
5674
|
+
// SEC-038: Do NOT embed the long-lived auth token in page source.
|
|
5675
|
+
// Use only the session token stored in sessionStorage by the login flow.
|
|
5676
|
+
const AUTH_TOKEN = sessionStorage.getItem('authToken') || '';
|
|
5602
5677
|
const TIMEOUT_SECONDS = ${options.timeoutSeconds};
|
|
5603
5678
|
const API_BASE = '';
|
|
5604
5679
|
|
|
@@ -8111,6 +8186,7 @@ function createPrincipalPolicyTools(policy, baseline, auditLog) {
|
|
|
8111
8186
|
}
|
|
8112
8187
|
|
|
8113
8188
|
// src/shr/verifier.ts
|
|
8189
|
+
init_identity();
|
|
8114
8190
|
init_encoding();
|
|
8115
8191
|
function verifySHR(shr, now) {
|
|
8116
8192
|
const errors = [];
|
|
@@ -8533,7 +8609,9 @@ function createSHRTools(config, identityManager, masterKey, auditLog) {
|
|
|
8533
8609
|
}
|
|
8534
8610
|
|
|
8535
8611
|
// src/handshake/protocol.ts
|
|
8612
|
+
init_identity();
|
|
8536
8613
|
init_encoding();
|
|
8614
|
+
init_random();
|
|
8537
8615
|
function generateNonce() {
|
|
8538
8616
|
return toBase64url(randomBytes(32));
|
|
8539
8617
|
}
|
|
@@ -8700,7 +8778,9 @@ function deriveTrustTier(level) {
|
|
|
8700
8778
|
}
|
|
8701
8779
|
|
|
8702
8780
|
// src/handshake/attestation.ts
|
|
8781
|
+
init_identity();
|
|
8703
8782
|
init_encoding();
|
|
8783
|
+
init_identity();
|
|
8704
8784
|
init_encoding();
|
|
8705
8785
|
var ATTESTATION_VERSION = "1.0";
|
|
8706
8786
|
function deriveTrustTier2(level) {
|
|
@@ -9493,10 +9573,13 @@ function createFederationTools(auditLog, handshakeResults) {
|
|
|
9493
9573
|
|
|
9494
9574
|
// src/bridge/tools.ts
|
|
9495
9575
|
init_encoding();
|
|
9576
|
+
init_encryption();
|
|
9496
9577
|
init_encoding();
|
|
9497
9578
|
|
|
9498
9579
|
// src/bridge/bridge.ts
|
|
9580
|
+
init_identity();
|
|
9499
9581
|
init_encoding();
|
|
9582
|
+
init_random();
|
|
9500
9583
|
init_hashing();
|
|
9501
9584
|
function canonicalize(outcome) {
|
|
9502
9585
|
return stringToBytes(stableStringify(outcome));
|
|
@@ -10647,7 +10730,9 @@ function createAuditTools(config) {
|
|
|
10647
10730
|
}
|
|
10648
10731
|
|
|
10649
10732
|
// src/l2-operational/context-gate.ts
|
|
10733
|
+
init_encryption();
|
|
10650
10734
|
init_encoding();
|
|
10735
|
+
init_random();
|
|
10651
10736
|
init_hashing();
|
|
10652
10737
|
var MAX_CONTEXT_FIELDS = 1e3;
|
|
10653
10738
|
var MAX_POLICY_RULES = 50;
|
|
@@ -12617,6 +12702,7 @@ function createL2HardeningTools(storagePath, auditLog) {
|
|
|
12617
12702
|
}
|
|
12618
12703
|
|
|
12619
12704
|
// src/index.ts
|
|
12705
|
+
init_random();
|
|
12620
12706
|
init_encoding();
|
|
12621
12707
|
|
|
12622
12708
|
// src/l2-operational/model-provenance.ts
|
|
@@ -12863,7 +12949,29 @@ async function createSanctuaryServer(options) {
|
|
|
12863
12949
|
keyProtection,
|
|
12864
12950
|
auditLog
|
|
12865
12951
|
);
|
|
12866
|
-
await identityManager.load();
|
|
12952
|
+
const loadResult = await identityManager.load();
|
|
12953
|
+
if (loadResult.total > 0 && loadResult.loaded === 0) {
|
|
12954
|
+
console.error(
|
|
12955
|
+
`
|
|
12956
|
+
\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
|
|
12957
|
+
\u2551 \u26A0 WARNING: Encrypted identities found but NONE loaded \u2551
|
|
12958
|
+
\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563
|
|
12959
|
+
\u2551 ${loadResult.total} encrypted identity file(s) found on disk \u2551
|
|
12960
|
+
\u2551 0 could be decrypted with the current master key \u2551
|
|
12961
|
+
\u2551 \u2551
|
|
12962
|
+
\u2551 This usually means SANCTUARY_PASSPHRASE is missing or \u2551
|
|
12963
|
+
\u2551 incorrect. The server will start but with NO identity data. \u2551
|
|
12964
|
+
\u2551 \u2551
|
|
12965
|
+
\u2551 To fix: set SANCTUARY_PASSPHRASE to the passphrase used \u2551
|
|
12966
|
+
\u2551 when this Sanctuary instance was first configured. \u2551
|
|
12967
|
+
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
|
|
12968
|
+
`
|
|
12969
|
+
);
|
|
12970
|
+
} else if (loadResult.failed > 0) {
|
|
12971
|
+
console.error(
|
|
12972
|
+
`Warning: ${loadResult.failed} of ${loadResult.total} identity files could not be decrypted (possibly corrupted).`
|
|
12973
|
+
);
|
|
12974
|
+
}
|
|
12867
12975
|
const l2Tools = [
|
|
12868
12976
|
{
|
|
12869
12977
|
name: "sanctuary/exec_attest",
|