@hydra-acp/browser 0.1.7 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.js +4 -3
- package/dist/config.js.map +1 -1
- package/dist/hydra/client.js +6 -0
- package/dist/hydra/client.js.map +1 -1
- package/dist/index.js +10 -13
- package/dist/index.js.map +1 -1
- package/dist/server/auth.js +6 -29
- package/dist/server/auth.js.map +1 -1
- package/dist/server/http.js +18 -42
- package/dist/server/http.js.map +1 -1
- package/dist/server/routes-agents.js +5 -3
- package/dist/server/routes-agents.js.map +1 -1
- package/dist/server/routes-config.js +5 -3
- package/dist/server/routes-config.js.map +1 -1
- package/dist/server/routes-files.js +7 -4
- package/dist/server/routes-files.js.map +1 -1
- package/dist/server/routes-root.js +151 -20
- package/dist/server/routes-root.js.map +1 -1
- package/dist/server/routes-sessions.js +22 -10
- package/dist/server/routes-sessions.js.map +1 -1
- package/dist/server/ws-bridge.js +27 -10
- package/dist/server/ws-bridge.js.map +1 -1
- package/dist/ui/index.html +10779 -415
- package/dist/util/paths.js +0 -3
- package/dist/util/paths.js.map +1 -1
- package/package.json +2 -1
package/dist/config.js
CHANGED
|
@@ -56,6 +56,8 @@ function commaList(map, key) {
|
|
|
56
56
|
.map((s) => s.trim())
|
|
57
57
|
.filter((s) => s.length > 0);
|
|
58
58
|
}
|
|
59
|
+
export const DEFAULT_DAEMON_PORT = 55514;
|
|
60
|
+
export const DEFAULT_BROWSER_PORT = 5514;
|
|
59
61
|
export function loadConfig(path = paths.configFile()) {
|
|
60
62
|
let text = "";
|
|
61
63
|
try {
|
|
@@ -67,7 +69,7 @@ export function loadConfig(path = paths.configFile()) {
|
|
|
67
69
|
const map = parseEnvFile(text);
|
|
68
70
|
const hydraDaemonUrl = process.env.HYDRA_ACP_DAEMON_URL ??
|
|
69
71
|
map.get("HYDRA_DAEMON_URL") ??
|
|
70
|
-
|
|
72
|
+
`http://127.0.0.1:${DEFAULT_DAEMON_PORT}`;
|
|
71
73
|
const hydraToken = process.env.HYDRA_ACP_TOKEN ?? map.get("HYDRA_TOKEN") ?? "";
|
|
72
74
|
if (!hydraToken) {
|
|
73
75
|
throw new Error("Missing HYDRA_ACP_TOKEN env var (or HYDRA_TOKEN config key). When run as a hydra extension, hydra injects this automatically; otherwise set it in ~/.hydra-acp-browser.conf.");
|
|
@@ -86,9 +88,8 @@ export function loadConfig(path = paths.configFile()) {
|
|
|
86
88
|
}
|
|
87
89
|
return {
|
|
88
90
|
browserHost: map.get("BROWSER_HOST") ?? "127.0.0.1",
|
|
89
|
-
browserPort: intVal(map, "BROWSER_PORT",
|
|
91
|
+
browserPort: intVal(map, "BROWSER_PORT", DEFAULT_BROWSER_PORT),
|
|
90
92
|
tls,
|
|
91
|
-
authkeyFile: expandHome(map.get("BROWSER_AUTHKEY_FILE") ?? paths.authkeyFile()),
|
|
92
93
|
linkFile: expandHome(map.get("BROWSER_LINK_FILE") ?? paths.linkFile()),
|
|
93
94
|
allowedHosts: commaList(map, "BROWSER_ALLOWED_HOSTS"),
|
|
94
95
|
fileMaxBytes: intVal(map, "BROWSER_FILE_MAX_BYTES", 256 * 1024),
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/hydra/client.js
CHANGED
|
@@ -7,6 +7,12 @@ export class HydraRestClient {
|
|
|
7
7
|
this.baseUrl = baseUrl;
|
|
8
8
|
this.token = token;
|
|
9
9
|
}
|
|
10
|
+
static forRequest(baseUrl, token) {
|
|
11
|
+
return new HydraRestClient(baseUrl, token);
|
|
12
|
+
}
|
|
13
|
+
get bearerToken() {
|
|
14
|
+
return this.token;
|
|
15
|
+
}
|
|
10
16
|
async json(method, path, body) {
|
|
11
17
|
const headers = {
|
|
12
18
|
Authorization: `Bearer ${this.token}`,
|
package/dist/hydra/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/hydra/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAExC,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;AAqBjC,MAAM,OAAO,eAAe;IAEP;IACA;IAFnB,YACmB,OAAe,EACf,KAAa;QADb,YAAO,GAAP,OAAO,CAAQ;QACf,UAAK,GAAL,KAAK,CAAQ;IAC7B,CAAC;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/hydra/client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
import { writeFileSync, chmodSync, mkdirSync } from "node:fs";
|
|
3
3
|
import { dirname } from "node:path";
|
|
4
4
|
import { loadConfig } from "./config.js";
|
|
5
|
-
import { HydraRestClient } from "./hydra/client.js";
|
|
6
|
-
import { ensureAuthkey, rotateAuthkey } from "./server/auth.js";
|
|
7
5
|
import { buildContext, createServer } from "./server/http.js";
|
|
8
6
|
import { registerSessionRoutes } from "./server/routes-sessions.js";
|
|
9
7
|
import { registerAgentRoutes } from "./server/routes-agents.js";
|
|
@@ -27,15 +25,10 @@ async function main(argv) {
|
|
|
27
25
|
printHelp();
|
|
28
26
|
return;
|
|
29
27
|
}
|
|
30
|
-
const rotate = argv.includes("--rotate-authkey");
|
|
31
28
|
const config = loadConfig();
|
|
32
29
|
setDebug(config.debug);
|
|
33
30
|
ensureLoopbackOrTls(config.browserHost, !!config.tls);
|
|
34
|
-
const
|
|
35
|
-
? rotateAuthkey(config.authkeyFile)
|
|
36
|
-
: ensureAuthkey(config.authkeyFile);
|
|
37
|
-
const rest = new HydraRestClient(config.hydraDaemonUrl, config.hydraToken);
|
|
38
|
-
const ctx = buildContext(config, rest, authkey);
|
|
31
|
+
const ctx = buildContext(config);
|
|
39
32
|
const app = createServer(ctx);
|
|
40
33
|
registerRootRoutes(app, ctx);
|
|
41
34
|
registerSessionRoutes(app, ctx);
|
|
@@ -45,11 +38,12 @@ async function main(argv) {
|
|
|
45
38
|
await app.listen({ host: config.browserHost, port: config.browserPort });
|
|
46
39
|
attachWsBridge(app.server, ctx);
|
|
47
40
|
const scheme = config.tls ? "https" : "http";
|
|
48
|
-
const url = `${scheme}://${displayHost(config.browserHost)}:${config.browserPort}
|
|
41
|
+
const url = `${scheme}://${displayHost(config.browserHost)}:${config.browserPort}/`;
|
|
49
42
|
writeLinkFile(config.linkFile, url);
|
|
50
43
|
log.info(`hydra daemon: ${config.hydraDaemonUrl}`);
|
|
51
44
|
log.info(`listening on ${scheme}://${config.browserHost}:${config.browserPort}`);
|
|
52
45
|
log.info(`Open: ${url}`);
|
|
46
|
+
log.info(`Sign in with the password set via \`hydra-acp auth password\` on the daemon host.`);
|
|
53
47
|
const shutdown = async (signal) => {
|
|
54
48
|
log.info(`received ${signal}, shutting down`);
|
|
55
49
|
try {
|
|
@@ -84,13 +78,16 @@ function printHelp() {
|
|
|
84
78
|
|
|
85
79
|
Usage:
|
|
86
80
|
hydra-acp-browser Start the server.
|
|
87
|
-
hydra-acp-browser --rotate-authkey
|
|
88
|
-
Generate a fresh authkey, kicking existing
|
|
89
|
-
browsers, and exit after starting.
|
|
90
81
|
hydra-acp-browser --help Show this message.
|
|
91
82
|
|
|
83
|
+
Set the master password on the daemon host:
|
|
84
|
+
hydra-acp auth password
|
|
85
|
+
|
|
86
|
+
Sign in by opening the printed URL in your browser and entering the
|
|
87
|
+
password.
|
|
88
|
+
|
|
92
89
|
Config: ~/.hydra-acp-browser.conf (KEY=VALUE).
|
|
93
|
-
When run as
|
|
90
|
+
When run as a hydra-acp extension, HYDRA_ACP_DAEMON_URL / HYDRA_ACP_TOKEN /
|
|
94
91
|
HYDRA_ACP_WS_URL are injected automatically.
|
|
95
92
|
`);
|
|
96
93
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/server/auth.js
CHANGED
|
@@ -1,31 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
4
|
-
import { logger } from "../util/log.js";
|
|
5
|
-
const log = logger("auth");
|
|
6
|
-
export const COOKIE_NAME = "hb_authkey";
|
|
1
|
+
import { timingSafeEqual } from "node:crypto";
|
|
2
|
+
export const COOKIE_NAME = "hb_session";
|
|
7
3
|
export const COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 30;
|
|
8
|
-
export function ensureAuthkey(path) {
|
|
9
|
-
try {
|
|
10
|
-
const existing = readFileSync(path, "utf8").trim();
|
|
11
|
-
if (existing.length >= 32) {
|
|
12
|
-
return existing;
|
|
13
|
-
}
|
|
14
|
-
log.warn(`existing authkey at ${path} too short; rotating`);
|
|
15
|
-
}
|
|
16
|
-
catch {
|
|
17
|
-
// Doesn't exist yet or unreadable; we'll create it.
|
|
18
|
-
}
|
|
19
|
-
return rotateAuthkey(path);
|
|
20
|
-
}
|
|
21
|
-
export function rotateAuthkey(path) {
|
|
22
|
-
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
23
|
-
const key = randomBytes(32).toString("hex");
|
|
24
|
-
writeFileSync(path, key + "\n", { mode: 0o600 });
|
|
25
|
-
chmodSync(path, 0o600);
|
|
26
|
-
log.info(`authkey written to ${path}`);
|
|
27
|
-
return key;
|
|
28
|
-
}
|
|
29
4
|
export function constantTimeKeyMatch(a, b) {
|
|
30
5
|
if (typeof a !== "string" || typeof b !== "string") {
|
|
31
6
|
return false;
|
|
@@ -37,8 +12,10 @@ export function constantTimeKeyMatch(a, b) {
|
|
|
37
12
|
}
|
|
38
13
|
return timingSafeEqual(aBuf, bBuf);
|
|
39
14
|
}
|
|
40
|
-
//
|
|
41
|
-
// triggers a temporary block.
|
|
15
|
+
// Per-IP rate limiter for failed auth attempts on the browser's own
|
|
16
|
+
// /login path. 10 failures in 15 min triggers a temporary block. The
|
|
17
|
+
// daemon has its own rate limiter for /v1/auth/login — this one is
|
|
18
|
+
// defense in depth for the browser-facing surface.
|
|
42
19
|
export class AuthRateLimiter {
|
|
43
20
|
entries = new Map();
|
|
44
21
|
maxFails = 10;
|
package/dist/server/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/server/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/server/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/server/http.js
CHANGED
|
@@ -3,7 +3,7 @@ import { randomBytes } from "node:crypto";
|
|
|
3
3
|
import Fastify from "fastify";
|
|
4
4
|
import { logger } from "../util/log.js";
|
|
5
5
|
import { buildSecurityContext, checkStateChanging } from "../util/csrf.js";
|
|
6
|
-
import { AuthRateLimiter, COOKIE_NAME,
|
|
6
|
+
import { AuthRateLimiter, COOKIE_NAME, parseCookies, } from "./auth.js";
|
|
7
7
|
const log = logger("http");
|
|
8
8
|
export function createServer(ctx) {
|
|
9
9
|
const httpsOptions = ctx.config.tls
|
|
@@ -16,6 +16,9 @@ export function createServer(ctx) {
|
|
|
16
16
|
logger: false,
|
|
17
17
|
https: httpsOptions ?? null,
|
|
18
18
|
});
|
|
19
|
+
app.addContentTypeParser("application/x-www-form-urlencoded", { parseAs: "string" }, (_req, body, done) => {
|
|
20
|
+
done(null, Object.fromEntries(new URLSearchParams(body)));
|
|
21
|
+
});
|
|
19
22
|
app.addHook("onRequest", async (request, reply) => {
|
|
20
23
|
const nonce = randomBytes(16).toString("base64");
|
|
21
24
|
request.cspNonce = nonce;
|
|
@@ -34,6 +37,13 @@ export function createServer(ctx) {
|
|
|
34
37
|
});
|
|
35
38
|
app.addHook("onRequest", async (request, reply) => {
|
|
36
39
|
if (request.routeOptions.config?.skipAuth) {
|
|
40
|
+
// Still surface the cookie value for skipAuth routes that might
|
|
41
|
+
// want to read it (e.g. the root handler decides login vs SPA).
|
|
42
|
+
const cookies = parseCookies(request.headers.cookie);
|
|
43
|
+
const provided = cookies.get(COOKIE_NAME);
|
|
44
|
+
if (provided && provided.length > 0) {
|
|
45
|
+
request.sessionToken = provided;
|
|
46
|
+
}
|
|
37
47
|
return;
|
|
38
48
|
}
|
|
39
49
|
if (!authenticate(request, reply, ctx)) {
|
|
@@ -62,8 +72,11 @@ function setSecurityHeaders(reply, nonce, secure) {
|
|
|
62
72
|
reply.header("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
|
|
63
73
|
}
|
|
64
74
|
}
|
|
65
|
-
// Returns true if the request
|
|
66
|
-
//
|
|
75
|
+
// Returns true if the request carries an hb_session cookie. The actual
|
|
76
|
+
// validity of the token is enforced by the daemon when this server
|
|
77
|
+
// proxies the cookie value as a bearer — a forged/expired cookie will
|
|
78
|
+
// hit a 403 on the very next daemon call and propagate to the user as a
|
|
79
|
+
// 401 here, prompting a re-login.
|
|
67
80
|
function authenticate(request, reply, ctx) {
|
|
68
81
|
const ip = request.ip ?? "unknown";
|
|
69
82
|
if (ctx.rateLimiter.isBlocked(ip)) {
|
|
@@ -73,53 +86,16 @@ function authenticate(request, reply, ctx) {
|
|
|
73
86
|
const cookies = parseCookies(request.headers.cookie);
|
|
74
87
|
const provided = cookies.get(COOKIE_NAME);
|
|
75
88
|
if (!provided) {
|
|
76
|
-
ctx.rateLimiter.recordFailure(ip);
|
|
77
|
-
reply.code(401).send({ error: "unauthorized" });
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
if (!constantTimeKeyMatch(provided, ctx.authkey)) {
|
|
81
|
-
ctx.rateLimiter.recordFailure(ip);
|
|
82
89
|
reply.code(401).send({ error: "unauthorized" });
|
|
83
90
|
return false;
|
|
84
91
|
}
|
|
85
|
-
|
|
92
|
+
request.sessionToken = provided;
|
|
86
93
|
return true;
|
|
87
94
|
}
|
|
88
|
-
|
|
89
|
-
// "redirect" (cookie set, caller should 302), "ok" (already authenticated,
|
|
90
|
-
// caller serves the SPA), or "deny" (caller serves the login instructions).
|
|
91
|
-
export function processRootAuth(request, reply, ctx) {
|
|
92
|
-
const ip = request.ip ?? "unknown";
|
|
93
|
-
if (ctx.rateLimiter.isBlocked(ip)) {
|
|
94
|
-
reply.code(429).send({ error: "rate limited" });
|
|
95
|
-
return "deny";
|
|
96
|
-
}
|
|
97
|
-
const query = (request.query ?? {});
|
|
98
|
-
if (typeof query.authkey === "string") {
|
|
99
|
-
if (constantTimeKeyMatch(query.authkey, ctx.authkey)) {
|
|
100
|
-
ctx.rateLimiter.recordSuccess(ip);
|
|
101
|
-
reply.header("Set-Cookie", buildSetCookie(ctx.authkey, {
|
|
102
|
-
secure: ctx.scheme === "https",
|
|
103
|
-
maxAgeSeconds: 60 * 60 * 24 * 30,
|
|
104
|
-
}));
|
|
105
|
-
return "redirect";
|
|
106
|
-
}
|
|
107
|
-
ctx.rateLimiter.recordFailure(ip);
|
|
108
|
-
return "deny";
|
|
109
|
-
}
|
|
110
|
-
const cookies = parseCookies(request.headers.cookie);
|
|
111
|
-
const provided = cookies.get(COOKIE_NAME);
|
|
112
|
-
if (provided && constantTimeKeyMatch(provided, ctx.authkey)) {
|
|
113
|
-
return "ok";
|
|
114
|
-
}
|
|
115
|
-
return "deny";
|
|
116
|
-
}
|
|
117
|
-
export function buildContext(config, rest, authkey) {
|
|
95
|
+
export function buildContext(config) {
|
|
118
96
|
const scheme = config.tls ? "https" : "http";
|
|
119
97
|
return {
|
|
120
98
|
config,
|
|
121
|
-
rest,
|
|
122
|
-
authkey,
|
|
123
99
|
security: buildSecurityContext(config.browserHost, config.browserPort, scheme, config.allowedHosts),
|
|
124
100
|
rateLimiter: new AuthRateLimiter(),
|
|
125
101
|
scheme,
|
package/dist/server/http.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/server/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,OAAyE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/server/http.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { HydraRestError } from "../hydra/client.js";
|
|
1
|
+
import { HydraRestClient, HydraRestError } from "../hydra/client.js";
|
|
2
2
|
export function registerAgentRoutes(app, ctx) {
|
|
3
|
-
app.get("/api/agents", async (
|
|
3
|
+
app.get("/api/agents", async (request, reply) => {
|
|
4
|
+
const token = request.sessionToken ?? ctx.config.hydraToken;
|
|
5
|
+
const client = HydraRestClient.forRequest(ctx.config.hydraDaemonUrl, token);
|
|
4
6
|
try {
|
|
5
|
-
const result = await
|
|
7
|
+
const result = await client.listAgents();
|
|
6
8
|
reply.send(result);
|
|
7
9
|
}
|
|
8
10
|
catch (err) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes-agents.js","sourceRoot":"","sources":["../../src/server/routes-agents.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"routes-agents.js","sourceRoot":"","sources":["../../src/server/routes-agents.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGrE,MAAM,UAAU,mBAAmB,CACjC,GAAoB,EACpB,GAAkB;IAElB,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QAC9C,MAAM,KAAK,GAAG,OAAO,CAAC,YAAY,IAAI,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC;QAC5D,MAAM,MAAM,GAAG,eAAe,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;QAC5E,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;YACzC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,MAAM,GAAG,GAAG,YAAY,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;YAChE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAG,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { HydraRestError } from "../hydra/client.js";
|
|
1
|
+
import { HydraRestClient, HydraRestError } from "../hydra/client.js";
|
|
2
2
|
export function registerConfigRoutes(app, ctx) {
|
|
3
|
-
app.get("/api/config", async (
|
|
3
|
+
app.get("/api/config", async (request, reply) => {
|
|
4
|
+
const token = request.sessionToken ?? ctx.config.hydraToken;
|
|
5
|
+
const client = HydraRestClient.forRequest(ctx.config.hydraDaemonUrl, token);
|
|
4
6
|
try {
|
|
5
|
-
const result = await
|
|
7
|
+
const result = await client.getConfig();
|
|
6
8
|
reply.send(result);
|
|
7
9
|
}
|
|
8
10
|
catch (err) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes-config.js","sourceRoot":"","sources":["../../src/server/routes-config.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"routes-config.js","sourceRoot":"","sources":["../../src/server/routes-config.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGrE,MAAM,UAAU,oBAAoB,CAClC,GAAoB,EACpB,GAAkB;IAElB,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QAC9C,MAAM,KAAK,GAAG,OAAO,CAAC,YAAY,IAAI,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC;QAC5D,MAAM,MAAM,GAAG,eAAe,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;QAC5E,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC;YACxC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,MAAM,GAAG,GAAG,YAAY,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;YAChE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAG,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { promises as fsp } from "node:fs";
|
|
2
2
|
import { resolve, sep } from "node:path";
|
|
3
|
+
import { HydraRestClient } from "../hydra/client.js";
|
|
3
4
|
// Resolve a request `path` (relative to the session's cwd) and verify it is
|
|
4
5
|
// inside the cwd after symlink resolution. Returns the realpath if safe,
|
|
5
6
|
// otherwise throws PathScopeError.
|
|
@@ -26,8 +27,10 @@ export class PathScopeError extends Error {
|
|
|
26
27
|
this.name = "PathScopeError";
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
|
-
async function lookupSessionCwd(ctx, sessionId) {
|
|
30
|
-
const
|
|
30
|
+
async function lookupSessionCwd(ctx, request, sessionId) {
|
|
31
|
+
const token = request.sessionToken ?? ctx.config.hydraToken;
|
|
32
|
+
const client = HydraRestClient.forRequest(ctx.config.hydraDaemonUrl, token);
|
|
33
|
+
const result = await client.listSessions({ all: true });
|
|
31
34
|
const match = result.sessions.find((s) => s.sessionId === sessionId);
|
|
32
35
|
return match?.cwd;
|
|
33
36
|
}
|
|
@@ -38,7 +41,7 @@ export function registerFileRoutes(app, ctx) {
|
|
|
38
41
|
reply.code(400).send({ error: "sessionId required" });
|
|
39
42
|
return;
|
|
40
43
|
}
|
|
41
|
-
const cwd = await lookupSessionCwd(ctx, body.sessionId);
|
|
44
|
+
const cwd = await lookupSessionCwd(ctx, request, body.sessionId);
|
|
42
45
|
if (!cwd) {
|
|
43
46
|
reply.code(404).send({ error: "session not found" });
|
|
44
47
|
return;
|
|
@@ -110,7 +113,7 @@ export function registerFileRoutes(app, ctx) {
|
|
|
110
113
|
reply.code(400).send({ error: "path required" });
|
|
111
114
|
return;
|
|
112
115
|
}
|
|
113
|
-
const cwd = await lookupSessionCwd(ctx, body.sessionId);
|
|
116
|
+
const cwd = await lookupSessionCwd(ctx, request, body.sessionId);
|
|
114
117
|
if (!cwd) {
|
|
115
118
|
reply.code(404).send({ error: "session not found" });
|
|
116
119
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes-files.js","sourceRoot":"","sources":["../../src/server/routes-files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,GAAG,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"routes-files.js","sourceRoot":"","sources":["../../src/server/routes-files.ts"],"names":[],"mappings":"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"}
|