feat: move session sharing and collab rooms into a plugin (B12)

This commit is contained in:
LukeGus committed 2026-09-23 23:42:46 -05:00
1 parent 791d8656a1
commit a276f6898c
207 files changed
+35771 -11072

No files matched your search

-4
View File
@@ -200,7 +200,6 @@ router.post(
enableTmuxMonitor,
enableTerminalToolbar,
enableAiAssistant,
allowSessionSharing,
showTerminalInSidebar,
showFileManagerInSidebar,
showTunnelInSidebar,
@@ -343,7 +342,6 @@ router.post(
enableTmuxMonitor: enableTmuxMonitor ? 1 : 0,
enableTerminalToolbar: enableTerminalToolbar === false ? 0 : 1,
enableAiAssistant: enableAiAssistant ? 1 : 0,
allowSessionSharing: allowSessionSharing === false ? 0 : 1,
showTerminalInSidebar: showTerminalInSidebar ? 1 : 0,
showFileManagerInSidebar: showFileManagerInSidebar ? 1 : 0,
showTunnelInSidebar: showTunnelInSidebar ? 1 : 0,
@@ -918,7 +916,6 @@ router.put(
enableTmuxMonitor,
enableTerminalToolbar,
enableAiAssistant,
allowSessionSharing,
showTerminalInSidebar,
showFileManagerInSidebar,
showTunnelInSidebar,
@@ -1064,7 +1061,6 @@ router.put(
enableTmuxMonitor: enableTmuxMonitor ? 1 : 0,
enableTerminalToolbar: enableTerminalToolbar === false ? 0 : 1,
enableAiAssistant: enableAiAssistant ? 1 : 0,
allowSessionSharing: allowSessionSharing === false ? 0 : 1,
showTerminalInSidebar: showTerminalInSidebar ? 1 : 0,
showFileManagerInSidebar: showFileManagerInSidebar ? 1 : 0,
showTunnelInSidebar: showTunnelInSidebar ? 1 : 0,
+5 -30
View File
@@ -3,10 +3,7 @@ import express, { type Request, type Response } from "express";
import { databaseLogger } from "../../utils/logger.js";
import { AuthManager } from "../../utils/auth-manager.js";
import { liveTerminalSessions } from "../../hosts/live-terminal-sessions.js";
import {
createCurrentOpenTabRepository,
createCurrentSessionShareRepository,
} from "../repositories/factory.js";
import { createCurrentOpenTabRepository } from "../repositories/factory.js";
const router = express.Router();
const authManager = AuthManager.getInstance();
@@ -298,14 +295,14 @@ router.get(
* get:
* summary: Get all active backend sessions for the current user
* description: >
* Returns live terminal sessions from the session manager, both sessions the
* caller owns and SSH sessions shared to the caller by another user (via
* an in-app session share). Used by the Active Connections panel and tab restore logic.
* Returns the live terminal sessions the caller owns. Sessions other
* users shared with the caller come from the session sharing plugin.
* Used by the Active Connections panel and tab restore logic.
* tags:
* - Open Tabs
* responses:
* 200:
* description: List of active sessions (own and shared-with-me).
* description: List of the caller's active sessions.
* content:
* application/json:
* schema:
@@ -357,28 +354,6 @@ router.get(
shareId: null as string | null,
}));
const sharedWithMe =
await createCurrentSessionShareRepository().findSharesTargetingUser(
userId,
);
for (const share of sharedWithMe) {
if (share.protocol !== "ssh") continue;
const sharedSession = liveTerminalSessions.getSession(share.sessionId);
if (!sharedSession || !sharedSession.isConnected) continue;
result.push({
sessionId: sharedSession.id,
hostId: sharedSession.hostId,
hostName: sharedSession.hostName,
tabInstanceId: sharedSession.tabInstanceId,
isConnected: sharedSession.isConnected,
createdAt: sharedSession.createdAt,
isOwnSession: false,
sharedByUsername: share.ownerUsername,
permissionLevel: share.permissionLevel,
shareId: share.id,
});
}
return res.json(result);
} catch (e) {
databaseLogger.error("Failed to get active sessions", e, {
+7 -3
View File
@@ -54,7 +54,8 @@ const requireManagePlugins = permissionManager.requirePermission(
* No auth. A shared-session or collab guest link has no session, yet its
* page still draws surfaces a plugin provides (a remote desktop stream).
* Returns only enabled plugins whose manifest sets contributes.guest,
* with the fields the browser loader needs and nothing operational.
* with the fields the browser loader needs and nothing operational,
* plus the ?view= names each serves to guests (contributes.guestViews).
* tags:
* - Plugins
* responses:
@@ -69,7 +70,7 @@ router.get("/public", async (_req: Request, res: Response) => {
if (record.state !== "enabled") return [];
const loaded = loader.get(record.id);
let manifest: {
contributes?: { guest?: boolean };
contributes?: { guest?: boolean; guestViews?: string[] };
dependencies?: Record<string, string>;
optionalDependencies?: Record<string, string>;
};
@@ -86,7 +87,10 @@ router.get("/public", async (_req: Request, res: Response) => {
version: record.version,
enabled: true,
state: loaded?.state ?? record.state,
contributes: { guest: true },
contributes: {
guest: true,
guestViews: manifest.contributes.guestViews ?? [],
},
dependencies: manifest.dependencies ?? {},
optionalDependencies: manifest.optionalDependencies ?? {},
...describePluginFrontend(loaded),
@@ -587,91 +587,6 @@ export function registerUserSettingsRoutes(
}
});
router.get("/session-sharing-enabled", authenticateJWT, async (_req, res) => {
try {
res.json({
enabled: await createCurrentSettingsRepository().getBoolean(
"session_sharing_globally_enabled",
true,
),
});
} catch (err) {
authLogger.error("Failed to get session sharing enabled setting", err);
res
.status(500)
.json({ error: "Failed to get session sharing enabled setting" });
}
});
/**
* @openapi
* /users/session-sharing-enabled:
* patch:
* summary: Update session sharing globally enabled setting (admin only)
* description: Enables or disables live session sharing instance-wide, overriding every per-host allowSessionSharing toggle.
* tags:
* - Users
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* enabled:
* type: boolean
* responses:
* 200:
* description: Setting updated.
* 403:
* description: Not authorized.
* 500:
* description: Failed to update setting.
*/
router.patch(
"/session-sharing-enabled",
authenticateJWT,
async (req, res) => {
const userId = (req as AuthenticatedRequest).userId;
try {
const actor = await getAdminActor(userId);
if (!actor) {
return res.status(403).json({ error: "Not authorized" });
}
const { enabled } = req.body;
if (typeof enabled !== "boolean") {
return res.status(400).json({ error: "enabled must be a boolean" });
}
await createCurrentSettingsRepository().set(
"session_sharing_globally_enabled",
enabled ? "true" : "false",
);
const { ipAddress, userAgent } = getRequestMeta(req);
await logAudit({
userId,
username: actor.username ?? userId,
action: "update_session_sharing_enabled",
resourceType: "setting",
details: JSON.stringify({ enabled }),
ipAddress,
userAgent,
success: true,
});
res.json({ enabled });
} catch (err) {
authLogger.error(
"Failed to update session sharing enabled setting",
err,
);
res
.status(500)
.json({ error: "Failed to update session sharing enabled setting" });
}
},
);
/**
* GET/PATCH a comma-list of private hosts an outbound feature may reach.
* Shared by notifications and Step CA; each keeps its own setting key.