feat(backend): enforce user-owned sessions
This commit is contained in:
+29
-5
@@ -5,12 +5,14 @@ import { ThtRunner } from "./tht/tht-runner.js";
|
||||
import { PiProcessManager } from "./pi/pi-process-manager.js";
|
||||
import { SseHub } from "./sse/sse-hub.js";
|
||||
import { authPreHandler } from "./auth/auth.js";
|
||||
import { getPrincipal } from "./auth/auth.js";
|
||||
import type { PrincipalContext } from "./auth/principal.js";
|
||||
import { sessionRoutes } from "./routes/sessions.js";
|
||||
import { sqlRoutes } from "./routes/sql.js";
|
||||
import { metaRoutes, type ListModelsFn } from "./routes/meta.js";
|
||||
import { settingsRoutes, effectiveSettings } from "./routes/settings.js";
|
||||
import { createPiModelLister } from "./pi/list-models.js";
|
||||
import { loadSettings, type Settings } from "./settings/settings-store.js";
|
||||
import { loadSettings, saveSettings, type Settings } from "./settings/settings-store.js";
|
||||
import { ReadinessManager } from "./runtime/readiness-manager.js";
|
||||
|
||||
export interface BuildAppDeps {
|
||||
@@ -18,7 +20,7 @@ export interface BuildAppDeps {
|
||||
mgr?: PiProcessManager;
|
||||
spawnFn?: () => any;
|
||||
listModels?: ListModelsFn;
|
||||
getSettings?: () => Settings;
|
||||
getSettings?: (principal?: PrincipalContext) => Settings | Promise<Settings>;
|
||||
readiness?: ReadinessManager;
|
||||
hub?: SseHub;
|
||||
}
|
||||
@@ -52,7 +54,28 @@ export function buildApp(config: AppConfig, deps?: BuildAppDeps): FastifyInstanc
|
||||
"Pi enabled-model configuration warning",
|
||||
),
|
||||
});
|
||||
const getSettings = deps?.getSettings ?? (() => effectiveSettings(config, loadSettings(config)));
|
||||
const runnerFor = (principal: PrincipalContext): any => {
|
||||
const candidate = tht as any;
|
||||
return typeof candidate.withPrincipal === "function" ? candidate.withPrincipal(principal) : candidate;
|
||||
};
|
||||
const getSettings = async (principal: PrincipalContext): Promise<Settings> => {
|
||||
if (deps?.getSettings) return await deps.getSettings(principal);
|
||||
const runner = runnerFor(principal);
|
||||
// The real runner persists preferences through the harness repository. The file fallback
|
||||
// only keeps older isolated route tests and externally injected runners compatible.
|
||||
if (typeof runner.preferencesGet === "function") {
|
||||
return effectiveSettings(config, await runner.preferencesGet());
|
||||
}
|
||||
return effectiveSettings(config, loadSettings(config));
|
||||
};
|
||||
const saveUserSettings = async (principal: PrincipalContext, settings: Settings): Promise<void> => {
|
||||
const runner = runnerFor(principal);
|
||||
if (typeof runner.preferencesSet === "function") {
|
||||
await runner.preferencesSet(settings);
|
||||
return;
|
||||
}
|
||||
saveSettings(config, settings);
|
||||
};
|
||||
|
||||
const authenticate = authPreHandler(config.authMode);
|
||||
app.addHook("preHandler", async (req, reply) => {
|
||||
@@ -61,12 +84,13 @@ export function buildApp(config: AppConfig, deps?: BuildAppDeps): FastifyInstanc
|
||||
return authenticate(req, reply);
|
||||
});
|
||||
app.get("/health", async () => ({ status: "ok" }));
|
||||
app.get("/me", async (req) => getPrincipal(req));
|
||||
sessionRoutes(app, {
|
||||
mgr, tht: tht as ThtRunner, hub, getSettings, readiness,
|
||||
});
|
||||
sqlRoutes(app, { tht: tht as ThtRunner });
|
||||
sqlRoutes(app, { tht: tht as ThtRunner, getSettings });
|
||||
metaRoutes(app, { harnessDir: config.harnessDir, listModels });
|
||||
settingsRoutes(app, { cfg: config, listModels });
|
||||
settingsRoutes(app, { cfg: config, listModels, getSettings, saveSettings: saveUserSettings });
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user