vuln fix so mfs who aren't logged in can't check plugin shit

This commit is contained in:
KingKDot
2026-04-28 22:23:15 -05:00
parent 8232216873
commit 4808a0fbd3
2 changed files with 31 additions and 0 deletions
+1
View File
@@ -429,6 +429,7 @@ async function startServer() {
}, },
plugin: { plugin: {
PLUGIN_ROOT, PLUGIN_ROOT,
PUBLIC_ROOT,
pluginState, pluginState,
pluginLoadedByClient, pluginLoadedByClient,
pluginLoadingByClient, pluginLoadingByClient,
@@ -30,6 +30,7 @@ type PluginState = {
type PluginRouteDeps = { type PluginRouteDeps = {
PLUGIN_ROOT: string; PLUGIN_ROOT: string;
PUBLIC_ROOT: string;
pluginState: PluginState; pluginState: PluginState;
pluginLoadedByClient: Map<string, Set<string>>; pluginLoadedByClient: Map<string, Set<string>>;
pluginLoadingByClient: Map<string, Set<string>>; pluginLoadingByClient: Map<string, Set<string>>;
@@ -62,6 +63,14 @@ export async function handlePluginRoutes(
return null; return null;
} }
async function serveLoginOrUnauthorized(): Promise<Response> {
const loginFile = Bun.file(`${deps.PUBLIC_ROOT}/login.html`);
if (await loginFile.exists()) {
return new Response(loginFile, { headers: deps.secureHeaders(deps.mimeType("/login.html")) });
}
return new Response("Unauthorized", { status: 401 });
}
if (req.method === "GET" && url.pathname === "/api/plugins") { if (req.method === "GET" && url.pathname === "/api/plugins") {
if (!(await authenticateRequest(req))) { if (!(await authenticateRequest(req))) {
return new Response("Unauthorized", { status: 401 }); return new Response("Unauthorized", { status: 401 });
@@ -699,6 +708,12 @@ export async function handlePluginRoutes(
const pluginFrameMatch = url.pathname.match(/^\/plugins\/([^/]+)\/frame$/); const pluginFrameMatch = url.pathname.match(/^\/plugins\/([^/]+)\/frame$/);
if (req.method === "GET" && pluginFrameMatch) { if (req.method === "GET" && pluginFrameMatch) {
const user = await authenticateRequest(req);
if (!user) return serveLoginOrUnauthorized();
if (user.role === "viewer") {
return new Response("Forbidden: Viewers cannot access interactive features", { status: 403 });
}
let pluginId = ""; let pluginId = "";
try { try {
pluginId = deps.sanitizePluginId(pluginFrameMatch[1]); pluginId = deps.sanitizePluginId(pluginFrameMatch[1]);
@@ -728,6 +743,12 @@ export async function handlePluginRoutes(
const pluginPageMatch = url.pathname.match(/^\/plugins\/([^/]+)$/); const pluginPageMatch = url.pathname.match(/^\/plugins\/([^/]+)$/);
if (req.method === "GET" && pluginPageMatch) { if (req.method === "GET" && pluginPageMatch) {
const user = await authenticateRequest(req);
if (!user) return serveLoginOrUnauthorized();
if (user.role === "viewer") {
return new Response("Forbidden: Viewers cannot access interactive features", { status: 403 });
}
let pluginId = ""; let pluginId = "";
try { try {
pluginId = deps.sanitizePluginId(pluginPageMatch[1]); pluginId = deps.sanitizePluginId(pluginPageMatch[1]);
@@ -736,6 +757,9 @@ export async function handlePluginRoutes(
} }
const clientId = url.searchParams.get("clientId") || ""; const clientId = url.searchParams.get("clientId") || "";
if (clientId && !canUserAccessClient(user.userId, user.role, clientId)) {
return new Response("Forbidden: Client access denied", { status: 403 });
}
const htmlFile = path.join(deps.PLUGIN_ROOT, pluginId, "assets", `${pluginId}.html`); const htmlFile = path.join(deps.PLUGIN_ROOT, pluginId, "assets", `${pluginId}.html`);
const file = Bun.file(htmlFile); const file = Bun.file(htmlFile);
@@ -798,6 +822,12 @@ export async function handlePluginRoutes(
const pluginAssetMatch = url.pathname.match(/^\/plugins\/([^/]+)\/assets\/(.+)$/); const pluginAssetMatch = url.pathname.match(/^\/plugins\/([^/]+)\/assets\/(.+)$/);
if (req.method === "GET" && pluginAssetMatch) { if (req.method === "GET" && pluginAssetMatch) {
const user = await authenticateRequest(req);
if (!user) return new Response("Unauthorized", { status: 401 });
if (user.role === "viewer") {
return new Response("Forbidden: Viewers cannot access interactive features", { status: 403 });
}
const [, pluginId, assetPath] = pluginAssetMatch; const [, pluginId, assetPath] = pluginAssetMatch;
let decodedPath = assetPath; let decodedPath = assetPath;
try { try {