feat(backend): enforce user-owned sessions
This commit is contained in:
@@ -1,25 +1,63 @@
|
||||
import type { FastifyInstance } from "fastify";
|
||||
import type { ThtRunner } from "../tht/tht-runner.js";
|
||||
import { getPrincipal } from "../auth/auth.js";
|
||||
import type { PrincipalContext } from "../auth/principal.js";
|
||||
import type { Settings } from "../settings/settings-store.js";
|
||||
|
||||
export function sqlRoutes(app: FastifyInstance, deps: { tht: ThtRunner }): void {
|
||||
export function sqlRoutes(app: FastifyInstance, deps: {
|
||||
tht: ThtRunner; getSettings: (principal: PrincipalContext) => Promise<Settings>;
|
||||
}): void {
|
||||
const runnerFor = (principal: PrincipalContext): any => {
|
||||
const runner = deps.tht as any;
|
||||
return typeof runner.withPrincipal === "function" ? runner.withPrincipal(principal) : runner;
|
||||
};
|
||||
const authorize = async (principal: PrincipalContext, id: string, workspace?: string) => {
|
||||
try {
|
||||
const runner = runnerFor(principal);
|
||||
if (typeof runner.sessionShow !== "function") return {};
|
||||
return await runner.sessionShow(id, workspace);
|
||||
}
|
||||
catch (error) {
|
||||
if (/not found|non trovata|inesistente|404/i.test(error instanceof Error ? error.message : String(error))) return undefined;
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
app.post("/sessions/:id/sql/preview", async (req, reply) => {
|
||||
const id = (req.params as any).id as string;
|
||||
const { limit, offset } = (req.body as any) ?? {};
|
||||
let principal: PrincipalContext;
|
||||
let workspace: string | undefined;
|
||||
try {
|
||||
const result = await deps.tht.sqlPreview(id, { limit, offset });
|
||||
return result;
|
||||
} catch (err: any) {
|
||||
return reply.code(500).send({ error: err.message ?? String(err) });
|
||||
principal = getPrincipal(req);
|
||||
const settings = await deps.getSettings(principal);
|
||||
workspace = settings.workspace;
|
||||
if (!await authorize(principal, id, settings.workspace)) return reply.code(404).send({ error: "session not found" });
|
||||
} catch {
|
||||
return reply.code(503).send({ error: "session storage is unavailable" });
|
||||
}
|
||||
try {
|
||||
return await runnerFor(principal).sqlPreview(id, { limit, offset }, workspace);
|
||||
} catch (error: any) {
|
||||
return reply.code(500).send({ error: error.message ?? String(error) });
|
||||
}
|
||||
});
|
||||
|
||||
app.post("/sessions/:id/sql/export", async (req, reply) => {
|
||||
const id = (req.params as any).id as string;
|
||||
let principal: PrincipalContext;
|
||||
let workspace: string | undefined;
|
||||
try {
|
||||
const result = await deps.tht.sqlExport(id);
|
||||
return result;
|
||||
} catch (err: any) {
|
||||
return reply.code(500).send({ error: err.message ?? String(err) });
|
||||
principal = getPrincipal(req);
|
||||
const settings = await deps.getSettings(principal);
|
||||
workspace = settings.workspace;
|
||||
if (!await authorize(principal, id, settings.workspace)) return reply.code(404).send({ error: "session not found" });
|
||||
} catch {
|
||||
return reply.code(503).send({ error: "session storage is unavailable" });
|
||||
}
|
||||
try {
|
||||
return await runnerFor(principal).sqlExport(id, workspace);
|
||||
} catch (error: any) {
|
||||
return reply.code(500).send({ error: error.message ?? String(error) });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user