@suveren/gateway 0.7.3 → 0.7.6
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/content/integrations/gmail.json +3 -6
- package/dist/control-plane/index.mjs +294 -62
- package/dist/mcp-server/http.mjs +467 -73
- package/dist/ui/assets/{index-CkWaRck1.css → index-BYVb_0oG.css} +1 -1
- package/dist/ui/assets/index-CsrM6RQr.js +110 -0
- package/dist/ui/index.html +2 -2
- package/node_modules/@hap/core/dist/index.d.mts +258 -9
- package/node_modules/@hap/core/dist/index.d.ts +258 -9
- package/node_modules/@hap/core/dist/index.js +227 -5
- package/node_modules/@hap/core/dist/index.mjs +213 -4
- package/node_modules/@hap/core/package.json +3 -2
- package/node_modules/@hap/core/src/did-key.ts +126 -0
- package/node_modules/@hap/core/src/identity.ts +21 -5
- package/node_modules/@hap/core/src/index.ts +3 -0
- package/node_modules/@hap/core/src/mandate.ts +207 -0
- package/node_modules/@hap/core/src/receipt.ts +74 -0
- package/node_modules/@hap/core/src/types.ts +81 -5
- package/node_modules/@hono/node-server/dist/index.cjs +151 -9
- package/node_modules/@hono/node-server/dist/index.mjs +151 -9
- package/node_modules/@hono/node-server/package.json +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/node_modules/content-type/README.md +2 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/node_modules/content-type/dist/index.d.ts +20 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/node_modules/content-type/dist/index.js +20 -14
- package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/node_modules/content-type/dist/index.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/node_modules/content-type/package.json +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/lib/accept.js +54 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/lib/charset.js +10 -34
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/lib/encoding.js +9 -30
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/lib/language.js +15 -36
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/lib/mediaType.js +16 -134
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/node_modules/content-type/LICENSE +22 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/node_modules/content-type/README.md +71 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/node_modules/content-type/dist/index.d.ts +46 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/node_modules/content-type/dist/index.js +176 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/node_modules/content-type/dist/index.js.map +1 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/node_modules/content-type/package.json +52 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/package.json +16 -10
- package/node_modules/@modelcontextprotocol/sdk/node_modules/type-is/node_modules/content-type/README.md +2 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/type-is/node_modules/content-type/dist/index.d.ts +20 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/type-is/node_modules/content-type/dist/index.js +20 -14
- package/node_modules/@modelcontextprotocol/sdk/node_modules/type-is/node_modules/content-type/dist/index.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/type-is/node_modules/content-type/package.json +1 -1
- package/node_modules/@types/node/README.md +1 -1
- package/node_modules/@types/node/buffer.buffer.d.ts +5 -5
- package/node_modules/@types/node/crypto.d.ts +2 -2
- package/node_modules/@types/node/http.d.ts +16 -0
- package/node_modules/@types/node/http2.d.ts +10 -2
- package/node_modules/@types/node/package.json +2 -2
- package/node_modules/@types/node/process.d.ts +52 -0
- package/node_modules/@types/node/quic.d.ts +210 -28
- package/node_modules/@types/node/sqlite.d.ts +6 -2
- package/node_modules/@types/node/test.d.ts +36 -0
- package/node_modules/eventsource-parser/dist/index.cjs +2 -2
- package/node_modules/eventsource-parser/dist/index.cjs.map +1 -1
- package/node_modules/eventsource-parser/dist/index.js +2 -2
- package/node_modules/eventsource-parser/dist/index.js.map +1 -1
- package/node_modules/eventsource-parser/package.json +1 -1
- package/node_modules/eventsource-parser/src/parse.ts +4 -2
- package/node_modules/fast-uri/index.js +201 -48
- package/node_modules/fast-uri/lib/schemes.js +9 -4
- package/node_modules/fast-uri/lib/utils.js +388 -91
- package/node_modules/fast-uri/package.json +1 -1
- package/node_modules/fast-uri/test/component-safe-serialization.test.js +105 -0
- package/node_modules/fast-uri/test/equal.test.js +31 -3
- package/node_modules/fast-uri/test/fixtures/uri-js-parse.json +2 -0
- package/node_modules/fast-uri/test/ipv6-canonical.test.js +34 -0
- package/node_modules/fast-uri/test/ipv6-validation.test.js +90 -0
- package/node_modules/fast-uri/test/malformed-percent.test.js +77 -0
- package/node_modules/fast-uri/test/malformed-urn.test.js +61 -0
- package/node_modules/fast-uri/test/parse.test.js +7 -3
- package/node_modules/fast-uri/test/query-fragment-normalization.test.js +33 -0
- package/node_modules/fast-uri/test/reserved-path-normalization.test.js +109 -0
- package/node_modules/fast-uri/test/scheme-validation.test.js +124 -0
- package/node_modules/fast-uri/test/security-normalization.test.js +101 -0
- package/node_modules/fast-uri/test/security.test.js +75 -3
- package/node_modules/fast-uri/test/urn-full-input.test.js +29 -0
- package/node_modules/fast-uri/test/websocket-query-preservation.test.js +24 -0
- package/node_modules/hono/dist/cjs/client/client.js +27 -13
- package/node_modules/hono/dist/cjs/client/utils.js +4 -1
- package/node_modules/hono/dist/cjs/context.js +4 -0
- package/node_modules/hono/dist/cjs/helper/accepts/accepts.js +36 -2
- package/node_modules/hono/dist/cjs/helper/ssg/ssg.js +1 -1
- package/node_modules/hono/dist/cjs/helper/ssg/utils.js +30 -10
- package/node_modules/hono/dist/cjs/jsx/dom/render.js +2 -0
- package/node_modules/hono/dist/cjs/jsx/intrinsic-element/components.js +1 -1
- package/node_modules/hono/dist/cjs/middleware/cache/index.js +1 -1
- package/node_modules/hono/dist/cjs/middleware/cors/index.js +16 -13
- package/node_modules/hono/dist/cjs/middleware/csrf/index.js +1 -1
- package/node_modules/hono/dist/cjs/middleware/etag/digest.js +47 -1
- package/node_modules/hono/dist/cjs/middleware/etag/index.js +3 -3
- package/node_modules/hono/dist/cjs/middleware/pretty-json/index.js +3 -1
- package/node_modules/hono/dist/cjs/middleware/secure-headers/secure-headers.js +6 -3
- package/node_modules/hono/dist/cjs/request.js +8 -4
- package/node_modules/hono/dist/cjs/router/linear-router/router.js +7 -2
- package/node_modules/hono/dist/cjs/router/pattern-router/router.js +3 -9
- package/node_modules/hono/dist/cjs/router/reg-exp-router/node.js +10 -3
- package/node_modules/hono/dist/cjs/router/reg-exp-router/router.js +47 -83
- package/node_modules/hono/dist/cjs/router/reg-exp-router/trie.js +2 -1
- package/node_modules/hono/dist/cjs/router/trie-router/node.js +46 -69
- package/node_modules/hono/dist/cjs/router/trie-router/router.js +3 -11
- package/node_modules/hono/dist/cjs/router/utils.js +27 -0
- package/node_modules/hono/dist/cjs/utils/body.js +15 -3
- package/node_modules/hono/dist/cjs/utils/cookie.js +1 -1
- package/node_modules/hono/dist/cjs/utils/ipaddr.js +5 -3
- package/node_modules/hono/dist/cjs/utils/stream.js +7 -1
- package/node_modules/hono/dist/cjs/utils/url.js +11 -3
- package/node_modules/hono/dist/client/client.js +27 -13
- package/node_modules/hono/dist/client/utils.js +4 -1
- package/node_modules/hono/dist/context.js +4 -0
- package/node_modules/hono/dist/helper/accepts/accepts.js +36 -2
- package/node_modules/hono/dist/helper/ssg/ssg.js +1 -1
- package/node_modules/hono/dist/helper/ssg/utils.js +30 -10
- package/node_modules/hono/dist/jsx/dom/render.js +2 -0
- package/node_modules/hono/dist/jsx/intrinsic-element/components.js +1 -1
- package/node_modules/hono/dist/middleware/cache/index.js +1 -1
- package/node_modules/hono/dist/middleware/cors/index.js +16 -13
- package/node_modules/hono/dist/middleware/csrf/index.js +1 -1
- package/node_modules/hono/dist/middleware/etag/digest.js +47 -1
- package/node_modules/hono/dist/middleware/etag/index.js +3 -3
- package/node_modules/hono/dist/middleware/pretty-json/index.js +3 -1
- package/node_modules/hono/dist/middleware/secure-headers/secure-headers.js +6 -3
- package/node_modules/hono/dist/request.js +8 -4
- package/node_modules/hono/dist/router/linear-router/router.js +7 -2
- package/node_modules/hono/dist/router/pattern-router/router.js +3 -9
- package/node_modules/hono/dist/router/reg-exp-router/node.js +6 -2
- package/node_modules/hono/dist/router/reg-exp-router/router.js +53 -84
- package/node_modules/hono/dist/router/reg-exp-router/trie.js +2 -1
- package/node_modules/hono/dist/router/trie-router/node.js +46 -69
- package/node_modules/hono/dist/router/trie-router/router.js +3 -11
- package/node_modules/hono/dist/router/utils.js +5 -0
- package/node_modules/hono/dist/types/context.d.ts +4 -0
- package/node_modules/hono/dist/types/middleware/secure-headers/permissions-policy.d.ts +3 -3
- package/node_modules/hono/dist/types/router/reg-exp-router/node.d.ts +3 -0
- package/node_modules/hono/dist/types/router/trie-router/node.d.ts +1 -2
- package/node_modules/hono/dist/types/router/trie-router/router.d.ts +0 -1
- package/node_modules/hono/dist/types/router/utils.d.ts +1 -0
- package/node_modules/hono/dist/types/utils/url.d.ts +4 -0
- package/node_modules/hono/dist/utils/body.js +15 -3
- package/node_modules/hono/dist/utils/cookie.js +1 -1
- package/node_modules/hono/dist/utils/ipaddr.js +5 -3
- package/node_modules/hono/dist/utils/stream.js +7 -1
- package/node_modules/hono/dist/utils/url.js +11 -3
- package/node_modules/hono/package.json +1 -1
- package/node_modules/ip-address/README.md +134 -134
- package/node_modules/ip-address/dist/address-error.d.ts +11 -0
- package/node_modules/ip-address/dist/address-error.js.map +1 -1
- package/node_modules/ip-address/dist/ipv4.d.ts +22 -6
- package/node_modules/ip-address/dist/ipv4.js +22 -6
- package/node_modules/ip-address/dist/ipv4.js.map +1 -1
- package/node_modules/ip-address/dist/ipv6.d.ts +10 -3
- package/node_modules/ip-address/dist/ipv6.js +26 -17
- package/node_modules/ip-address/dist/ipv6.js.map +1 -1
- package/node_modules/ip-address/package.json +1 -1
- package/node_modules/is-plain-object/README.md +39 -95
- package/node_modules/is-plain-object/dist/is-plain-object.js +0 -2
- package/node_modules/is-plain-object/is-plain-object.d.ts +6 -1
- package/node_modules/is-plain-object/package.json +8 -34
- package/node_modules/jose/dist/types/jwe/compact/encrypt.d.ts +4 -3
- package/node_modules/jose/dist/types/jwe/flattened/encrypt.d.ts +4 -3
- package/node_modules/jose/dist/types/jwe/general/encrypt.d.ts +4 -3
- package/node_modules/jose/dist/types/jwks/remote.d.ts +4 -4
- package/node_modules/jose/dist/types/jws/general/verify.d.ts +3 -3
- package/node_modules/jose/dist/types/jwt/encrypt.d.ts +12 -17
- package/node_modules/jose/dist/types/jwt/sign.d.ts +8 -14
- package/node_modules/jose/dist/types/jwt/unsecured.d.ts +9 -15
- package/node_modules/jose/dist/types/types.d.ts +4 -2
- package/node_modules/jose/dist/webapi/jwe/compact/encrypt.js +30 -8
- package/node_modules/jose/dist/webapi/jwe/flattened/decrypt.js +8 -4
- package/node_modules/jose/dist/webapi/jwe/flattened/encrypt.js +6 -13
- package/node_modules/jose/dist/webapi/jwe/general/decrypt.js +19 -19
- package/node_modules/jose/dist/webapi/jwe/general/encrypt.js +32 -21
- package/node_modules/jose/dist/webapi/jwk/embedded.js +15 -1
- package/node_modules/jose/dist/webapi/jwk/thumbprint.js +11 -5
- package/node_modules/jose/dist/webapi/jwks/local.js +45 -53
- package/node_modules/jose/dist/webapi/jwks/remote.js +82 -103
- package/node_modules/jose/dist/webapi/jws/compact/sign.js +10 -9
- package/node_modules/jose/dist/webapi/jws/flattened/sign.js +2 -1
- package/node_modules/jose/dist/webapi/jws/flattened/verify.js +8 -7
- package/node_modules/jose/dist/webapi/jws/general/sign.js +5 -3
- package/node_modules/jose/dist/webapi/jws/general/verify.js +51 -21
- package/node_modules/jose/dist/webapi/jwt/decrypt.js +7 -9
- package/node_modules/jose/dist/webapi/jwt/encrypt.js +21 -50
- package/node_modules/jose/dist/webapi/jwt/sign.js +8 -41
- package/node_modules/jose/dist/webapi/jwt/unsecured.js +21 -42
- package/node_modules/jose/dist/webapi/key/generate_key_pair.js +6 -2
- package/node_modules/jose/dist/webapi/key/generate_secret.js +7 -6
- package/node_modules/jose/dist/webapi/key/import.js +16 -12
- package/node_modules/jose/dist/webapi/lib/asn1.js +7 -2
- package/node_modules/jose/dist/webapi/lib/content_encryption.js +7 -15
- package/node_modules/jose/dist/webapi/lib/deflate.js +8 -0
- package/node_modules/jose/dist/webapi/lib/helpers.js +1 -1
- package/node_modules/jose/dist/webapi/lib/jwe_decrypt.js +85 -28
- package/node_modules/jose/dist/webapi/lib/jwe_encrypt.js +45 -13
- package/node_modules/jose/dist/webapi/lib/jwk_metadata.js +20 -0
- package/node_modules/jose/dist/webapi/lib/jws_sign.js +47 -36
- package/node_modules/jose/dist/webapi/lib/jws_verify.js +77 -45
- package/node_modules/jose/dist/webapi/lib/jwt_claims_set.js +82 -47
- package/node_modules/jose/dist/webapi/lib/key.js +24 -9
- package/node_modules/jose/dist/webapi/lib/key_management.js +10 -4
- package/node_modules/jose/dist/webapi/lib/key_options.js +6 -0
- package/node_modules/jose/dist/webapi/lib/options.js +26 -0
- package/node_modules/jose/dist/webapi/lib/type_checks.js +11 -13
- package/node_modules/jose/package.json +1 -1
- package/package.json +2 -2
- package/dist/ui/assets/index-DdJeSfV9.js +0 -110
- package/node_modules/@modelcontextprotocol/sdk/node_modules/negotiator/HISTORY.md +0 -114
|
@@ -216,8 +216,7 @@
|
|
|
216
216
|
"bounds": {
|
|
217
217
|
"recipient_max": "0",
|
|
218
218
|
"send_daily_max": "0",
|
|
219
|
-
"read_max_age_days": "30"
|
|
220
|
-
"read_daily_max": "100"
|
|
219
|
+
"read_max_age_days": "30"
|
|
221
220
|
},
|
|
222
221
|
"context": {
|
|
223
222
|
"allowed_recipients": "",
|
|
@@ -227,8 +226,7 @@
|
|
|
227
226
|
"ttl": 2592000,
|
|
228
227
|
"tags": [
|
|
229
228
|
"read-only",
|
|
230
|
-
"30 days"
|
|
231
|
-
"100 reads/day"
|
|
229
|
+
"30 days"
|
|
232
230
|
]
|
|
233
231
|
},
|
|
234
232
|
{
|
|
@@ -239,8 +237,7 @@
|
|
|
239
237
|
"bounds": {
|
|
240
238
|
"recipient_max": "5",
|
|
241
239
|
"send_daily_max": "20",
|
|
242
|
-
"read_max_age_days": "90"
|
|
243
|
-
"read_daily_max": "200"
|
|
240
|
+
"read_max_age_days": "90"
|
|
244
241
|
},
|
|
245
242
|
"context": {
|
|
246
243
|
"allowed_recipients": "",
|
|
@@ -419,6 +419,13 @@ async function getEnrichedAuthorizations() {
|
|
|
419
419
|
if (!res.ok) throw new Error("Failed to fetch authorizations");
|
|
420
420
|
return res.json();
|
|
421
421
|
}
|
|
422
|
+
async function getLocalEvidence() {
|
|
423
|
+
const res = await fetch(`${MCP_BASE}/internal/evidence`, {
|
|
424
|
+
headers: internalHeaders()
|
|
425
|
+
});
|
|
426
|
+
if (!res.ok) throw new Error(`Failed to fetch local evidence: ${res.status}`);
|
|
427
|
+
return res.json();
|
|
428
|
+
}
|
|
422
429
|
async function getMcpHealth() {
|
|
423
430
|
const res = await fetch(`${MCP_BASE}/health`);
|
|
424
431
|
if (!res.ok) throw new Error("MCP server unreachable");
|
|
@@ -865,6 +872,7 @@ function createVaultRouter(vault2) {
|
|
|
865
872
|
import { Router as Router3 } from "express";
|
|
866
873
|
|
|
867
874
|
// src/lib/ai-client.ts
|
|
875
|
+
var CHAT_TOKEN_BUDGET = 4e3;
|
|
868
876
|
var PROVIDER_PRESETS = {
|
|
869
877
|
ollama: {
|
|
870
878
|
provider: "ollama",
|
|
@@ -892,6 +900,30 @@ var PROVIDER_PRESETS = {
|
|
|
892
900
|
model: "meta-llama/Llama-3-8b-chat-hf"
|
|
893
901
|
}
|
|
894
902
|
};
|
|
903
|
+
function explainEmptyReply(choice, usage, budget) {
|
|
904
|
+
const reasoningTokens = usage?.completion_tokens_details?.reasoning_tokens ?? 0;
|
|
905
|
+
const finish = choice?.finish_reason;
|
|
906
|
+
const hadReasoning = reasoningTokens > 0 || Boolean(choice?.message?.reasoning_content || choice?.message?.reasoning);
|
|
907
|
+
if (finish === "length" && hadReasoning) {
|
|
908
|
+
return `The model is a reasoning model and spent its whole ${budget}-token budget` + (reasoningTokens ? ` (${reasoningTokens} tokens)` : "") + " thinking, leaving nothing for the answer. Raise the token limit or choose a non-reasoning model in Settings.";
|
|
909
|
+
}
|
|
910
|
+
if (finish === "length") {
|
|
911
|
+
return `The model hit the ${budget}-token limit before writing any answer.`;
|
|
912
|
+
}
|
|
913
|
+
if (hadReasoning) {
|
|
914
|
+
return "The model returned only internal reasoning and no answer \u2014 it may not be compatible with this endpoint. Try a different model in Settings.";
|
|
915
|
+
}
|
|
916
|
+
if (finish === "content_filter") {
|
|
917
|
+
return "The provider's content filter blocked the response.";
|
|
918
|
+
}
|
|
919
|
+
if (choice?.message?.tool_calls?.length) {
|
|
920
|
+
return "The model tried to call a tool instead of answering. Choose a model without forced tool use.";
|
|
921
|
+
}
|
|
922
|
+
if (!choice) {
|
|
923
|
+
return "The provider returned no choices. Check the model name in Settings.";
|
|
924
|
+
}
|
|
925
|
+
return `The model returned an empty answer${finish ? ` (finish_reason: ${finish})` : ""}.`;
|
|
926
|
+
}
|
|
895
927
|
var SYSTEM_PROMPTS = {
|
|
896
928
|
intent: `You are a reviewing assistant helping a human articulate their intent for an AI agent authorization.
|
|
897
929
|
|
|
@@ -1062,13 +1094,20 @@ ${request.currentText}
|
|
|
1062
1094
|
model: config.model,
|
|
1063
1095
|
messages,
|
|
1064
1096
|
stream: false,
|
|
1065
|
-
options: { temperature: 0.3, num_predict:
|
|
1097
|
+
options: { temperature: 0.3, num_predict: CHAT_TOKEN_BUDGET }
|
|
1066
1098
|
}),
|
|
1067
1099
|
signal: AbortSignal.timeout(6e4)
|
|
1068
1100
|
});
|
|
1069
1101
|
if (!response.ok) throw new Error(`Ollama: ${response.status}`);
|
|
1070
1102
|
const data = await response.json();
|
|
1071
|
-
|
|
1103
|
+
const content = data.message?.content?.trim();
|
|
1104
|
+
if (!content) {
|
|
1105
|
+
return {
|
|
1106
|
+
success: false,
|
|
1107
|
+
error: data.message?.thinking ? "The model returned only internal reasoning and no answer. Try a non-thinking model." : `The model returned an empty answer. Check that "${config.model}" is pulled and running in Ollama.`
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
1110
|
+
reply = content;
|
|
1072
1111
|
} else {
|
|
1073
1112
|
const headers = { "Content-Type": "application/json" };
|
|
1074
1113
|
if (config.apiKey) headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
@@ -1079,7 +1118,10 @@ ${request.currentText}
|
|
|
1079
1118
|
model: config.model,
|
|
1080
1119
|
messages,
|
|
1081
1120
|
temperature: 0.3,
|
|
1082
|
-
|
|
1121
|
+
// Reasoning models charge their thinking against this same budget,
|
|
1122
|
+
// so a small number here produces an empty answer rather than a
|
|
1123
|
+
// short one. 4000 leaves room to think AND reply.
|
|
1124
|
+
max_tokens: CHAT_TOKEN_BUDGET
|
|
1083
1125
|
}),
|
|
1084
1126
|
signal: AbortSignal.timeout(6e4)
|
|
1085
1127
|
});
|
|
@@ -1088,7 +1130,14 @@ ${request.currentText}
|
|
|
1088
1130
|
throw new Error(`AI provider: ${response.status} - ${errorText}`);
|
|
1089
1131
|
}
|
|
1090
1132
|
const data = await response.json();
|
|
1091
|
-
|
|
1133
|
+
const content = data.choices?.[0]?.message?.content?.trim();
|
|
1134
|
+
if (!content) {
|
|
1135
|
+
return {
|
|
1136
|
+
success: false,
|
|
1137
|
+
error: explainEmptyReply(data.choices?.[0], data.usage, CHAT_TOKEN_BUDGET)
|
|
1138
|
+
};
|
|
1139
|
+
}
|
|
1140
|
+
reply = content;
|
|
1092
1141
|
}
|
|
1093
1142
|
return { success: true, reply };
|
|
1094
1143
|
} catch (error) {
|
|
@@ -1893,49 +1942,11 @@ function createEncryptIntentRouter() {
|
|
|
1893
1942
|
return router;
|
|
1894
1943
|
}
|
|
1895
1944
|
|
|
1896
|
-
// src/routes/
|
|
1897
|
-
import { Router as
|
|
1898
|
-
function createDecryptIntentRouter(vault2) {
|
|
1899
|
-
const router = Router8();
|
|
1900
|
-
router.post("/", async (req, res) => {
|
|
1901
|
-
const { intentCiphertext, encryptedKey, approverId } = req.body;
|
|
1902
|
-
if (typeof intentCiphertext !== "string" || intentCiphertext.length === 0) {
|
|
1903
|
-
res.status(400).json({ error: "Missing or invalid field: intentCiphertext (base64 string)" });
|
|
1904
|
-
return;
|
|
1905
|
-
}
|
|
1906
|
-
if (typeof encryptedKey !== "object" || encryptedKey === null || typeof encryptedKey.ct !== "string" || typeof encryptedKey.enc !== "string") {
|
|
1907
|
-
res.status(400).json({ error: "Missing or invalid field: encryptedKey ({ ct: string; enc: string })" });
|
|
1908
|
-
return;
|
|
1909
|
-
}
|
|
1910
|
-
if (typeof approverId !== "string" || approverId.length === 0) {
|
|
1911
|
-
res.status(400).json({ error: "Missing or invalid field: approverId (string)" });
|
|
1912
|
-
return;
|
|
1913
|
-
}
|
|
1914
|
-
try {
|
|
1915
|
-
const kp = await loadOrGenerateKeyPair(vault2);
|
|
1916
|
-
const { ct, enc } = encryptedKey;
|
|
1917
|
-
const encrypted = {
|
|
1918
|
-
intentCiphertext: new Uint8Array(Buffer.from(intentCiphertext, "base64")),
|
|
1919
|
-
encryptedKeys: {
|
|
1920
|
-
[approverId]: {
|
|
1921
|
-
ct: new Uint8Array(Buffer.from(ct, "base64")),
|
|
1922
|
-
enc: new Uint8Array(Buffer.from(enc, "base64"))
|
|
1923
|
-
}
|
|
1924
|
-
}
|
|
1925
|
-
};
|
|
1926
|
-
const intent = await decryptIntent(encrypted, approverId, kp.privateKey);
|
|
1927
|
-
res.json({ intent });
|
|
1928
|
-
} catch (err) {
|
|
1929
|
-
console.error("[Control Plane] decrypt-intent error:", err);
|
|
1930
|
-
const msg = err instanceof Error ? err.message : "Decryption failed";
|
|
1931
|
-
res.status(500).json({ error: msg });
|
|
1932
|
-
}
|
|
1933
|
-
});
|
|
1934
|
-
return router;
|
|
1935
|
-
}
|
|
1945
|
+
// src/routes/evidence-export.ts
|
|
1946
|
+
import { Router as Router9 } from "express";
|
|
1936
1947
|
|
|
1937
1948
|
// src/routes/approved-intents.ts
|
|
1938
|
-
import { Router as
|
|
1949
|
+
import { Router as Router8 } from "express";
|
|
1939
1950
|
import { readFileSync as readFileSync2, writeFileSync as writeFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
|
|
1940
1951
|
import { homedir as homedir3 } from "os";
|
|
1941
1952
|
import { join as join3 } from "path";
|
|
@@ -1955,19 +1966,22 @@ function writeFile(data) {
|
|
|
1955
1966
|
mkdirSync3(SUVEREN_DATA_DIR, { recursive: true });
|
|
1956
1967
|
writeFileSync3(FILE_PATH, JSON.stringify(data, null, 2), "utf-8");
|
|
1957
1968
|
}
|
|
1969
|
+
function readApprovedIntents(vault2) {
|
|
1970
|
+
const file = readFile();
|
|
1971
|
+
const result = {};
|
|
1972
|
+
for (const [authorityId, blob] of Object.entries(file.entries)) {
|
|
1973
|
+
try {
|
|
1974
|
+
result[authorityId] = vault2.decrypt(blob);
|
|
1975
|
+
} catch {
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
return result;
|
|
1979
|
+
}
|
|
1958
1980
|
function createApprovedIntentsRouter(vault2) {
|
|
1959
|
-
const router =
|
|
1981
|
+
const router = Router8();
|
|
1960
1982
|
router.get("/", (req, res) => {
|
|
1961
1983
|
try {
|
|
1962
|
-
|
|
1963
|
-
const result = {};
|
|
1964
|
-
for (const [authorityId, blob] of Object.entries(file.entries)) {
|
|
1965
|
-
try {
|
|
1966
|
-
result[authorityId] = vault2.decrypt(blob);
|
|
1967
|
-
} catch {
|
|
1968
|
-
}
|
|
1969
|
-
}
|
|
1970
|
-
res.json({ intents: result });
|
|
1984
|
+
res.json({ intents: readApprovedIntents(vault2) });
|
|
1971
1985
|
} catch (err) {
|
|
1972
1986
|
console.error("[Control Plane] approved-intents GET error:", err);
|
|
1973
1987
|
res.status(500).json({ error: "Failed to read approved intents" });
|
|
@@ -1997,6 +2011,222 @@ function createApprovedIntentsRouter(vault2) {
|
|
|
1997
2011
|
return router;
|
|
1998
2012
|
}
|
|
1999
2013
|
|
|
2014
|
+
// src/routes/evidence-export.ts
|
|
2015
|
+
var AS_FETCH_TIMEOUT_MS = 2e4;
|
|
2016
|
+
function createEvidenceExportRouter(spUrl, vault2) {
|
|
2017
|
+
const router = Router9();
|
|
2018
|
+
const getSpCookie = () => vault2.getSpCookie();
|
|
2019
|
+
router.get("/", async (_req, res) => {
|
|
2020
|
+
let local = null;
|
|
2021
|
+
let localError;
|
|
2022
|
+
try {
|
|
2023
|
+
local = await getLocalEvidence();
|
|
2024
|
+
} catch (err) {
|
|
2025
|
+
localError = err instanceof Error ? err.message : String(err);
|
|
2026
|
+
}
|
|
2027
|
+
let authorityServer = null;
|
|
2028
|
+
let asError;
|
|
2029
|
+
const cookie = getSpCookie();
|
|
2030
|
+
if (!cookie) {
|
|
2031
|
+
asError = "No Authority Server session \u2014 sign in to include the full account history.";
|
|
2032
|
+
} else {
|
|
2033
|
+
const controller = new AbortController();
|
|
2034
|
+
const timeout = setTimeout(() => controller.abort(), AS_FETCH_TIMEOUT_MS);
|
|
2035
|
+
try {
|
|
2036
|
+
const asRes = await fetch(`${spUrl}/api/receipts/export`, {
|
|
2037
|
+
headers: { Cookie: cookie },
|
|
2038
|
+
signal: controller.signal
|
|
2039
|
+
});
|
|
2040
|
+
if (asRes.ok) {
|
|
2041
|
+
authorityServer = await asRes.json();
|
|
2042
|
+
} else {
|
|
2043
|
+
asError = `Authority Server export failed: ${asRes.status}`;
|
|
2044
|
+
}
|
|
2045
|
+
} catch (err) {
|
|
2046
|
+
asError = `Authority Server unreachable: ${err instanceof Error ? err.message : String(err)}`;
|
|
2047
|
+
} finally {
|
|
2048
|
+
clearTimeout(timeout);
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
if (!local && !authorityServer) {
|
|
2052
|
+
res.status(502).json({
|
|
2053
|
+
error: "No evidence source available.",
|
|
2054
|
+
localError,
|
|
2055
|
+
asError
|
|
2056
|
+
});
|
|
2057
|
+
return;
|
|
2058
|
+
}
|
|
2059
|
+
let approvedIntents = {};
|
|
2060
|
+
try {
|
|
2061
|
+
approvedIntents = readApprovedIntents(vault2);
|
|
2062
|
+
} catch {
|
|
2063
|
+
}
|
|
2064
|
+
const exportedAt = Math.floor(Date.now() / 1e3);
|
|
2065
|
+
const date = new Date(exportedAt * 1e3).toISOString().slice(0, 10);
|
|
2066
|
+
res.setHeader("Content-Disposition", `attachment; filename="suveren-evidence-${date}.json"`).setHeader("Cache-Control", "no-store").json({
|
|
2067
|
+
format: "suveren-evidence-bundle/1",
|
|
2068
|
+
exportedAt,
|
|
2069
|
+
sources: {
|
|
2070
|
+
local: local !== null,
|
|
2071
|
+
authorityServer: authorityServer !== null,
|
|
2072
|
+
...localError ? { localError } : {},
|
|
2073
|
+
...asError ? { asError } : {}
|
|
2074
|
+
},
|
|
2075
|
+
local,
|
|
2076
|
+
approvedIntents,
|
|
2077
|
+
authorityServer
|
|
2078
|
+
});
|
|
2079
|
+
});
|
|
2080
|
+
return router;
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
// src/routes/evidence.ts
|
|
2084
|
+
import { Router as Router10 } from "express";
|
|
2085
|
+
import { verifyReceiptSignature } from "@hap/core";
|
|
2086
|
+
async function verifyAll(receipts) {
|
|
2087
|
+
const out = {};
|
|
2088
|
+
for (const raw of receipts) {
|
|
2089
|
+
const e = raw;
|
|
2090
|
+
const id = typeof e.receipt?.id === "string" ? e.receipt.id : void 0;
|
|
2091
|
+
if (!id) continue;
|
|
2092
|
+
if (!e.asPublicKey) {
|
|
2093
|
+
out[id] = "unverifiable";
|
|
2094
|
+
continue;
|
|
2095
|
+
}
|
|
2096
|
+
try {
|
|
2097
|
+
await verifyReceiptSignature(e.receipt, e.asPublicKey);
|
|
2098
|
+
out[id] = "valid";
|
|
2099
|
+
} catch {
|
|
2100
|
+
out[id] = "invalid";
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
return out;
|
|
2104
|
+
}
|
|
2105
|
+
function mergeAuthorizations(evidence) {
|
|
2106
|
+
const out = {};
|
|
2107
|
+
for (const raw of evidence.authorizations ?? []) {
|
|
2108
|
+
const a = raw;
|
|
2109
|
+
const id = a.authorizationId;
|
|
2110
|
+
if (!id) continue;
|
|
2111
|
+
out[id] = {
|
|
2112
|
+
authorizationId: id,
|
|
2113
|
+
profileId: a.profileId,
|
|
2114
|
+
boundsHash: a.boundsHash,
|
|
2115
|
+
contextHash: a.contextHash,
|
|
2116
|
+
bounds: a.bounds,
|
|
2117
|
+
context: a.context,
|
|
2118
|
+
intent: a.intent,
|
|
2119
|
+
archived: true
|
|
2120
|
+
};
|
|
2121
|
+
}
|
|
2122
|
+
for (const raw of evidence.gates ?? []) {
|
|
2123
|
+
const g = raw;
|
|
2124
|
+
const id = g.authorizationId;
|
|
2125
|
+
if (!id) continue;
|
|
2126
|
+
const gateContent = g.gateContent ?? {};
|
|
2127
|
+
const existing = out[id];
|
|
2128
|
+
if (!existing) {
|
|
2129
|
+
out[id] = {
|
|
2130
|
+
authorizationId: id,
|
|
2131
|
+
profileId: g.profileId,
|
|
2132
|
+
boundsHash: g.boundsHash,
|
|
2133
|
+
contextHash: g.contextHash,
|
|
2134
|
+
context: g.context,
|
|
2135
|
+
intent: gateContent.intent,
|
|
2136
|
+
archived: false
|
|
2137
|
+
};
|
|
2138
|
+
continue;
|
|
2139
|
+
}
|
|
2140
|
+
existing.intent ??= gateContent.intent;
|
|
2141
|
+
existing.context ??= g.context;
|
|
2142
|
+
existing.contextHash ??= g.contextHash;
|
|
2143
|
+
}
|
|
2144
|
+
return out;
|
|
2145
|
+
}
|
|
2146
|
+
function createEvidenceRouter() {
|
|
2147
|
+
const router = Router10();
|
|
2148
|
+
router.get("/authorizations", async (_req, res) => {
|
|
2149
|
+
try {
|
|
2150
|
+
const evidence = await getLocalEvidence();
|
|
2151
|
+
res.json({
|
|
2152
|
+
authorizations: mergeAuthorizations(evidence),
|
|
2153
|
+
// Verified here, on this machine, so the card's badge reports a check
|
|
2154
|
+
// that actually ran rather than the issuer vouching for itself.
|
|
2155
|
+
signatures: await verifyAll(evidence.receipts ?? [])
|
|
2156
|
+
});
|
|
2157
|
+
} catch (err) {
|
|
2158
|
+
res.status(503).json({
|
|
2159
|
+
error: "Local evidence unavailable",
|
|
2160
|
+
detail: err instanceof Error ? err.message : String(err)
|
|
2161
|
+
});
|
|
2162
|
+
}
|
|
2163
|
+
});
|
|
2164
|
+
router.get("/receipt/:id", async (req, res) => {
|
|
2165
|
+
const id = String(req.params.id);
|
|
2166
|
+
try {
|
|
2167
|
+
const evidence = await getLocalEvidence();
|
|
2168
|
+
const entry = (evidence.receipts ?? []).find(
|
|
2169
|
+
(r) => r.receipt?.id === id
|
|
2170
|
+
);
|
|
2171
|
+
if (!entry) {
|
|
2172
|
+
res.status(404).json({ error: "No local copy of this receipt" });
|
|
2173
|
+
return;
|
|
2174
|
+
}
|
|
2175
|
+
const authorizationId = entry.authorizationId;
|
|
2176
|
+
const authorization = authorizationId ? mergeAuthorizations(evidence)[authorizationId] ?? null : null;
|
|
2177
|
+
const signature = (await verifyAll([entry]))[id] ?? "unverifiable";
|
|
2178
|
+
res.json({ entry, authorization, signature });
|
|
2179
|
+
} catch (err) {
|
|
2180
|
+
res.status(503).json({
|
|
2181
|
+
error: "Local evidence unavailable",
|
|
2182
|
+
detail: err instanceof Error ? err.message : String(err)
|
|
2183
|
+
});
|
|
2184
|
+
}
|
|
2185
|
+
});
|
|
2186
|
+
return router;
|
|
2187
|
+
}
|
|
2188
|
+
|
|
2189
|
+
// src/routes/decrypt-intent.ts
|
|
2190
|
+
import { Router as Router11 } from "express";
|
|
2191
|
+
function createDecryptIntentRouter(vault2) {
|
|
2192
|
+
const router = Router11();
|
|
2193
|
+
router.post("/", async (req, res) => {
|
|
2194
|
+
const { intentCiphertext, encryptedKey, approverId } = req.body;
|
|
2195
|
+
if (typeof intentCiphertext !== "string" || intentCiphertext.length === 0) {
|
|
2196
|
+
res.status(400).json({ error: "Missing or invalid field: intentCiphertext (base64 string)" });
|
|
2197
|
+
return;
|
|
2198
|
+
}
|
|
2199
|
+
if (typeof encryptedKey !== "object" || encryptedKey === null || typeof encryptedKey.ct !== "string" || typeof encryptedKey.enc !== "string") {
|
|
2200
|
+
res.status(400).json({ error: "Missing or invalid field: encryptedKey ({ ct: string; enc: string })" });
|
|
2201
|
+
return;
|
|
2202
|
+
}
|
|
2203
|
+
if (typeof approverId !== "string" || approverId.length === 0) {
|
|
2204
|
+
res.status(400).json({ error: "Missing or invalid field: approverId (string)" });
|
|
2205
|
+
return;
|
|
2206
|
+
}
|
|
2207
|
+
try {
|
|
2208
|
+
const kp = await loadOrGenerateKeyPair(vault2);
|
|
2209
|
+
const { ct, enc } = encryptedKey;
|
|
2210
|
+
const encrypted = {
|
|
2211
|
+
intentCiphertext: new Uint8Array(Buffer.from(intentCiphertext, "base64")),
|
|
2212
|
+
encryptedKeys: {
|
|
2213
|
+
[approverId]: {
|
|
2214
|
+
ct: new Uint8Array(Buffer.from(ct, "base64")),
|
|
2215
|
+
enc: new Uint8Array(Buffer.from(enc, "base64"))
|
|
2216
|
+
}
|
|
2217
|
+
}
|
|
2218
|
+
};
|
|
2219
|
+
const intent = await decryptIntent(encrypted, approverId, kp.privateKey);
|
|
2220
|
+
res.json({ intent });
|
|
2221
|
+
} catch (err) {
|
|
2222
|
+
console.error("[Control Plane] decrypt-intent error:", err);
|
|
2223
|
+
const msg = err instanceof Error ? err.message : "Decryption failed";
|
|
2224
|
+
res.status(500).json({ error: msg });
|
|
2225
|
+
}
|
|
2226
|
+
});
|
|
2227
|
+
return router;
|
|
2228
|
+
}
|
|
2229
|
+
|
|
2000
2230
|
// src/lib/update-checker.ts
|
|
2001
2231
|
import { execSync } from "child_process";
|
|
2002
2232
|
import { dirname as dirname3 } from "path";
|
|
@@ -2133,7 +2363,7 @@ data: null
|
|
|
2133
2363
|
}
|
|
2134
2364
|
|
|
2135
2365
|
// src/routes/gateway-settings.ts
|
|
2136
|
-
import { Router as
|
|
2366
|
+
import { Router as Router12 } from "express";
|
|
2137
2367
|
|
|
2138
2368
|
// src/lib/gateway-settings.ts
|
|
2139
2369
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4 } from "fs";
|
|
@@ -2169,7 +2399,7 @@ function writeSettings(patch, dataDir) {
|
|
|
2169
2399
|
|
|
2170
2400
|
// src/routes/gateway-settings.ts
|
|
2171
2401
|
function createGatewaySettingsRouter() {
|
|
2172
|
-
const router =
|
|
2402
|
+
const router = Router12();
|
|
2173
2403
|
router.get("/", (_req, res) => {
|
|
2174
2404
|
res.json(readSettings());
|
|
2175
2405
|
});
|
|
@@ -2192,7 +2422,7 @@ function createGatewaySettingsRouter() {
|
|
|
2192
2422
|
}
|
|
2193
2423
|
|
|
2194
2424
|
// src/routes/internal-events.ts
|
|
2195
|
-
import { Router as
|
|
2425
|
+
import { Router as Router13 } from "express";
|
|
2196
2426
|
import { timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
2197
2427
|
var ALLOWED = ["proposal-added", "action-approval-needed"];
|
|
2198
2428
|
function secretMatches(provided, expected) {
|
|
@@ -2204,7 +2434,7 @@ function secretMatches(provided, expected) {
|
|
|
2204
2434
|
return timingSafeEqual2(a, b);
|
|
2205
2435
|
}
|
|
2206
2436
|
function createInternalEventsRouter(getSecret) {
|
|
2207
|
-
const router =
|
|
2437
|
+
const router = Router13();
|
|
2208
2438
|
router.post("/event", (req, res) => {
|
|
2209
2439
|
if (!secretMatches(req.headers["x-internal-secret"], getSecret())) {
|
|
2210
2440
|
res.status(401).json({ error: "Unauthorized" });
|
|
@@ -2586,6 +2816,8 @@ app.use("/mcp", jsonParser, authGuard, createMCPRouter());
|
|
|
2586
2816
|
app.use("/autostart", jsonParser, authGuard, createAutostartRouter());
|
|
2587
2817
|
app.use("/api/gateway-settings", jsonParser, authGuard, createGatewaySettingsRouter());
|
|
2588
2818
|
app.use("/api/encrypt-intent", jsonParser, authGuard, createEncryptIntentRouter());
|
|
2819
|
+
app.use("/api/evidence-export", authGuard, createEvidenceExportRouter(SP_URL2, vault));
|
|
2820
|
+
app.use("/api/evidence", authGuard, createEvidenceRouter());
|
|
2589
2821
|
app.use("/api/decrypt-intent", jsonParser, authGuard, createDecryptIntentRouter(vault));
|
|
2590
2822
|
app.use("/api/approved-intents", jsonParser, authGuard, createApprovedIntentsRouter(vault));
|
|
2591
2823
|
app.put("/integrations/:id/read-policy", jsonParser, authGuard, async (req, res) => {
|
|
@@ -2808,10 +3040,10 @@ app.use(
|
|
|
2808
3040
|
const url = req.url ?? "";
|
|
2809
3041
|
if (method !== "POST" && method !== "DELETE") return;
|
|
2810
3042
|
const path = url.split("?")[0];
|
|
2811
|
-
if (method === "POST" && path === "/api/as/attest") {
|
|
2812
|
-
eventBus.emit("attestation-changed");
|
|
2813
|
-
} else if (method === "POST" && /^\/api\/attestations\/[^/]+\/revoke$/.test(path)) {
|
|
3043
|
+
if (method === "POST" && path === "/api/as/attest" || method === "POST" && /^\/api\/attestations\/[^/]+\/revoke$/.test(path) || method === "POST" && /^\/api\/authorizations\/[^/]+\/delete$/.test(path)) {
|
|
2814
3044
|
eventBus.emit("attestation-changed");
|
|
3045
|
+
void resyncGates().catch(() => {
|
|
3046
|
+
});
|
|
2815
3047
|
} else if (method === "POST" && path === "/api/proposals") {
|
|
2816
3048
|
eventBus.emit("proposal-added");
|
|
2817
3049
|
} else if (method === "POST" && /^\/api\/proposals\/[^/]+\/resolve$/.test(path)) {
|