@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.cjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var crypto = require('crypto');
|
|
4
|
+
var aes_js = require('@noble/ciphers/aes.js');
|
|
3
5
|
var sha256 = require('@noble/hashes/sha256');
|
|
4
6
|
var hmac = require('@noble/hashes/hmac');
|
|
7
|
+
var ed25519 = require('@noble/curves/ed25519');
|
|
5
8
|
var promises = require('fs/promises');
|
|
6
9
|
var path = require('path');
|
|
7
10
|
var os = require('os');
|
|
8
11
|
var module$1 = require('module');
|
|
9
|
-
var crypto = require('crypto');
|
|
10
|
-
var aes_js = require('@noble/ciphers/aes.js');
|
|
11
|
-
var ed25519 = require('@noble/curves/ed25519');
|
|
12
12
|
var hashWasm = require('hash-wasm');
|
|
13
13
|
var hkdf = require('@noble/hashes/hkdf');
|
|
14
14
|
var index_js = require('@modelcontextprotocol/sdk/server/index.js');
|
|
@@ -28,6 +28,26 @@ var __export = (target, all) => {
|
|
|
28
28
|
for (var name in all)
|
|
29
29
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
30
30
|
};
|
|
31
|
+
function randomBytes(length) {
|
|
32
|
+
if (length <= 0) {
|
|
33
|
+
throw new RangeError("Length must be positive");
|
|
34
|
+
}
|
|
35
|
+
const buf = crypto.randomBytes(length);
|
|
36
|
+
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
37
|
+
}
|
|
38
|
+
function generateIV() {
|
|
39
|
+
return randomBytes(12);
|
|
40
|
+
}
|
|
41
|
+
function generateSalt() {
|
|
42
|
+
return randomBytes(32);
|
|
43
|
+
}
|
|
44
|
+
function generateRandomKey() {
|
|
45
|
+
return randomBytes(32);
|
|
46
|
+
}
|
|
47
|
+
var init_random = __esm({
|
|
48
|
+
"src/core/random.ts"() {
|
|
49
|
+
}
|
|
50
|
+
});
|
|
31
51
|
|
|
32
52
|
// src/core/encoding.ts
|
|
33
53
|
var encoding_exports = {};
|
|
@@ -79,6 +99,42 @@ var init_encoding = __esm({
|
|
|
79
99
|
"src/core/encoding.ts"() {
|
|
80
100
|
}
|
|
81
101
|
});
|
|
102
|
+
function encrypt(plaintext, key, aad) {
|
|
103
|
+
if (key.length !== 32) {
|
|
104
|
+
throw new Error("Key must be exactly 32 bytes (256 bits)");
|
|
105
|
+
}
|
|
106
|
+
const iv = generateIV();
|
|
107
|
+
const cipher = aes_js.gcm(key, iv, aad);
|
|
108
|
+
const ciphertext = cipher.encrypt(plaintext);
|
|
109
|
+
return {
|
|
110
|
+
v: 1,
|
|
111
|
+
alg: "aes-256-gcm",
|
|
112
|
+
iv: toBase64url(iv),
|
|
113
|
+
ct: toBase64url(ciphertext),
|
|
114
|
+
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function decrypt(payload, key, aad) {
|
|
118
|
+
if (key.length !== 32) {
|
|
119
|
+
throw new Error("Key must be exactly 32 bytes (256 bits)");
|
|
120
|
+
}
|
|
121
|
+
if (payload.v !== 1) {
|
|
122
|
+
throw new Error(`Unsupported payload version: ${payload.v}`);
|
|
123
|
+
}
|
|
124
|
+
if (payload.alg !== "aes-256-gcm") {
|
|
125
|
+
throw new Error(`Unsupported algorithm: ${payload.alg}`);
|
|
126
|
+
}
|
|
127
|
+
const iv = fromBase64url(payload.iv);
|
|
128
|
+
const ciphertext = fromBase64url(payload.ct);
|
|
129
|
+
const cipher = aes_js.gcm(key, iv, aad);
|
|
130
|
+
return cipher.decrypt(ciphertext);
|
|
131
|
+
}
|
|
132
|
+
var init_encryption = __esm({
|
|
133
|
+
"src/core/encryption.ts"() {
|
|
134
|
+
init_random();
|
|
135
|
+
init_encoding();
|
|
136
|
+
}
|
|
137
|
+
});
|
|
82
138
|
|
|
83
139
|
// src/core/hashing.ts
|
|
84
140
|
var hashing_exports = {};
|
|
@@ -207,6 +263,123 @@ var init_hashing = __esm({
|
|
|
207
263
|
init_encoding();
|
|
208
264
|
}
|
|
209
265
|
});
|
|
266
|
+
|
|
267
|
+
// src/core/identity.ts
|
|
268
|
+
var identity_exports = {};
|
|
269
|
+
__export(identity_exports, {
|
|
270
|
+
createIdentity: () => createIdentity,
|
|
271
|
+
generateIdentityId: () => generateIdentityId,
|
|
272
|
+
generateKeypair: () => generateKeypair,
|
|
273
|
+
publicKeyToDid: () => publicKeyToDid,
|
|
274
|
+
rotateKeys: () => rotateKeys,
|
|
275
|
+
sign: () => sign,
|
|
276
|
+
verify: () => verify
|
|
277
|
+
});
|
|
278
|
+
function generateKeypair() {
|
|
279
|
+
const privateKey = randomBytes(32);
|
|
280
|
+
const publicKey = ed25519.ed25519.getPublicKey(privateKey);
|
|
281
|
+
return { publicKey, privateKey };
|
|
282
|
+
}
|
|
283
|
+
function publicKeyToDid(publicKey) {
|
|
284
|
+
const multicodec = new Uint8Array([237, 1, ...publicKey]);
|
|
285
|
+
return `did:key:z${toBase64url(multicodec)}`;
|
|
286
|
+
}
|
|
287
|
+
function generateIdentityId(publicKey) {
|
|
288
|
+
const keyHash = hash(publicKey);
|
|
289
|
+
return Array.from(keyHash.slice(0, 16)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
290
|
+
}
|
|
291
|
+
function createIdentity(label, encryptionKey, keyProtection) {
|
|
292
|
+
const { publicKey, privateKey } = generateKeypair();
|
|
293
|
+
const identityId = generateIdentityId(publicKey);
|
|
294
|
+
const did = publicKeyToDid(publicKey);
|
|
295
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
296
|
+
const encryptedPrivateKey = encrypt(privateKey, encryptionKey);
|
|
297
|
+
privateKey.fill(0);
|
|
298
|
+
const publicIdentity = {
|
|
299
|
+
identity_id: identityId,
|
|
300
|
+
label,
|
|
301
|
+
public_key: toBase64url(publicKey),
|
|
302
|
+
did,
|
|
303
|
+
created_at: now,
|
|
304
|
+
key_type: "ed25519",
|
|
305
|
+
key_protection: keyProtection
|
|
306
|
+
};
|
|
307
|
+
const storedIdentity = {
|
|
308
|
+
...publicIdentity,
|
|
309
|
+
encrypted_private_key: encryptedPrivateKey,
|
|
310
|
+
rotation_history: []
|
|
311
|
+
};
|
|
312
|
+
return { publicIdentity, storedIdentity };
|
|
313
|
+
}
|
|
314
|
+
function sign(payload, encryptedPrivateKey, encryptionKey) {
|
|
315
|
+
const privateKey = decrypt(encryptedPrivateKey, encryptionKey);
|
|
316
|
+
try {
|
|
317
|
+
return ed25519.ed25519.sign(payload, privateKey);
|
|
318
|
+
} finally {
|
|
319
|
+
privateKey.fill(0);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
function verify(payload, signature, publicKey) {
|
|
323
|
+
try {
|
|
324
|
+
return ed25519.ed25519.verify(signature, payload, publicKey);
|
|
325
|
+
} catch {
|
|
326
|
+
return false;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
function rotateKeys(storedIdentity, encryptionKey, reason) {
|
|
330
|
+
const { publicKey: newPublicKey, privateKey: newPrivateKey } = generateKeypair();
|
|
331
|
+
const newIdentityDid = publicKeyToDid(newPublicKey);
|
|
332
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
333
|
+
const eventData = JSON.stringify({
|
|
334
|
+
old_public_key: storedIdentity.public_key,
|
|
335
|
+
new_public_key: toBase64url(newPublicKey),
|
|
336
|
+
identity_id: storedIdentity.identity_id,
|
|
337
|
+
reason,
|
|
338
|
+
rotated_at: now
|
|
339
|
+
});
|
|
340
|
+
const eventBytes = new TextEncoder().encode(eventData);
|
|
341
|
+
const signature = sign(
|
|
342
|
+
eventBytes,
|
|
343
|
+
storedIdentity.encrypted_private_key,
|
|
344
|
+
encryptionKey
|
|
345
|
+
);
|
|
346
|
+
const rotationEvent = {
|
|
347
|
+
old_public_key: storedIdentity.public_key,
|
|
348
|
+
new_public_key: toBase64url(newPublicKey),
|
|
349
|
+
identity_id: storedIdentity.identity_id,
|
|
350
|
+
reason,
|
|
351
|
+
rotated_at: now,
|
|
352
|
+
signature: toBase64url(signature)
|
|
353
|
+
};
|
|
354
|
+
const encryptedNewPrivateKey = encrypt(newPrivateKey, encryptionKey);
|
|
355
|
+
newPrivateKey.fill(0);
|
|
356
|
+
const updatedIdentity = {
|
|
357
|
+
...storedIdentity,
|
|
358
|
+
public_key: toBase64url(newPublicKey),
|
|
359
|
+
did: newIdentityDid,
|
|
360
|
+
encrypted_private_key: encryptedNewPrivateKey,
|
|
361
|
+
rotation_history: [
|
|
362
|
+
...storedIdentity.rotation_history,
|
|
363
|
+
{
|
|
364
|
+
old_public_key: storedIdentity.public_key,
|
|
365
|
+
new_public_key: toBase64url(newPublicKey),
|
|
366
|
+
rotation_event: toBase64url(
|
|
367
|
+
new TextEncoder().encode(JSON.stringify(rotationEvent))
|
|
368
|
+
),
|
|
369
|
+
rotated_at: now
|
|
370
|
+
}
|
|
371
|
+
]
|
|
372
|
+
};
|
|
373
|
+
return { updatedIdentity, rotationEvent };
|
|
374
|
+
}
|
|
375
|
+
var init_identity = __esm({
|
|
376
|
+
"src/core/identity.ts"() {
|
|
377
|
+
init_encoding();
|
|
378
|
+
init_encryption();
|
|
379
|
+
init_hashing();
|
|
380
|
+
init_random();
|
|
381
|
+
}
|
|
382
|
+
});
|
|
210
383
|
var require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
211
384
|
var { version: PKG_VERSION } = require2("../package.json");
|
|
212
385
|
var SANCTUARY_VERSION = PKG_VERSION;
|
|
@@ -384,24 +557,9 @@ function deepMerge(base, override) {
|
|
|
384
557
|
}
|
|
385
558
|
return result;
|
|
386
559
|
}
|
|
387
|
-
function randomBytes(length) {
|
|
388
|
-
if (length <= 0) {
|
|
389
|
-
throw new RangeError("Length must be positive");
|
|
390
|
-
}
|
|
391
|
-
const buf = crypto.randomBytes(length);
|
|
392
|
-
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
393
|
-
}
|
|
394
|
-
function generateIV() {
|
|
395
|
-
return randomBytes(12);
|
|
396
|
-
}
|
|
397
|
-
function generateSalt() {
|
|
398
|
-
return randomBytes(32);
|
|
399
|
-
}
|
|
400
|
-
function generateRandomKey() {
|
|
401
|
-
return randomBytes(32);
|
|
402
|
-
}
|
|
403
560
|
|
|
404
561
|
// src/storage/filesystem.ts
|
|
562
|
+
init_random();
|
|
405
563
|
var FilesystemStorage = class {
|
|
406
564
|
basePath;
|
|
407
565
|
constructor(basePath) {
|
|
@@ -509,141 +667,14 @@ var FilesystemStorage = class {
|
|
|
509
667
|
return total;
|
|
510
668
|
}
|
|
511
669
|
};
|
|
512
|
-
init_encoding();
|
|
513
|
-
function encrypt(plaintext, key, aad) {
|
|
514
|
-
if (key.length !== 32) {
|
|
515
|
-
throw new Error("Key must be exactly 32 bytes (256 bits)");
|
|
516
|
-
}
|
|
517
|
-
const iv = generateIV();
|
|
518
|
-
const cipher = aes_js.gcm(key, iv, aad);
|
|
519
|
-
const ciphertext = cipher.encrypt(plaintext);
|
|
520
|
-
return {
|
|
521
|
-
v: 1,
|
|
522
|
-
alg: "aes-256-gcm",
|
|
523
|
-
iv: toBase64url(iv),
|
|
524
|
-
ct: toBase64url(ciphertext),
|
|
525
|
-
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
526
|
-
};
|
|
527
|
-
}
|
|
528
|
-
function decrypt(payload, key, aad) {
|
|
529
|
-
if (key.length !== 32) {
|
|
530
|
-
throw new Error("Key must be exactly 32 bytes (256 bits)");
|
|
531
|
-
}
|
|
532
|
-
if (payload.v !== 1) {
|
|
533
|
-
throw new Error(`Unsupported payload version: ${payload.v}`);
|
|
534
|
-
}
|
|
535
|
-
if (payload.alg !== "aes-256-gcm") {
|
|
536
|
-
throw new Error(`Unsupported algorithm: ${payload.alg}`);
|
|
537
|
-
}
|
|
538
|
-
const iv = fromBase64url(payload.iv);
|
|
539
|
-
const ciphertext = fromBase64url(payload.ct);
|
|
540
|
-
const cipher = aes_js.gcm(key, iv, aad);
|
|
541
|
-
return cipher.decrypt(ciphertext);
|
|
542
|
-
}
|
|
543
670
|
|
|
544
671
|
// src/l1-cognitive/state-store.ts
|
|
672
|
+
init_encryption();
|
|
545
673
|
init_hashing();
|
|
674
|
+
init_identity();
|
|
546
675
|
|
|
547
|
-
// src/core/
|
|
548
|
-
|
|
549
|
-
init_hashing();
|
|
550
|
-
function generateKeypair() {
|
|
551
|
-
const privateKey = randomBytes(32);
|
|
552
|
-
const publicKey = ed25519.ed25519.getPublicKey(privateKey);
|
|
553
|
-
return { publicKey, privateKey };
|
|
554
|
-
}
|
|
555
|
-
function publicKeyToDid(publicKey) {
|
|
556
|
-
const multicodec = new Uint8Array([237, 1, ...publicKey]);
|
|
557
|
-
return `did:key:z${toBase64url(multicodec)}`;
|
|
558
|
-
}
|
|
559
|
-
function generateIdentityId(publicKey) {
|
|
560
|
-
const keyHash = hash(publicKey);
|
|
561
|
-
return Array.from(keyHash.slice(0, 16)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
562
|
-
}
|
|
563
|
-
function createIdentity(label, encryptionKey, keyProtection) {
|
|
564
|
-
const { publicKey, privateKey } = generateKeypair();
|
|
565
|
-
const identityId = generateIdentityId(publicKey);
|
|
566
|
-
const did = publicKeyToDid(publicKey);
|
|
567
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
568
|
-
const encryptedPrivateKey = encrypt(privateKey, encryptionKey);
|
|
569
|
-
privateKey.fill(0);
|
|
570
|
-
const publicIdentity = {
|
|
571
|
-
identity_id: identityId,
|
|
572
|
-
label,
|
|
573
|
-
public_key: toBase64url(publicKey),
|
|
574
|
-
did,
|
|
575
|
-
created_at: now,
|
|
576
|
-
key_type: "ed25519",
|
|
577
|
-
key_protection: keyProtection
|
|
578
|
-
};
|
|
579
|
-
const storedIdentity = {
|
|
580
|
-
...publicIdentity,
|
|
581
|
-
encrypted_private_key: encryptedPrivateKey,
|
|
582
|
-
rotation_history: []
|
|
583
|
-
};
|
|
584
|
-
return { publicIdentity, storedIdentity };
|
|
585
|
-
}
|
|
586
|
-
function sign(payload, encryptedPrivateKey, encryptionKey) {
|
|
587
|
-
const privateKey = decrypt(encryptedPrivateKey, encryptionKey);
|
|
588
|
-
try {
|
|
589
|
-
return ed25519.ed25519.sign(payload, privateKey);
|
|
590
|
-
} finally {
|
|
591
|
-
privateKey.fill(0);
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
function verify(payload, signature, publicKey) {
|
|
595
|
-
try {
|
|
596
|
-
return ed25519.ed25519.verify(signature, payload, publicKey);
|
|
597
|
-
} catch {
|
|
598
|
-
return false;
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
function rotateKeys(storedIdentity, encryptionKey, reason) {
|
|
602
|
-
const { publicKey: newPublicKey, privateKey: newPrivateKey } = generateKeypair();
|
|
603
|
-
const newIdentityDid = publicKeyToDid(newPublicKey);
|
|
604
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
605
|
-
const eventData = JSON.stringify({
|
|
606
|
-
old_public_key: storedIdentity.public_key,
|
|
607
|
-
new_public_key: toBase64url(newPublicKey),
|
|
608
|
-
identity_id: storedIdentity.identity_id,
|
|
609
|
-
reason,
|
|
610
|
-
rotated_at: now
|
|
611
|
-
});
|
|
612
|
-
const eventBytes = new TextEncoder().encode(eventData);
|
|
613
|
-
const signature = sign(
|
|
614
|
-
eventBytes,
|
|
615
|
-
storedIdentity.encrypted_private_key,
|
|
616
|
-
encryptionKey
|
|
617
|
-
);
|
|
618
|
-
const rotationEvent = {
|
|
619
|
-
old_public_key: storedIdentity.public_key,
|
|
620
|
-
new_public_key: toBase64url(newPublicKey),
|
|
621
|
-
identity_id: storedIdentity.identity_id,
|
|
622
|
-
reason,
|
|
623
|
-
rotated_at: now,
|
|
624
|
-
signature: toBase64url(signature)
|
|
625
|
-
};
|
|
626
|
-
const encryptedNewPrivateKey = encrypt(newPrivateKey, encryptionKey);
|
|
627
|
-
newPrivateKey.fill(0);
|
|
628
|
-
const updatedIdentity = {
|
|
629
|
-
...storedIdentity,
|
|
630
|
-
public_key: toBase64url(newPublicKey),
|
|
631
|
-
did: newIdentityDid,
|
|
632
|
-
encrypted_private_key: encryptedNewPrivateKey,
|
|
633
|
-
rotation_history: [
|
|
634
|
-
...storedIdentity.rotation_history,
|
|
635
|
-
{
|
|
636
|
-
old_public_key: storedIdentity.public_key,
|
|
637
|
-
new_public_key: toBase64url(newPublicKey),
|
|
638
|
-
rotation_event: toBase64url(
|
|
639
|
-
new TextEncoder().encode(JSON.stringify(rotationEvent))
|
|
640
|
-
),
|
|
641
|
-
rotated_at: now
|
|
642
|
-
}
|
|
643
|
-
]
|
|
644
|
-
};
|
|
645
|
-
return { updatedIdentity, rotationEvent };
|
|
646
|
-
}
|
|
676
|
+
// src/core/key-derivation.ts
|
|
677
|
+
init_random();
|
|
647
678
|
init_encoding();
|
|
648
679
|
var ARGON2_MEMORY_COST = 65536;
|
|
649
680
|
var ARGON2_TIME_COST = 3;
|
|
@@ -1241,7 +1272,9 @@ function toolResult(data) {
|
|
|
1241
1272
|
}
|
|
1242
1273
|
|
|
1243
1274
|
// src/l1-cognitive/tools.ts
|
|
1275
|
+
init_identity();
|
|
1244
1276
|
init_encoding();
|
|
1277
|
+
init_encryption();
|
|
1245
1278
|
init_encoding();
|
|
1246
1279
|
var RESERVED_NAMESPACE_PREFIXES2 = [
|
|
1247
1280
|
"_identities",
|
|
@@ -1278,9 +1311,13 @@ var IdentityManager = class {
|
|
|
1278
1311
|
get encryptionKey() {
|
|
1279
1312
|
return derivePurposeKey(this.masterKey, "identity-encryption");
|
|
1280
1313
|
}
|
|
1281
|
-
/** Load identities from storage on startup
|
|
1314
|
+
/** Load identities from storage on startup.
|
|
1315
|
+
* Returns { total: number of encrypted files found, loaded: number successfully decrypted }.
|
|
1316
|
+
* A mismatch (total > 0, loaded === 0) indicates a wrong master key / missing passphrase.
|
|
1317
|
+
*/
|
|
1282
1318
|
async load() {
|
|
1283
1319
|
const entries = await this.storage.list("_identities");
|
|
1320
|
+
let failed = 0;
|
|
1284
1321
|
for (const entry of entries) {
|
|
1285
1322
|
const raw = await this.storage.read("_identities", entry.key);
|
|
1286
1323
|
if (!raw) continue;
|
|
@@ -1293,8 +1330,10 @@ var IdentityManager = class {
|
|
|
1293
1330
|
this.primaryIdentityId = identity.identity_id;
|
|
1294
1331
|
}
|
|
1295
1332
|
} catch {
|
|
1333
|
+
failed++;
|
|
1296
1334
|
}
|
|
1297
1335
|
}
|
|
1336
|
+
return { total: entries.length, loaded: this.identities.size, failed };
|
|
1298
1337
|
}
|
|
1299
1338
|
/** Save an identity to storage */
|
|
1300
1339
|
async save(identity) {
|
|
@@ -1742,6 +1781,7 @@ function createL1Tools(stateStore, storage, masterKey, keyProtection, auditLog)
|
|
|
1742
1781
|
}
|
|
1743
1782
|
|
|
1744
1783
|
// src/l2-operational/audit-log.ts
|
|
1784
|
+
init_encryption();
|
|
1745
1785
|
init_encoding();
|
|
1746
1786
|
var AuditLog = class {
|
|
1747
1787
|
storage;
|
|
@@ -1839,6 +1879,8 @@ var AuditLog = class {
|
|
|
1839
1879
|
// src/l3-disclosure/commitments.ts
|
|
1840
1880
|
init_hashing();
|
|
1841
1881
|
init_encoding();
|
|
1882
|
+
init_random();
|
|
1883
|
+
init_encryption();
|
|
1842
1884
|
init_encoding();
|
|
1843
1885
|
function createCommitment(value, blindingFactor) {
|
|
1844
1886
|
const blindingBytes = blindingFactor ? fromBase64url(blindingFactor) : randomBytes(32);
|
|
@@ -1919,7 +1961,9 @@ var CommitmentStore = class {
|
|
|
1919
1961
|
};
|
|
1920
1962
|
|
|
1921
1963
|
// src/l3-disclosure/policies.ts
|
|
1964
|
+
init_encryption();
|
|
1922
1965
|
init_encoding();
|
|
1966
|
+
init_random();
|
|
1923
1967
|
function evaluateDisclosure(policy, context, requestedFields) {
|
|
1924
1968
|
return requestedFields.map((field) => {
|
|
1925
1969
|
const exactRule = policy.rules.find((r) => r.context === context);
|
|
@@ -2050,6 +2094,9 @@ var PolicyStore = class {
|
|
|
2050
2094
|
);
|
|
2051
2095
|
}
|
|
2052
2096
|
};
|
|
2097
|
+
|
|
2098
|
+
// src/l3-disclosure/zk-proofs.ts
|
|
2099
|
+
init_random();
|
|
2053
2100
|
init_encoding();
|
|
2054
2101
|
var G = ed25519.RistrettoPoint.BASE;
|
|
2055
2102
|
var H_INPUT = concatBytes(
|
|
@@ -2727,7 +2774,10 @@ function createL3Tools(storage, masterKey, auditLog) {
|
|
|
2727
2774
|
}
|
|
2728
2775
|
|
|
2729
2776
|
// src/l4-reputation/reputation-store.ts
|
|
2777
|
+
init_encryption();
|
|
2730
2778
|
init_encoding();
|
|
2779
|
+
init_random();
|
|
2780
|
+
init_identity();
|
|
2731
2781
|
function computeMedian(values) {
|
|
2732
2782
|
if (values.length === 0) return 0;
|
|
2733
2783
|
const sorted = [...values].sort((a, b) => a - b);
|
|
@@ -3622,6 +3672,24 @@ function createL4Tools(storage, masterKey, identityManager, auditLog, handshakeR
|
|
|
3622
3672
|
}
|
|
3623
3673
|
const publishType = args.type;
|
|
3624
3674
|
const veracoreUrl = args.verascore_url || "https://verascore.ai";
|
|
3675
|
+
const ALLOWED_VERASCORE_HOSTS = ["verascore.ai", "www.verascore.ai", "api.verascore.ai"];
|
|
3676
|
+
try {
|
|
3677
|
+
const parsed = new URL(veracoreUrl);
|
|
3678
|
+
if (parsed.protocol !== "https:") {
|
|
3679
|
+
return toolResult({
|
|
3680
|
+
error: `verascore_url must use HTTPS. Got: ${parsed.protocol}`
|
|
3681
|
+
});
|
|
3682
|
+
}
|
|
3683
|
+
if (!ALLOWED_VERASCORE_HOSTS.includes(parsed.hostname)) {
|
|
3684
|
+
return toolResult({
|
|
3685
|
+
error: `verascore_url must point to a known Verascore domain (${ALLOWED_VERASCORE_HOSTS.join(", ")}). Got: ${parsed.hostname}`
|
|
3686
|
+
});
|
|
3687
|
+
}
|
|
3688
|
+
} catch {
|
|
3689
|
+
return toolResult({
|
|
3690
|
+
error: `verascore_url is not a valid URL: ${veracoreUrl}`
|
|
3691
|
+
});
|
|
3692
|
+
}
|
|
3625
3693
|
const agentId = args.verascore_agent_id || identity.did.replace(/[^a-zA-Z0-9-]/g, "-").toLowerCase();
|
|
3626
3694
|
let publishData;
|
|
3627
3695
|
if (args.data) {
|
|
@@ -3651,24 +3719,21 @@ function createL4Tools(storage, masterKey, identityManager, auditLog, handshakeR
|
|
|
3651
3719
|
return toolResult({ error: `Unknown publish type: ${publishType}` });
|
|
3652
3720
|
}
|
|
3653
3721
|
}
|
|
3654
|
-
const { sign:
|
|
3655
|
-
const payloadBytes =
|
|
3722
|
+
const { sign: identitySign } = await Promise.resolve().then(() => (init_identity(), identity_exports));
|
|
3723
|
+
const payloadBytes = new TextEncoder().encode(JSON.stringify(publishData));
|
|
3656
3724
|
let signatureB64;
|
|
3657
3725
|
try {
|
|
3658
|
-
const
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
]),
|
|
3665
|
-
format: "der",
|
|
3666
|
-
type: "pkcs8"
|
|
3667
|
-
});
|
|
3668
|
-
const sig = sign2(null, payloadBytes, privateKey);
|
|
3669
|
-
signatureB64 = sig.toString("base64url");
|
|
3726
|
+
const signingBytes = identitySign(
|
|
3727
|
+
payloadBytes,
|
|
3728
|
+
identity.encrypted_private_key,
|
|
3729
|
+
identityEncryptionKey
|
|
3730
|
+
);
|
|
3731
|
+
signatureB64 = toBase64url(signingBytes);
|
|
3670
3732
|
} catch (signError) {
|
|
3671
|
-
|
|
3733
|
+
return toolResult({
|
|
3734
|
+
error: "Failed to sign publish payload. Identity key may be corrupted.",
|
|
3735
|
+
details: signError instanceof Error ? signError.message : String(signError)
|
|
3736
|
+
});
|
|
3672
3737
|
}
|
|
3673
3738
|
const requestBody = {
|
|
3674
3739
|
agentId,
|
|
@@ -3747,7 +3812,9 @@ var DEFAULT_POLICY = {
|
|
|
3747
3812
|
"reputation_import",
|
|
3748
3813
|
"reputation_export",
|
|
3749
3814
|
"bootstrap_provide_guarantee",
|
|
3750
|
-
"decommission_certificate"
|
|
3815
|
+
"decommission_certificate",
|
|
3816
|
+
"reputation_publish"
|
|
3817
|
+
// SEC-039: Explicit Tier 1 — sends data to external API
|
|
3751
3818
|
],
|
|
3752
3819
|
tier2_anomaly: DEFAULT_TIER2,
|
|
3753
3820
|
tier3_always_allow: [
|
|
@@ -3799,7 +3866,9 @@ var DEFAULT_POLICY = {
|
|
|
3799
3866
|
"shr_gateway_export",
|
|
3800
3867
|
"bridge_commit",
|
|
3801
3868
|
"bridge_verify",
|
|
3802
|
-
"bridge_attest"
|
|
3869
|
+
"bridge_attest",
|
|
3870
|
+
"dashboard_open"
|
|
3871
|
+
// SEC-039: Explicit Tier 3 — only generates a URL
|
|
3803
3872
|
],
|
|
3804
3873
|
approval_channel: DEFAULT_CHANNEL
|
|
3805
3874
|
};
|
|
@@ -3907,6 +3976,7 @@ tier1_always_approve:
|
|
|
3907
3976
|
- reputation_import
|
|
3908
3977
|
- reputation_export
|
|
3909
3978
|
- bootstrap_provide_guarantee
|
|
3979
|
+
- reputation_publish
|
|
3910
3980
|
|
|
3911
3981
|
# \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
|
|
3912
3982
|
# Triggers approval when agent behavior deviates from its baseline.
|
|
@@ -3969,6 +4039,7 @@ tier3_always_allow:
|
|
|
3969
4039
|
- bridge_commit
|
|
3970
4040
|
- bridge_verify
|
|
3971
4041
|
- bridge_attest
|
|
4042
|
+
- dashboard_open
|
|
3972
4043
|
|
|
3973
4044
|
# \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
|
|
3974
4045
|
# How Sanctuary reaches you when approval is needed.
|
|
@@ -3996,6 +4067,7 @@ async function loadPrincipalPolicy(storagePath) {
|
|
|
3996
4067
|
}
|
|
3997
4068
|
|
|
3998
4069
|
// src/principal-policy/baseline.ts
|
|
4070
|
+
init_encryption();
|
|
3999
4071
|
init_encoding();
|
|
4000
4072
|
var BASELINE_NAMESPACE = "_principal";
|
|
4001
4073
|
var BASELINE_KEY = "session-baseline";
|
|
@@ -4221,6 +4293,7 @@ function canonicalizeForSigning(body) {
|
|
|
4221
4293
|
}
|
|
4222
4294
|
|
|
4223
4295
|
// src/shr/generator.ts
|
|
4296
|
+
init_identity();
|
|
4224
4297
|
init_encoding();
|
|
4225
4298
|
var DEFAULT_VALIDITY_MS = 60 * 60 * 1e3;
|
|
4226
4299
|
function generateSHR(identityId, opts) {
|
|
@@ -5601,7 +5674,9 @@ function generateDashboardHTML(options) {
|
|
|
5601
5674
|
|
|
5602
5675
|
<script>
|
|
5603
5676
|
// Constants
|
|
5604
|
-
|
|
5677
|
+
// SEC-038: Do NOT embed the long-lived auth token in page source.
|
|
5678
|
+
// Use only the session token stored in sessionStorage by the login flow.
|
|
5679
|
+
const AUTH_TOKEN = sessionStorage.getItem('authToken') || '';
|
|
5605
5680
|
const TIMEOUT_SECONDS = ${options.timeoutSeconds};
|
|
5606
5681
|
const API_BASE = '';
|
|
5607
5682
|
|
|
@@ -8114,6 +8189,7 @@ function createPrincipalPolicyTools(policy, baseline, auditLog) {
|
|
|
8114
8189
|
}
|
|
8115
8190
|
|
|
8116
8191
|
// src/shr/verifier.ts
|
|
8192
|
+
init_identity();
|
|
8117
8193
|
init_encoding();
|
|
8118
8194
|
function verifySHR(shr, now) {
|
|
8119
8195
|
const errors = [];
|
|
@@ -8536,7 +8612,9 @@ function createSHRTools(config, identityManager, masterKey, auditLog) {
|
|
|
8536
8612
|
}
|
|
8537
8613
|
|
|
8538
8614
|
// src/handshake/protocol.ts
|
|
8615
|
+
init_identity();
|
|
8539
8616
|
init_encoding();
|
|
8617
|
+
init_random();
|
|
8540
8618
|
function generateNonce() {
|
|
8541
8619
|
return toBase64url(randomBytes(32));
|
|
8542
8620
|
}
|
|
@@ -8703,7 +8781,9 @@ function deriveTrustTier(level) {
|
|
|
8703
8781
|
}
|
|
8704
8782
|
|
|
8705
8783
|
// src/handshake/attestation.ts
|
|
8784
|
+
init_identity();
|
|
8706
8785
|
init_encoding();
|
|
8786
|
+
init_identity();
|
|
8707
8787
|
init_encoding();
|
|
8708
8788
|
var ATTESTATION_VERSION = "1.0";
|
|
8709
8789
|
function deriveTrustTier2(level) {
|
|
@@ -9496,10 +9576,13 @@ function createFederationTools(auditLog, handshakeResults) {
|
|
|
9496
9576
|
|
|
9497
9577
|
// src/bridge/tools.ts
|
|
9498
9578
|
init_encoding();
|
|
9579
|
+
init_encryption();
|
|
9499
9580
|
init_encoding();
|
|
9500
9581
|
|
|
9501
9582
|
// src/bridge/bridge.ts
|
|
9583
|
+
init_identity();
|
|
9502
9584
|
init_encoding();
|
|
9585
|
+
init_random();
|
|
9503
9586
|
init_hashing();
|
|
9504
9587
|
function canonicalize(outcome) {
|
|
9505
9588
|
return stringToBytes(stableStringify(outcome));
|
|
@@ -10650,7 +10733,9 @@ function createAuditTools(config) {
|
|
|
10650
10733
|
}
|
|
10651
10734
|
|
|
10652
10735
|
// src/l2-operational/context-gate.ts
|
|
10736
|
+
init_encryption();
|
|
10653
10737
|
init_encoding();
|
|
10738
|
+
init_random();
|
|
10654
10739
|
init_hashing();
|
|
10655
10740
|
var MAX_CONTEXT_FIELDS = 1e3;
|
|
10656
10741
|
var MAX_POLICY_RULES = 50;
|
|
@@ -12620,6 +12705,7 @@ function createL2HardeningTools(storagePath, auditLog) {
|
|
|
12620
12705
|
}
|
|
12621
12706
|
|
|
12622
12707
|
// src/index.ts
|
|
12708
|
+
init_random();
|
|
12623
12709
|
init_encoding();
|
|
12624
12710
|
|
|
12625
12711
|
// src/l2-operational/model-provenance.ts
|
|
@@ -12866,7 +12952,29 @@ async function createSanctuaryServer(options) {
|
|
|
12866
12952
|
keyProtection,
|
|
12867
12953
|
auditLog
|
|
12868
12954
|
);
|
|
12869
|
-
await identityManager.load();
|
|
12955
|
+
const loadResult = await identityManager.load();
|
|
12956
|
+
if (loadResult.total > 0 && loadResult.loaded === 0) {
|
|
12957
|
+
console.error(
|
|
12958
|
+
`
|
|
12959
|
+
\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
|
|
12960
|
+
\u2551 \u26A0 WARNING: Encrypted identities found but NONE loaded \u2551
|
|
12961
|
+
\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
|
|
12962
|
+
\u2551 ${loadResult.total} encrypted identity file(s) found on disk \u2551
|
|
12963
|
+
\u2551 0 could be decrypted with the current master key \u2551
|
|
12964
|
+
\u2551 \u2551
|
|
12965
|
+
\u2551 This usually means SANCTUARY_PASSPHRASE is missing or \u2551
|
|
12966
|
+
\u2551 incorrect. The server will start but with NO identity data. \u2551
|
|
12967
|
+
\u2551 \u2551
|
|
12968
|
+
\u2551 To fix: set SANCTUARY_PASSPHRASE to the passphrase used \u2551
|
|
12969
|
+
\u2551 when this Sanctuary instance was first configured. \u2551
|
|
12970
|
+
\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
|
|
12971
|
+
`
|
|
12972
|
+
);
|
|
12973
|
+
} else if (loadResult.failed > 0) {
|
|
12974
|
+
console.error(
|
|
12975
|
+
`Warning: ${loadResult.failed} of ${loadResult.total} identity files could not be decrypted (possibly corrupted).`
|
|
12976
|
+
);
|
|
12977
|
+
}
|
|
12870
12978
|
const l2Tools = [
|
|
12871
12979
|
{
|
|
12872
12980
|
name: "sanctuary/exec_attest",
|