@suveren/gateway 0.3.17 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/suveren-gateway.js +419 -28
- package/content/integrations/calendar.json +20 -8
- package/content/integrations/crm.json +97 -23
- package/content/integrations/gmail.json +166 -29
- package/content/integrations/linkedin.json +15 -3
- package/content/integrations/mollie.json +2 -2
- package/dist/control-plane/index.mjs +333 -41
- package/dist/mcp-server/http.mjs +880 -210
- package/dist/ui/assets/index-BDQY7Z3H.js +105 -0
- package/dist/ui/assets/{index-DOt3SNnl.css → index-JHaCddDE.css} +1 -1
- package/dist/ui/index.html +2 -2
- package/node_modules/@hap/core/dist/index.d.mts +27 -0
- package/node_modules/@hap/core/dist/index.d.ts +27 -0
- package/node_modules/@hap/core/dist/index.js +13 -1
- package/node_modules/@hap/core/dist/index.mjs +13 -1
- package/node_modules/@hap/core/package.json +1 -1
- package/node_modules/@hap/core/src/gatekeeper.ts +47 -1
- package/node_modules/@hap/core/src/types.ts +27 -0
- package/node_modules/@hono/node-server/README.md +58 -25
- package/node_modules/@hono/node-server/dist/conninfo.cjs +22 -0
- package/node_modules/@hono/node-server/dist/{conninfo.d.ts → conninfo.d.cts} +4 -3
- package/node_modules/@hono/node-server/dist/conninfo.d.mts +4 -3
- package/node_modules/@hono/node-server/dist/conninfo.mjs +19 -16
- package/node_modules/@hono/node-server/dist/constants-BLSFu_RU.mjs +5 -0
- package/node_modules/@hono/node-server/dist/constants-BXAKTxRC.cjs +11 -0
- package/node_modules/@hono/node-server/dist/index.cjs +1173 -0
- package/node_modules/@hono/node-server/dist/index.d.cts +101 -0
- package/node_modules/@hono/node-server/dist/index.d.mts +101 -8
- package/node_modules/@hono/node-server/dist/index.mjs +1143 -637
- package/node_modules/@hono/node-server/dist/serve-static.cjs +151 -0
- package/node_modules/@hono/node-server/dist/serve-static.d.cts +18 -0
- package/node_modules/@hono/node-server/dist/serve-static.d.mts +14 -13
- package/node_modules/@hono/node-server/dist/serve-static.mjs +143 -145
- package/node_modules/@hono/node-server/dist/utils/response.cjs +8 -0
- package/node_modules/@hono/node-server/dist/utils/response.d.cts +4 -0
- package/node_modules/@hono/node-server/dist/utils/response.d.mts +3 -2
- package/node_modules/@hono/node-server/dist/utils/response.mjs +6 -9
- package/node_modules/@hono/node-server/dist/utils/stream.cjs +65 -0
- package/node_modules/@hono/node-server/dist/utils/stream.d.cts +6 -0
- package/node_modules/@hono/node-server/dist/utils/stream.d.mts +6 -0
- package/node_modules/@hono/node-server/dist/utils/stream.mjs +64 -0
- package/node_modules/@hono/node-server/package.json +65 -54
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/index.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/index.js +1 -12
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/index.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/stdio.d.ts +7 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/stdio.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/stdio.js +9 -3
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/stdio.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/streamableHttp.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/streamableHttp.js +5 -3
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/streamableHttp.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/index.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/index.js +1 -12
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/index.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/sseKeepAlive.d.ts +5 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/sseKeepAlive.d.ts.map +1 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/sseKeepAlive.js +17 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/sseKeepAlive.js.map +1 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/stdio.d.ts +9 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/stdio.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/stdio.js +10 -4
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/stdio.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/webStandardStreamableHttp.d.ts +21 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/webStandardStreamableHttp.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/webStandardStreamableHttp.js +239 -41
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/webStandardStreamableHttp.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/zod-compat.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/zod-compat.js +25 -6
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/zod-compat.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/shared/mediaType.d.ts +32 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/shared/mediaType.d.ts.map +1 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/shared/mediaType.js +64 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/shared/mediaType.js.map +1 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/shared/stdio.d.ts +5 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/shared/stdio.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/shared/stdio.js +10 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/cjs/shared/stdio.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/client/index.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/client/index.js +2 -13
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/client/index.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/client/stdio.d.ts +7 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/client/stdio.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/client/stdio.js +9 -3
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/client/stdio.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js +5 -3
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js +2 -13
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/sseKeepAlive.d.ts +5 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/sseKeepAlive.d.ts.map +1 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/sseKeepAlive.js +13 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/sseKeepAlive.js.map +1 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.d.ts +9 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js +10 -4
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/webStandardStreamableHttp.d.ts +21 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/webStandardStreamableHttp.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/webStandardStreamableHttp.js +239 -41
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/webStandardStreamableHttp.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js +25 -6
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/mediaType.d.ts +32 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/mediaType.d.ts.map +1 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/mediaType.js +57 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/mediaType.js.map +1 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.d.ts +5 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.d.ts.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js +9 -0
- package/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/media-typer/README.md +15 -14
- package/node_modules/@modelcontextprotocol/sdk/node_modules/media-typer/index.js +0 -8
- package/node_modules/@modelcontextprotocol/sdk/node_modules/media-typer/package.json +16 -12
- package/node_modules/@modelcontextprotocol/sdk/package.json +4 -3
- package/node_modules/@types/node/README.md +1 -1
- package/node_modules/@types/node/crypto.d.ts +1 -1
- package/node_modules/@types/node/package.json +2 -2
- package/node_modules/body-parser/HISTORY.md +7 -1
- package/node_modules/body-parser/lib/types/json.js +7 -3
- package/node_modules/body-parser/lib/types/raw.js +7 -3
- package/node_modules/body-parser/lib/types/text.js +7 -3
- package/node_modules/body-parser/lib/types/urlencoded.js +7 -3
- package/node_modules/body-parser/package.json +1 -1
- package/node_modules/express-rate-limit/dist/index.cjs +69 -5
- package/node_modules/express-rate-limit/dist/index.d.cts +16 -0
- package/node_modules/express-rate-limit/dist/index.d.mts +16 -0
- package/node_modules/express-rate-limit/dist/index.d.ts +16 -0
- package/node_modules/express-rate-limit/dist/index.mjs +55 -5
- package/node_modules/express-rate-limit/node_modules/debug/LICENSE +20 -0
- package/node_modules/express-rate-limit/node_modules/debug/README.md +481 -0
- package/node_modules/express-rate-limit/node_modules/debug/package.json +64 -0
- package/node_modules/express-rate-limit/node_modules/debug/src/browser.js +272 -0
- package/node_modules/express-rate-limit/node_modules/debug/src/common.js +292 -0
- package/node_modules/express-rate-limit/node_modules/debug/src/index.js +10 -0
- package/node_modules/express-rate-limit/node_modules/debug/src/node.js +263 -0
- package/node_modules/express-rate-limit/node_modules/ms/index.js +162 -0
- package/node_modules/express-rate-limit/node_modules/ms/license.md +21 -0
- package/node_modules/express-rate-limit/node_modules/ms/package.json +38 -0
- package/node_modules/express-rate-limit/node_modules/ms/readme.md +59 -0
- package/node_modules/express-rate-limit/package.json +12 -9
- package/node_modules/fast-uri/index.js +17 -0
- package/node_modules/fast-uri/package.json +1 -1
- package/node_modules/fast-uri/test/security.test.js +62 -0
- package/node_modules/hono/dist/adapter/aws-lambda/handler.js +1 -4
- package/node_modules/hono/dist/adapter/lambda-edge/handler.js +12 -2
- package/node_modules/hono/dist/cjs/adapter/aws-lambda/handler.js +1 -4
- package/node_modules/hono/dist/cjs/adapter/lambda-edge/handler.js +12 -2
- package/node_modules/hono/dist/cjs/client/client.js +10 -1
- package/node_modules/hono/dist/cjs/client/utils.js +1 -1
- package/node_modules/hono/dist/cjs/helper/streaming/sse.js +5 -4
- package/node_modules/hono/dist/cjs/middleware/cache/index.js +1 -1
- package/node_modules/hono/dist/cjs/middleware/compress/index.js +2 -1
- package/node_modules/hono/dist/cjs/middleware/etag/index.js +2 -1
- package/node_modules/hono/dist/cjs/middleware/method-override/index.js +5 -3
- package/node_modules/hono/dist/cjs/middleware/secure-headers/secure-headers.js +10 -4
- package/node_modules/hono/dist/cjs/request.js +8 -3
- package/node_modules/hono/dist/cjs/router/trie-router/node.js +9 -0
- package/node_modules/hono/dist/cjs/utils/accept.js +1 -1
- package/node_modules/hono/dist/cjs/utils/body.js +6 -0
- package/node_modules/hono/dist/cjs/utils/url.js +1 -1
- package/node_modules/hono/dist/client/client.js +10 -1
- package/node_modules/hono/dist/client/utils.js +1 -1
- package/node_modules/hono/dist/helper/streaming/sse.js +5 -4
- package/node_modules/hono/dist/middleware/cache/index.js +1 -1
- package/node_modules/hono/dist/middleware/compress/index.js +2 -1
- package/node_modules/hono/dist/middleware/etag/index.js +2 -1
- package/node_modules/hono/dist/middleware/method-override/index.js +5 -3
- package/node_modules/hono/dist/middleware/secure-headers/secure-headers.js +10 -4
- package/node_modules/hono/dist/request.js +8 -3
- package/node_modules/hono/dist/router/trie-router/node.js +9 -0
- package/node_modules/hono/dist/types/adapter/aws-lambda/types.d.ts +9 -0
- package/node_modules/hono/dist/types/adapter/lambda-edge/handler.d.ts +1 -1
- package/node_modules/hono/dist/types/helper/websocket/index.d.ts +1 -1
- package/node_modules/hono/dist/types/middleware/combine/index.d.ts +1 -1
- package/node_modules/hono/dist/types/middleware/language/language.d.ts +18 -0
- package/node_modules/hono/dist/types/utils/types.d.ts +1 -1
- package/node_modules/hono/dist/utils/accept.js +1 -1
- package/node_modules/hono/dist/utils/body.js +6 -0
- package/node_modules/hono/dist/utils/url.js +1 -1
- package/node_modules/hono/package.json +4 -4
- package/node_modules/ip-address/README.md +102 -96
- package/node_modules/ip-address/dist/common.d.ts +23 -0
- package/node_modules/ip-address/dist/common.js +27 -4
- package/node_modules/ip-address/dist/common.js.map +1 -1
- package/node_modules/ip-address/dist/ipv4.d.ts +8 -1
- package/node_modules/ip-address/dist/ipv4.js +21 -8
- package/node_modules/ip-address/dist/ipv4.js.map +1 -1
- package/node_modules/ip-address/dist/ipv6.d.ts +59 -1
- package/node_modules/ip-address/dist/ipv6.js +149 -41
- package/node_modules/ip-address/dist/ipv6.js.map +1 -1
- package/node_modules/ip-address/dist/v4/constants.js +5 -1
- package/node_modules/ip-address/dist/v4/constants.js.map +1 -1
- package/node_modules/ip-address/dist/v6/constants.js +3 -2
- package/node_modules/ip-address/dist/v6/constants.js.map +1 -1
- package/node_modules/ip-address/package.json +2 -2
- package/node_modules/jose/README.md +1 -4
- package/node_modules/jose/dist/types/jwks/remote.d.ts +3 -3
- package/node_modules/jose/dist/webapi/jwks/remote.js +1 -1
- package/node_modules/jose/dist/webapi/lib/key_to_jwk.js +4 -1
- package/node_modules/jose/package.json +1 -1
- package/package.json +2 -2
- package/profiles/customers/0.4.profile.json +7 -4
- package/profiles/customers/0.5.profile.json +131 -0
- package/profiles/customers/0.6.profile.json +153 -0
- package/profiles/email/0.4.profile.json +8 -4
- package/profiles/index.json +2 -0
- package/server.js +10 -0
- package/dist/ui/assets/index-CTmWS7W4.js +0 -105
- package/node_modules/@hono/node-server/dist/conninfo.js +0 -42
- package/node_modules/@hono/node-server/dist/globals.d.mts +0 -2
- package/node_modules/@hono/node-server/dist/globals.d.ts +0 -2
- package/node_modules/@hono/node-server/dist/globals.js +0 -29
- package/node_modules/@hono/node-server/dist/globals.mjs +0 -5
- package/node_modules/@hono/node-server/dist/index.d.ts +0 -8
- package/node_modules/@hono/node-server/dist/index.js +0 -702
- package/node_modules/@hono/node-server/dist/listener.d.mts +0 -13
- package/node_modules/@hono/node-server/dist/listener.d.ts +0 -13
- package/node_modules/@hono/node-server/dist/listener.js +0 -670
- package/node_modules/@hono/node-server/dist/listener.mjs +0 -635
- package/node_modules/@hono/node-server/dist/request.d.mts +0 -25
- package/node_modules/@hono/node-server/dist/request.d.ts +0 -25
- package/node_modules/@hono/node-server/dist/request.js +0 -238
- package/node_modules/@hono/node-server/dist/request.mjs +0 -206
- package/node_modules/@hono/node-server/dist/response.d.mts +0 -26
- package/node_modules/@hono/node-server/dist/response.d.ts +0 -26
- package/node_modules/@hono/node-server/dist/response.js +0 -112
- package/node_modules/@hono/node-server/dist/response.mjs +0 -85
- package/node_modules/@hono/node-server/dist/serve-static.d.ts +0 -17
- package/node_modules/@hono/node-server/dist/serve-static.js +0 -177
- package/node_modules/@hono/node-server/dist/server.d.mts +0 -10
- package/node_modules/@hono/node-server/dist/server.d.ts +0 -10
- package/node_modules/@hono/node-server/dist/server.js +0 -696
- package/node_modules/@hono/node-server/dist/server.mjs +0 -660
- package/node_modules/@hono/node-server/dist/types.d.mts +0 -44
- package/node_modules/@hono/node-server/dist/types.d.ts +0 -44
- package/node_modules/@hono/node-server/dist/types.js +0 -18
- package/node_modules/@hono/node-server/dist/types.mjs +0 -0
- package/node_modules/@hono/node-server/dist/utils/response/constants.d.mts +0 -3
- package/node_modules/@hono/node-server/dist/utils/response/constants.d.ts +0 -3
- package/node_modules/@hono/node-server/dist/utils/response/constants.js +0 -30
- package/node_modules/@hono/node-server/dist/utils/response/constants.mjs +0 -5
- package/node_modules/@hono/node-server/dist/utils/response.d.ts +0 -3
- package/node_modules/@hono/node-server/dist/utils/response.js +0 -37
- package/node_modules/@hono/node-server/dist/utils.d.mts +0 -9
- package/node_modules/@hono/node-server/dist/utils.d.ts +0 -9
- package/node_modules/@hono/node-server/dist/utils.js +0 -99
- package/node_modules/@hono/node-server/dist/utils.mjs +0 -71
- package/node_modules/@hono/node-server/dist/vercel.d.mts +0 -7
- package/node_modules/@hono/node-server/dist/vercel.d.ts +0 -7
- package/node_modules/@hono/node-server/dist/vercel.js +0 -677
- package/node_modules/@hono/node-server/dist/vercel.mjs +0 -640
|
@@ -5,8 +5,8 @@ import {
|
|
|
5
5
|
|
|
6
6
|
// src/index.ts
|
|
7
7
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
8
|
-
import { existsSync as
|
|
9
|
-
import { join as
|
|
8
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4, renameSync } from "fs";
|
|
9
|
+
import { join as join4 } from "path";
|
|
10
10
|
import { homedir as homedir3 } from "os";
|
|
11
11
|
import express from "express";
|
|
12
12
|
import { createProxyMiddleware } from "http-proxy-middleware";
|
|
@@ -16,28 +16,64 @@ import { createHash, pbkdf2Sync, randomBytes, createCipheriv, createDecipheriv,
|
|
|
16
16
|
import { mkdirSync, readFileSync, writeFileSync, existsSync } from "fs";
|
|
17
17
|
import { homedir } from "os";
|
|
18
18
|
import { dirname, join } from "path";
|
|
19
|
+
var KDF_ITERATIONS = 1e5;
|
|
20
|
+
var KDF_KEY_BYTES = 32;
|
|
21
|
+
var ApiKeyUnsealProvider = class {
|
|
22
|
+
constructor(apiKey) {
|
|
23
|
+
this.apiKey = apiKey;
|
|
24
|
+
}
|
|
25
|
+
id = "api-key";
|
|
26
|
+
deriveKey(salt) {
|
|
27
|
+
return pbkdf2Sync(this.apiKey, salt, KDF_ITERATIONS, KDF_KEY_BYTES, "sha256");
|
|
28
|
+
}
|
|
29
|
+
};
|
|
19
30
|
var Vault = class {
|
|
20
31
|
vaultKey = null;
|
|
21
32
|
apiKeyHash = null;
|
|
22
33
|
spSessionCookie = null;
|
|
34
|
+
unsealedBy = null;
|
|
23
35
|
dataDir;
|
|
24
36
|
constructor(dataDir) {
|
|
25
37
|
this.dataDir = dataDir ?? process.env.SUVEREN_DATA_DIR ?? join(homedir(), ".suveren");
|
|
26
38
|
}
|
|
27
39
|
// ─── Key management ─────────────────────────────────────────────────────
|
|
28
|
-
|
|
40
|
+
/**
|
|
41
|
+
* The vault's PBKDF2 salt, created on first unseal and stable thereafter.
|
|
42
|
+
* Every provider derives against the same salt, so swapping providers on an
|
|
43
|
+
* existing vault produces a different key — which is correct: a vault sealed
|
|
44
|
+
* by one authority is not readable by another.
|
|
45
|
+
*/
|
|
46
|
+
ensureSalt() {
|
|
29
47
|
const vaultData = this.readVaultFile();
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
salt = vaultData.salt;
|
|
33
|
-
} else {
|
|
34
|
-
salt = randomBytes(32).toString("hex");
|
|
35
|
-
vaultData.salt = salt;
|
|
48
|
+
if (!vaultData.salt) {
|
|
49
|
+
vaultData.salt = randomBytes(32).toString("hex");
|
|
36
50
|
this.writeVaultFile(vaultData);
|
|
37
51
|
}
|
|
38
|
-
|
|
52
|
+
return Buffer.from(vaultData.salt, "hex");
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Unlock the vault using any UnsealProvider. Call sites should prefer this
|
|
56
|
+
* over the API-key-specific helper below; adding an unattended provider then
|
|
57
|
+
* requires no change here.
|
|
58
|
+
*/
|
|
59
|
+
async unseal(provider) {
|
|
60
|
+
this.vaultKey = await provider.deriveKey(this.ensureSalt());
|
|
61
|
+
this.unsealedBy = provider.id;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Unlock from the user's API key. Also records the key's hash so subsequent
|
|
65
|
+
* requests can be validated (see validateApiKey) — that check is specific to
|
|
66
|
+
* a user-presented secret and has no meaning for a machine provider, which is
|
|
67
|
+
* why it lives here rather than on the interface.
|
|
68
|
+
*/
|
|
69
|
+
async deriveAndSetKey(apiKey) {
|
|
70
|
+
await this.unseal(new ApiKeyUnsealProvider(apiKey));
|
|
39
71
|
this.apiKeyHash = createHash("sha256").update(apiKey).digest("hex");
|
|
40
72
|
}
|
|
73
|
+
/** Which provider unlocked this vault, for diagnostics. Null while locked. */
|
|
74
|
+
unsealedByProvider() {
|
|
75
|
+
return this.vaultKey ? this.unsealedBy : null;
|
|
76
|
+
}
|
|
41
77
|
validateApiKey(apiKey) {
|
|
42
78
|
if (!this.apiKeyHash) return false;
|
|
43
79
|
const hash = createHash("sha256").update(apiKey).digest("hex");
|
|
@@ -49,6 +85,7 @@ var Vault = class {
|
|
|
49
85
|
this.vaultKey = null;
|
|
50
86
|
this.apiKeyHash = null;
|
|
51
87
|
this.spSessionCookie = null;
|
|
88
|
+
this.unsealedBy = null;
|
|
52
89
|
}
|
|
53
90
|
/**
|
|
54
91
|
* Check if the vault was created by a different API key.
|
|
@@ -522,7 +559,7 @@ function createAuthRouter(vault2, logoutAuth, loginRateLimit2) {
|
|
|
522
559
|
const setCookieHeaders = spRes.headers.getSetCookie?.() ?? [];
|
|
523
560
|
const sessionCookie = setCookieHeaders.join("; ");
|
|
524
561
|
vault2.setSpCookie(sessionCookie);
|
|
525
|
-
vault2.deriveAndSetKey(apiKey);
|
|
562
|
+
await vault2.deriveAndSetKey(apiKey);
|
|
526
563
|
if (vault2.isVaultFromDifferentKey()) {
|
|
527
564
|
if (!confirmWipe) {
|
|
528
565
|
const credentialIds = vault2.listCredentials();
|
|
@@ -546,7 +583,7 @@ function createAuthRouter(vault2, logoutAuth, loginRateLimit2) {
|
|
|
546
583
|
console.error("[Control Plane] Failed to remove integrations:", err);
|
|
547
584
|
}
|
|
548
585
|
vault2.wipe();
|
|
549
|
-
vault2.deriveAndSetKey(apiKey);
|
|
586
|
+
await vault2.deriveAndSetKey(apiKey);
|
|
550
587
|
}
|
|
551
588
|
if (sessionCookie) {
|
|
552
589
|
try {
|
|
@@ -657,7 +694,13 @@ function createVaultRouter(vault2) {
|
|
|
657
694
|
});
|
|
658
695
|
router.put("/credentials/:name", async (req, res) => {
|
|
659
696
|
const { name } = req.params;
|
|
660
|
-
const
|
|
697
|
+
const incoming = req.body;
|
|
698
|
+
let fields = incoming;
|
|
699
|
+
try {
|
|
700
|
+
const existing = vault2.getCredential(name);
|
|
701
|
+
if (existing) fields = { ...existing, ...incoming };
|
|
702
|
+
} catch {
|
|
703
|
+
}
|
|
661
704
|
vault2.setCredential(name, fields);
|
|
662
705
|
try {
|
|
663
706
|
await pushServiceCredentials(name, fields);
|
|
@@ -1061,6 +1104,38 @@ async function getIntentReview(config, request) {
|
|
|
1061
1104
|
};
|
|
1062
1105
|
}
|
|
1063
1106
|
}
|
|
1107
|
+
async function listAIModels(config) {
|
|
1108
|
+
try {
|
|
1109
|
+
if (config.provider === "ollama") {
|
|
1110
|
+
const res2 = await fetch(`${config.endpoint}/api/tags`, {
|
|
1111
|
+
signal: AbortSignal.timeout(5e3)
|
|
1112
|
+
});
|
|
1113
|
+
if (!res2.ok) throw new Error(`Ollama: ${res2.status}`);
|
|
1114
|
+
const data = await res2.json();
|
|
1115
|
+
const models2 = (data.models ?? []).map((m) => m.name).filter((n) => !!n).sort();
|
|
1116
|
+
return { ok: true, models: models2 };
|
|
1117
|
+
}
|
|
1118
|
+
const headers = {};
|
|
1119
|
+
if (config.apiKey) headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
1120
|
+
const res = await fetch(`${config.endpoint}/models`, {
|
|
1121
|
+
headers,
|
|
1122
|
+
signal: AbortSignal.timeout(8e3)
|
|
1123
|
+
});
|
|
1124
|
+
if (!res.ok) {
|
|
1125
|
+
if (res.status === 401 || res.status === 403) {
|
|
1126
|
+
throw new Error("Enter this provider\u2019s API key, then Refresh");
|
|
1127
|
+
}
|
|
1128
|
+
const text = await res.text().catch(() => "");
|
|
1129
|
+
throw new Error(`AI provider: ${res.status}${text ? ` - ${text}` : ""}`);
|
|
1130
|
+
}
|
|
1131
|
+
const raw = await res.json();
|
|
1132
|
+
const list = Array.isArray(raw) ? raw : raw.data ?? [];
|
|
1133
|
+
const models = list.map((m) => m.id).filter((n) => !!n).sort();
|
|
1134
|
+
return { ok: true, models };
|
|
1135
|
+
} catch (err) {
|
|
1136
|
+
return { ok: false, models: [], message: err instanceof Error ? err.message : "Failed to list models" };
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1064
1139
|
async function testAIConnectivity(config) {
|
|
1065
1140
|
try {
|
|
1066
1141
|
if (config.provider === "ollama") {
|
|
@@ -1175,16 +1250,19 @@ function createAIRouter(vault2) {
|
|
|
1175
1250
|
});
|
|
1176
1251
|
router.post("/test", async (req, res) => {
|
|
1177
1252
|
const body = req.body;
|
|
1253
|
+
const stored = loadAIConfig();
|
|
1178
1254
|
let config;
|
|
1179
1255
|
if (body?.endpoint) {
|
|
1180
1256
|
config = {
|
|
1181
|
-
provider: body.provider || "
|
|
1257
|
+
provider: body.provider || "openai-compatible",
|
|
1182
1258
|
endpoint: body.endpoint,
|
|
1183
1259
|
model: body.model || "",
|
|
1184
|
-
|
|
1260
|
+
// Fall back to the stored key only when it belongs to the SAME
|
|
1261
|
+
// endpoint — so testing a different provider without its key fails
|
|
1262
|
+
// honestly instead of passing on an unrelated stored key.
|
|
1263
|
+
apiKey: body.apiKey || (stored && stored.endpoint === body.endpoint ? stored.apiKey : void 0)
|
|
1185
1264
|
};
|
|
1186
1265
|
} else {
|
|
1187
|
-
const stored = loadAIConfig();
|
|
1188
1266
|
if (!stored) {
|
|
1189
1267
|
res.status(400).json({ ok: false, message: "No AI config stored" });
|
|
1190
1268
|
return;
|
|
@@ -1194,6 +1272,27 @@ function createAIRouter(vault2) {
|
|
|
1194
1272
|
const result = await testAIConnectivity(config);
|
|
1195
1273
|
res.json(result);
|
|
1196
1274
|
});
|
|
1275
|
+
router.post("/models", async (req, res) => {
|
|
1276
|
+
const body = req.body;
|
|
1277
|
+
const stored = loadAIConfig();
|
|
1278
|
+
let config;
|
|
1279
|
+
if (body?.endpoint) {
|
|
1280
|
+
config = {
|
|
1281
|
+
provider: body.provider || "openai-compatible",
|
|
1282
|
+
endpoint: body.endpoint,
|
|
1283
|
+
model: body.model || "",
|
|
1284
|
+
apiKey: body.apiKey || (stored && stored.endpoint === body.endpoint ? stored.apiKey : void 0)
|
|
1285
|
+
};
|
|
1286
|
+
} else {
|
|
1287
|
+
config = stored;
|
|
1288
|
+
}
|
|
1289
|
+
if (!config) {
|
|
1290
|
+
res.status(400).json({ ok: false, models: [], message: "AI not configured. Pick a provider first." });
|
|
1291
|
+
return;
|
|
1292
|
+
}
|
|
1293
|
+
const result = await listAIModels(config);
|
|
1294
|
+
res.json(result);
|
|
1295
|
+
});
|
|
1197
1296
|
router.get("/presets", (_req, res) => {
|
|
1198
1297
|
res.json({ presets: PROVIDER_PRESETS });
|
|
1199
1298
|
});
|
|
@@ -1362,11 +1461,161 @@ function createMCPRouter() {
|
|
|
1362
1461
|
return router;
|
|
1363
1462
|
}
|
|
1364
1463
|
|
|
1365
|
-
// src/routes/
|
|
1464
|
+
// src/routes/autostart.ts
|
|
1366
1465
|
import { Router as Router6 } from "express";
|
|
1466
|
+
import { execFile } from "child_process";
|
|
1467
|
+
import { existsSync as existsSync2 } from "fs";
|
|
1468
|
+
import { dirname as pathDirname, resolve } from "path";
|
|
1469
|
+
import { fileURLToPath } from "url";
|
|
1470
|
+
import { promisify } from "util";
|
|
1471
|
+
var run = promisify(execFile);
|
|
1472
|
+
var SUPPORTED = /* @__PURE__ */ new Set(["darwin", "win32", "linux"]);
|
|
1473
|
+
var MODULE_DIR = pathDirname(fileURLToPath(import.meta.url));
|
|
1474
|
+
function findCli(dirname3 = MODULE_DIR) {
|
|
1475
|
+
const candidates = [
|
|
1476
|
+
// Bundled (the shipped layout): dist/control-plane → dist → root → bin
|
|
1477
|
+
resolve(dirname3, "..", "..", "bin", "suveren-gateway.js"),
|
|
1478
|
+
// Bundled, were the routes/ directory ever preserved.
|
|
1479
|
+
resolve(dirname3, "..", "..", "..", "bin", "suveren-gateway.js"),
|
|
1480
|
+
// Dev, running from source: the repo's own bundle directory.
|
|
1481
|
+
resolve(dirname3, "..", "..", "..", "..", "bundle", "bin", "suveren-gateway.js"),
|
|
1482
|
+
resolve(dirname3, "..", "..", "..", "..", "..", "bundle", "bin", "suveren-gateway.js")
|
|
1483
|
+
// Deliberately NO process.cwd() fallback: it makes the result depend on
|
|
1484
|
+
// where the process happened to be launched from, so the same install
|
|
1485
|
+
// resolves differently between a shell and a login service — and it would
|
|
1486
|
+
// mask a genuinely missing CLI whenever the cwd happened to be the repo.
|
|
1487
|
+
];
|
|
1488
|
+
return candidates.find(existsSync2) ?? null;
|
|
1489
|
+
}
|
|
1490
|
+
async function cli(args) {
|
|
1491
|
+
const bin = findCli();
|
|
1492
|
+
if (!bin) return { ok: false, output: "CLI not found" };
|
|
1493
|
+
try {
|
|
1494
|
+
const { stdout, stderr } = await run(process.execPath, [bin, ...args], {
|
|
1495
|
+
timeout: 6e4,
|
|
1496
|
+
env: process.env
|
|
1497
|
+
});
|
|
1498
|
+
return { ok: true, output: `${stdout}${stderr}`.trim() };
|
|
1499
|
+
} catch (err) {
|
|
1500
|
+
const e = err;
|
|
1501
|
+
return { ok: false, output: `${e.stdout ?? ""}${e.stderr ?? ""}`.trim() || e.message || "failed" };
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
function safe(handler) {
|
|
1505
|
+
return (req, res) => {
|
|
1506
|
+
handler(req, res).catch((err) => {
|
|
1507
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1508
|
+
console.error("[Autostart] handler failed:", message);
|
|
1509
|
+
if (!res.headersSent) res.status(500).json({ error: "autostart_failed", message });
|
|
1510
|
+
});
|
|
1511
|
+
};
|
|
1512
|
+
}
|
|
1513
|
+
function createAutostartRouter() {
|
|
1514
|
+
const router = Router6();
|
|
1515
|
+
router.get("/", safe(async (_req, res) => {
|
|
1516
|
+
const platform = process.platform;
|
|
1517
|
+
const supported = SUPPORTED.has(platform);
|
|
1518
|
+
const bin = findCli();
|
|
1519
|
+
if (!supported || !bin) {
|
|
1520
|
+
res.json({
|
|
1521
|
+
supported: false,
|
|
1522
|
+
installed: false,
|
|
1523
|
+
platform,
|
|
1524
|
+
// Be specific about WHICH of the two reasons applies — "unavailable"
|
|
1525
|
+
// with no cause is the kind of dead end that generates support mail.
|
|
1526
|
+
reason: !supported ? `Autostart is not available on ${platform}.` : "Autostart needs the packaged gateway; it is unavailable when running from source."
|
|
1527
|
+
});
|
|
1528
|
+
return;
|
|
1529
|
+
}
|
|
1530
|
+
const { output } = await cli(["service", "status"]);
|
|
1531
|
+
res.json({
|
|
1532
|
+
supported: true,
|
|
1533
|
+
installed: /Login service:\s*installed/i.test(output),
|
|
1534
|
+
platform,
|
|
1535
|
+
detail: output
|
|
1536
|
+
});
|
|
1537
|
+
}));
|
|
1538
|
+
router.post("/", safe(async (_req, res) => {
|
|
1539
|
+
if (!SUPPORTED.has(process.platform) || !findCli()) {
|
|
1540
|
+
res.status(400).json({ error: "unsupported", message: "Autostart is not available here." });
|
|
1541
|
+
return;
|
|
1542
|
+
}
|
|
1543
|
+
const { ok, output } = await cli(["service", "install"]);
|
|
1544
|
+
if (!ok) {
|
|
1545
|
+
res.status(500).json({ error: "install_failed", message: output });
|
|
1546
|
+
return;
|
|
1547
|
+
}
|
|
1548
|
+
res.json({ ok: true, installed: true, detail: output });
|
|
1549
|
+
}));
|
|
1550
|
+
router.delete("/", safe(async (_req, res) => {
|
|
1551
|
+
if (!SUPPORTED.has(process.platform) || !findCli()) {
|
|
1552
|
+
res.status(400).json({ error: "unsupported", message: "Autostart is not available here." });
|
|
1553
|
+
return;
|
|
1554
|
+
}
|
|
1555
|
+
const { ok, output } = await cli(["service", "uninstall"]);
|
|
1556
|
+
if (!ok) {
|
|
1557
|
+
res.status(500).json({ error: "uninstall_failed", message: output });
|
|
1558
|
+
return;
|
|
1559
|
+
}
|
|
1560
|
+
res.json({ ok: true, installed: false, detail: output });
|
|
1561
|
+
}));
|
|
1562
|
+
return router;
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
// src/lib/desktop-notify.ts
|
|
1566
|
+
import { spawn } from "child_process";
|
|
1567
|
+
function osaQuote(value) {
|
|
1568
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
1569
|
+
}
|
|
1570
|
+
function psQuote(value) {
|
|
1571
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
1572
|
+
}
|
|
1573
|
+
function buildNotifyCommand(platform, title, message) {
|
|
1574
|
+
switch (platform) {
|
|
1575
|
+
case "darwin":
|
|
1576
|
+
return {
|
|
1577
|
+
cmd: "osascript",
|
|
1578
|
+
args: ["-e", `display notification ${osaQuote(message)} with title ${osaQuote(title)}`]
|
|
1579
|
+
};
|
|
1580
|
+
case "win32":
|
|
1581
|
+
return {
|
|
1582
|
+
cmd: "powershell",
|
|
1583
|
+
args: [
|
|
1584
|
+
"-NoProfile",
|
|
1585
|
+
"-NonInteractive",
|
|
1586
|
+
"-Command",
|
|
1587
|
+
`Add-Type -AssemblyName System.Windows.Forms; $n = New-Object System.Windows.Forms.NotifyIcon; $n.Icon = [System.Drawing.SystemIcons]::Information; $n.BalloonTipTitle = ${psQuote(title)}; $n.BalloonTipText = ${psQuote(message)}; $n.Visible = $true; $n.ShowBalloonTip(15000); Start-Sleep -Seconds 16; $n.Dispose()`
|
|
1588
|
+
]
|
|
1589
|
+
};
|
|
1590
|
+
case "linux":
|
|
1591
|
+
return { cmd: "notify-send", args: ["--app-name=Suveren", title, message] };
|
|
1592
|
+
default:
|
|
1593
|
+
return null;
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
function lockedNotification(port2) {
|
|
1597
|
+
return {
|
|
1598
|
+
title: "Suveren is running but locked",
|
|
1599
|
+
message: `Your agent has no authority until you unlock it. Open http://localhost:${port2} and enter your API key.`
|
|
1600
|
+
};
|
|
1601
|
+
}
|
|
1602
|
+
function notify(title, message, platform = process.platform) {
|
|
1603
|
+
const command = buildNotifyCommand(platform, title, message);
|
|
1604
|
+
if (!command) return;
|
|
1605
|
+
try {
|
|
1606
|
+
const child = spawn(command.cmd, command.args, { detached: true, stdio: "ignore" });
|
|
1607
|
+
child.on("error", () => {
|
|
1608
|
+
});
|
|
1609
|
+
child.unref();
|
|
1610
|
+
} catch {
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
// src/routes/encrypt-intent.ts
|
|
1615
|
+
import { Router as Router7 } from "express";
|
|
1367
1616
|
import { computeIntentDisclosureHash } from "@hap/core";
|
|
1368
1617
|
function createEncryptIntentRouter() {
|
|
1369
|
-
const router =
|
|
1618
|
+
const router = Router7();
|
|
1370
1619
|
router.post("/", async (req, res) => {
|
|
1371
1620
|
const { intent, recipients } = req.body;
|
|
1372
1621
|
if (typeof intent !== "string" || intent.length === 0) {
|
|
@@ -1428,9 +1677,9 @@ function createEncryptIntentRouter() {
|
|
|
1428
1677
|
}
|
|
1429
1678
|
|
|
1430
1679
|
// src/routes/decrypt-intent.ts
|
|
1431
|
-
import { Router as
|
|
1680
|
+
import { Router as Router8 } from "express";
|
|
1432
1681
|
function createDecryptIntentRouter(vault2) {
|
|
1433
|
-
const router =
|
|
1682
|
+
const router = Router8();
|
|
1434
1683
|
router.post("/", async (req, res) => {
|
|
1435
1684
|
const { intentCiphertext, encryptedKey, approverId } = req.body;
|
|
1436
1685
|
if (typeof intentCiphertext !== "string" || intentCiphertext.length === 0) {
|
|
@@ -1469,14 +1718,14 @@ function createDecryptIntentRouter(vault2) {
|
|
|
1469
1718
|
}
|
|
1470
1719
|
|
|
1471
1720
|
// src/routes/approved-intents.ts
|
|
1472
|
-
import { Router as
|
|
1473
|
-
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as
|
|
1721
|
+
import { Router as Router9 } from "express";
|
|
1722
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
1474
1723
|
import { homedir as homedir2 } from "os";
|
|
1475
1724
|
import { join as join2 } from "path";
|
|
1476
1725
|
var SUVEREN_DATA_DIR = process.env.SUVEREN_DATA_DIR ?? join2(homedir2(), ".suveren");
|
|
1477
1726
|
var FILE_PATH = join2(SUVEREN_DATA_DIR, "approved-intents.enc.json");
|
|
1478
1727
|
function readFile() {
|
|
1479
|
-
if (!
|
|
1728
|
+
if (!existsSync3(FILE_PATH)) {
|
|
1480
1729
|
return { version: 1, entries: {} };
|
|
1481
1730
|
}
|
|
1482
1731
|
try {
|
|
@@ -1490,7 +1739,7 @@ function writeFile(data) {
|
|
|
1490
1739
|
writeFileSync2(FILE_PATH, JSON.stringify(data, null, 2), "utf-8");
|
|
1491
1740
|
}
|
|
1492
1741
|
function createApprovedIntentsRouter(vault2) {
|
|
1493
|
-
const router =
|
|
1742
|
+
const router = Router9();
|
|
1494
1743
|
router.get("/", (req, res) => {
|
|
1495
1744
|
try {
|
|
1496
1745
|
const file = readFile();
|
|
@@ -1534,7 +1783,7 @@ function createApprovedIntentsRouter(vault2) {
|
|
|
1534
1783
|
// src/lib/update-checker.ts
|
|
1535
1784
|
import { execSync } from "child_process";
|
|
1536
1785
|
import { dirname as dirname2 } from "path";
|
|
1537
|
-
import { fileURLToPath } from "url";
|
|
1786
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1538
1787
|
var GHCR_IMAGE = "suverenai/suveren-gateway";
|
|
1539
1788
|
var NPM_PACKAGE = "@suveren/gateway";
|
|
1540
1789
|
var CHECK_INTERVAL = 60 * 60 * 1e3;
|
|
@@ -1599,7 +1848,7 @@ function compareSemver(a, b) {
|
|
|
1599
1848
|
return 0;
|
|
1600
1849
|
}
|
|
1601
1850
|
function checkDev() {
|
|
1602
|
-
const cwd = dirname2(
|
|
1851
|
+
const cwd = dirname2(fileURLToPath2(import.meta.url));
|
|
1603
1852
|
try {
|
|
1604
1853
|
execSync("git fetch origin --quiet", { cwd, stdio: "ignore", timeout: 15e3 });
|
|
1605
1854
|
const out = execSync("git rev-list HEAD..origin/main --count", {
|
|
@@ -1667,12 +1916,35 @@ data: ${data}
|
|
|
1667
1916
|
};
|
|
1668
1917
|
}
|
|
1669
1918
|
|
|
1919
|
+
// src/lib/denials-reader.ts
|
|
1920
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
|
|
1921
|
+
import { join as join3 } from "path";
|
|
1922
|
+
function loadDenials(dataDir, decrypt) {
|
|
1923
|
+
const encPath = join3(dataDir, "denials.enc.json");
|
|
1924
|
+
const plainPath = join3(dataDir, "denials.json");
|
|
1925
|
+
if (existsSync4(encPath)) {
|
|
1926
|
+
const { blob } = JSON.parse(readFileSync3(encPath, "utf-8"));
|
|
1927
|
+
return JSON.parse(decrypt(blob)).records ?? [];
|
|
1928
|
+
}
|
|
1929
|
+
if (existsSync4(plainPath)) {
|
|
1930
|
+
return JSON.parse(readFileSync3(plainPath, "utf-8")).records ?? [];
|
|
1931
|
+
}
|
|
1932
|
+
return [];
|
|
1933
|
+
}
|
|
1934
|
+
function selectDenials(records, opts = {}) {
|
|
1935
|
+
let out = [...records].sort((a, b) => b.ts - a.ts);
|
|
1936
|
+
if (opts.since !== void 0 && Number.isFinite(opts.since)) out = out.filter((r) => r.ts >= opts.since);
|
|
1937
|
+
const count = out.length;
|
|
1938
|
+
if (opts.limit !== void 0 && Number.isFinite(opts.limit) && opts.limit > 0) out = out.slice(0, opts.limit);
|
|
1939
|
+
return { count, records: out };
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1670
1942
|
// src/index.ts
|
|
1671
1943
|
(function migrateDataDir() {
|
|
1672
1944
|
if (process.env.SUVEREN_DATA_DIR) return;
|
|
1673
|
-
const oldDir =
|
|
1674
|
-
const newDir =
|
|
1675
|
-
if (!
|
|
1945
|
+
const oldDir = join4(homedir3(), ".hap");
|
|
1946
|
+
const newDir = join4(homedir3(), ".suveren");
|
|
1947
|
+
if (!existsSync5(newDir) && existsSync5(oldDir)) {
|
|
1676
1948
|
try {
|
|
1677
1949
|
renameSync(oldDir, newDir);
|
|
1678
1950
|
console.error(`[Control Plane] Migrated data directory: ${oldDir} \u2192 ${newDir}`);
|
|
@@ -1685,7 +1957,7 @@ data: ${data}
|
|
|
1685
1957
|
var SP_URL2 = process.env.SUVEREN_AS_URL ?? "https://www.suveren.ai";
|
|
1686
1958
|
var port = parseInt(process.env.SUVEREN_CP_PORT ?? "3402", 10);
|
|
1687
1959
|
var HAP_MODE = process.env.HAP_MODE ?? "personal";
|
|
1688
|
-
var UI_DIST = process.env.HAP_UI_DIST ??
|
|
1960
|
+
var UI_DIST = process.env.HAP_UI_DIST ?? join4(import.meta.dirname ?? __dirname, "../../ui/dist");
|
|
1689
1961
|
var vault = new Vault();
|
|
1690
1962
|
var internalSecret2 = process.env.SUVEREN_INTERNAL_SECRET ?? randomBytes2(32).toString("hex");
|
|
1691
1963
|
setInternalSecret(internalSecret2);
|
|
@@ -1919,6 +2191,7 @@ app.use("/vault", jsonParser, authGuard, createVaultRouter(vault));
|
|
|
1919
2191
|
app.use("/ai", jsonParser, authGuard, createAIRouter(vault));
|
|
1920
2192
|
app.use("/ai-prompts", jsonParser, authGuard, createAIPromptsRouter());
|
|
1921
2193
|
app.use("/mcp", jsonParser, authGuard, createMCPRouter());
|
|
2194
|
+
app.use("/autostart", jsonParser, authGuard, createAutostartRouter());
|
|
1922
2195
|
app.use("/api/encrypt-intent", jsonParser, authGuard, createEncryptIntentRouter());
|
|
1923
2196
|
app.use("/api/decrypt-intent", jsonParser, authGuard, createDecryptIntentRouter(vault));
|
|
1924
2197
|
app.use("/api/approved-intents", jsonParser, authGuard, createApprovedIntentsRouter(vault));
|
|
@@ -2033,6 +2306,21 @@ app.get("/active-authorizations", authGuard, async (_req, res) => {
|
|
|
2033
2306
|
res.status(500).json({ error: "Failed to fetch authorizations from MCP server" });
|
|
2034
2307
|
}
|
|
2035
2308
|
});
|
|
2309
|
+
app.get("/denials", authGuard, (req, res) => {
|
|
2310
|
+
try {
|
|
2311
|
+
const dataDir = process.env.SUVEREN_DATA_DIR ?? join4(homedir3(), ".suveren");
|
|
2312
|
+
const all = loadDenials(dataDir, (blob) => vault.decrypt(blob));
|
|
2313
|
+
const since = Number(req.query.since);
|
|
2314
|
+
const limit = Number(req.query.limit);
|
|
2315
|
+
res.json(selectDenials(all, {
|
|
2316
|
+
since: Number.isFinite(since) ? since : void 0,
|
|
2317
|
+
limit: Number.isFinite(limit) ? limit : void 0
|
|
2318
|
+
}));
|
|
2319
|
+
} catch (err) {
|
|
2320
|
+
console.error("[Control Plane] Denial log read error:", err);
|
|
2321
|
+
res.status(500).json({ error: "Could not read the denial log" });
|
|
2322
|
+
}
|
|
2323
|
+
});
|
|
2036
2324
|
app.post("/gate-content", jsonParser, authGuard, async (req, res) => {
|
|
2037
2325
|
try {
|
|
2038
2326
|
const { authorizationId, boundsHash, contextHash, context, contextLabels, path, gateContent } = req.body;
|
|
@@ -2053,16 +2341,16 @@ app.post("/resync-gates", authGuard, async (_req, res) => {
|
|
|
2053
2341
|
}
|
|
2054
2342
|
});
|
|
2055
2343
|
var AGENT_CONTEXT_MAX_BYTES = 16 * 1024;
|
|
2056
|
-
var SUVEREN_DATA_DIR2 = process.env.SUVEREN_DATA_DIR ??
|
|
2344
|
+
var SUVEREN_DATA_DIR2 = process.env.SUVEREN_DATA_DIR ?? join4(homedir3(), ".suveren");
|
|
2057
2345
|
app.get("/agent-brief/context", authGuard, async (_req, res) => {
|
|
2058
2346
|
try {
|
|
2059
|
-
const { readFileSync:
|
|
2060
|
-
const filePath =
|
|
2347
|
+
const { readFileSync: readFileSync5, existsSync: fileExists } = await import("fs");
|
|
2348
|
+
const filePath = join4(SUVEREN_DATA_DIR2, "context.md");
|
|
2061
2349
|
if (!fileExists(filePath)) {
|
|
2062
2350
|
res.json({ content: "" });
|
|
2063
2351
|
return;
|
|
2064
2352
|
}
|
|
2065
|
-
const content =
|
|
2353
|
+
const content = readFileSync5(filePath, "utf-8");
|
|
2066
2354
|
res.json({ content });
|
|
2067
2355
|
} catch (err) {
|
|
2068
2356
|
console.error("[Control Plane] agent-brief/context GET failed:", err);
|
|
@@ -2082,7 +2370,7 @@ app.put("/agent-brief/context", jsonParser, authGuard, async (req, res) => {
|
|
|
2082
2370
|
}
|
|
2083
2371
|
const { mkdirSync: mkdirSync3, writeFileSync: writeFileSync3, renameSync: renameSync2 } = await import("fs");
|
|
2084
2372
|
mkdirSync3(SUVEREN_DATA_DIR2, { recursive: true });
|
|
2085
|
-
const filePath =
|
|
2373
|
+
const filePath = join4(SUVEREN_DATA_DIR2, "context.md");
|
|
2086
2374
|
const tmpPath = `${filePath}.tmp`;
|
|
2087
2375
|
writeFileSync3(tmpPath, content, "utf-8");
|
|
2088
2376
|
renameSync2(tmpPath, filePath);
|
|
@@ -2134,7 +2422,7 @@ app.use(
|
|
|
2134
2422
|
})
|
|
2135
2423
|
);
|
|
2136
2424
|
function detectInstallMethod() {
|
|
2137
|
-
if (
|
|
2425
|
+
if (existsSync5("/.dockerenv")) return "docker";
|
|
2138
2426
|
const dir = import.meta.dirname ?? __dirname;
|
|
2139
2427
|
if (dir.includes("/node_modules/@suveren/gateway/")) return "npm";
|
|
2140
2428
|
return "dev";
|
|
@@ -2145,10 +2433,10 @@ function detectRunningVersion() {
|
|
|
2145
2433
|
return process.env.HAP_BUILD_SHA ?? "dev";
|
|
2146
2434
|
}
|
|
2147
2435
|
const dir = import.meta.dirname ?? __dirname;
|
|
2148
|
-
const bundlePkg =
|
|
2149
|
-
if (
|
|
2436
|
+
const bundlePkg = join4(dir, "..", "..", "package.json");
|
|
2437
|
+
if (existsSync5(bundlePkg)) {
|
|
2150
2438
|
try {
|
|
2151
|
-
const pkg = JSON.parse(
|
|
2439
|
+
const pkg = JSON.parse(readFileSync4(bundlePkg, "utf8"));
|
|
2152
2440
|
if (pkg.name === "@suveren/gateway" && typeof pkg.version === "string") {
|
|
2153
2441
|
return pkg.version;
|
|
2154
2442
|
}
|
|
@@ -2176,7 +2464,7 @@ app.get("/health", async (req, res) => {
|
|
|
2176
2464
|
}
|
|
2177
2465
|
});
|
|
2178
2466
|
});
|
|
2179
|
-
if (
|
|
2467
|
+
if (existsSync5(UI_DIST)) {
|
|
2180
2468
|
app.use(express.static(UI_DIST, {
|
|
2181
2469
|
setHeaders: (res, filePath) => {
|
|
2182
2470
|
if (filePath.endsWith("index.html")) {
|
|
@@ -2186,7 +2474,7 @@ if (existsSync3(UI_DIST)) {
|
|
|
2186
2474
|
}));
|
|
2187
2475
|
app.get("*", (_req, res) => {
|
|
2188
2476
|
res.setHeader("Cache-Control", "no-store, must-revalidate");
|
|
2189
|
-
res.sendFile(
|
|
2477
|
+
res.sendFile(join4(UI_DIST, "index.html"));
|
|
2190
2478
|
});
|
|
2191
2479
|
} else {
|
|
2192
2480
|
app.get("/", (_req, res) => {
|
|
@@ -2198,6 +2486,10 @@ if (existsSync3(UI_DIST)) {
|
|
|
2198
2486
|
}
|
|
2199
2487
|
app.listen(port, "0.0.0.0", () => {
|
|
2200
2488
|
console.error(`[Control Plane] Listening on http://0.0.0.0:${port}`);
|
|
2489
|
+
if (process.env.SUVEREN_AUTOSTART === "1" && !vault.isUnlocked()) {
|
|
2490
|
+
const { title, message } = lockedNotification(port);
|
|
2491
|
+
notify(title, message);
|
|
2492
|
+
}
|
|
2201
2493
|
console.error(`[Control Plane] SP proxy: ${SP_URL2}`);
|
|
2202
2494
|
console.error(`[Control Plane] UI dist: ${UI_DIST}`);
|
|
2203
2495
|
console.error(`[Control Plane] Internal secret: configured`);
|