From 9d336bf9dfcb85901f72c8ee50b8be825f1c0283 Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Wed, 15 Jul 2026 14:57:40 +0800 Subject: [PATCH] Merge commit from fork --- src/backend/database/routes/rbac.ts | 13 +++++++++-- src/backend/ssh/docker-container-routes.ts | 25 +++++++++++++--------- src/backend/ssh/docker.ts | 13 ++++++++++- 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/src/backend/database/routes/rbac.ts b/src/backend/database/routes/rbac.ts index 5582582f..00b878c1 100644 --- a/src/backend/database/routes/rbac.ts +++ b/src/backend/database/routes/rbac.ts @@ -362,7 +362,9 @@ router.delete( return res.status(403).json({ error: "Not host owner" }); } - await db.delete(hostAccess).where(eq(hostAccess.id, accessId)); + await db + .delete(hostAccess) + .where(and(eq(hostAccess.id, accessId), eq(hostAccess.hostId, hostId))); databaseLogger.info("Permission revoked", { operation: "rbac_permission_revoke", adminId: userId, @@ -1369,7 +1371,14 @@ router.delete( return res.status(403).json({ error: "Not snippet owner" }); } - await db.delete(snippetAccess).where(eq(snippetAccess.id, accessId)); + await db + .delete(snippetAccess) + .where( + and( + eq(snippetAccess.id, accessId), + eq(snippetAccess.snippetId, snippetId), + ), + ); res.json({ success: true, message: "Snippet access revoked" }); } catch (error) { diff --git a/src/backend/ssh/docker-container-routes.ts b/src/backend/ssh/docker-container-routes.ts index 9bb115ab..364a2803 100644 --- a/src/backend/ssh/docker-container-routes.ts +++ b/src/backend/ssh/docker-container-routes.ts @@ -9,6 +9,7 @@ const sshLogger = logger; type DockerSession = { isConnected: boolean; + userId?: string; lastActive: number; activeOperations: number; hostId?: number; @@ -46,6 +47,10 @@ export function registerDockerContainerRoutes( ): void { const getRuntime = (session: DockerSession) => session.containerRuntime ?? "docker"; + const getOwnedSession = (sessionId: string, userId: string) => { + const session = sshSessions[sessionId]; + return session?.userId === userId ? session : undefined; + }; /** * @openapi @@ -89,7 +94,7 @@ export function registerDockerContainerRoutes( }); } - const session = sshSessions[sessionId]; + const session = getOwnedSession(sessionId, userId); if (!session || !session.isConnected) { return res.status(400).json({ @@ -189,7 +194,7 @@ export function registerDockerContainerRoutes( return res.status(401).json({ error: "Authentication required" }); } - const session = sshSessions[sessionId]; + const session = getOwnedSession(sessionId, userId); if (!session || !session.isConnected) { return res.status(400).json({ @@ -287,7 +292,7 @@ export function registerDockerContainerRoutes( return res.status(401).json({ error: "Authentication required" }); } - const session = sshSessions[sessionId]; + const session = getOwnedSession(sessionId, userId); if (!session || !session.isConnected) { return res.status(400).json({ @@ -387,7 +392,7 @@ export function registerDockerContainerRoutes( return res.status(401).json({ error: "Authentication required" }); } - const session = sshSessions[sessionId]; + const session = getOwnedSession(sessionId, userId); if (!session || !session.isConnected) { return res.status(400).json({ @@ -487,7 +492,7 @@ export function registerDockerContainerRoutes( return res.status(401).json({ error: "Authentication required" }); } - const session = sshSessions[sessionId]; + const session = getOwnedSession(sessionId, userId); if (!session || !session.isConnected) { return res.status(400).json({ @@ -587,7 +592,7 @@ export function registerDockerContainerRoutes( return res.status(401).json({ error: "Authentication required" }); } - const session = sshSessions[sessionId]; + const session = getOwnedSession(sessionId, userId); if (!session || !session.isConnected) { return res.status(400).json({ @@ -687,7 +692,7 @@ export function registerDockerContainerRoutes( return res.status(401).json({ error: "Authentication required" }); } - const session = sshSessions[sessionId]; + const session = getOwnedSession(sessionId, userId); if (!session || !session.isConnected) { return res.status(400).json({ @@ -792,7 +797,7 @@ export function registerDockerContainerRoutes( return res.status(401).json({ error: "Authentication required" }); } - const session = sshSessions[sessionId]; + const session = getOwnedSession(sessionId, userId); if (!session || !session.isConnected) { return res.status(400).json({ @@ -925,7 +930,7 @@ export function registerDockerContainerRoutes( return res.status(401).json({ error: "Authentication required" }); } - const session = sshSessions[sessionId]; + const session = getOwnedSession(sessionId, userId); if (!session || !session.isConnected) { return res.status(400).json({ @@ -1040,7 +1045,7 @@ export function registerDockerContainerRoutes( return res.status(401).json({ error: "Authentication required" }); } - const session = sshSessions[sessionId]; + const session = getOwnedSession(sessionId, userId); if (!session || !session.isConnected) { return res.status(400).json({ diff --git a/src/backend/ssh/docker.ts b/src/backend/ssh/docker.ts index 3ff4066b..2a68f69e 100644 --- a/src/backend/ssh/docker.ts +++ b/src/backend/ssh/docker.ts @@ -2138,12 +2138,19 @@ app.post("/docker/ssh/keepalive", async (req, res) => { */ app.get("/docker/ssh/status", async (req, res) => { const sessionId = req.query.sessionId as string; + const userId = getRequestUserId(req); if (!sessionId) { return res.status(400).json({ error: "Session ID is required" }); } - const isConnected = !!sshSessions[sessionId]?.isConnected; + if (!userId) { + return res.status(401).json({ error: "Authentication required" }); + } + + const session = sshSessions[sessionId]; + const isConnected = + session?.userId === userId && session.isConnected === true; res.json({ success: true, connected: isConnected }); }); @@ -2193,6 +2200,10 @@ app.get("/docker/validate/:sessionId", async (req, res) => { }); } + if (session.userId !== userId) { + return res.status(403).json({ error: "Session access denied" }); + } + session.lastActive = Date.now(); session.activeOperations++;