bug fixes.

This commit is contained in:
KingKDot
2026-05-18 23:07:11 -05:00
parent 59a2622b47
commit 423e41854f
14 changed files with 110 additions and 69 deletions
@@ -16,6 +16,10 @@ export async function handleChatRoutes(
});
}
if (!hasPermission(user.role, "chat:write", user.userId)) {
return new Response("Forbidden: Chat access denied", { status: 403 });
}
const beforeParam = url.searchParams.get("before");
const limitParam = url.searchParams.get("limit");
const before = beforeParam ? Number(beforeParam) : undefined;
@@ -158,11 +158,8 @@ export async function handleClientRoutes(
const user = await authenticateRequest(req);
if (!user) return new Response("Unauthorized", { status: 401 });
try {
requirePermission(user, "clients:control");
} catch (error) {
if (error instanceof Response) return error;
return new Response("Forbidden", { status: 403 });
if (user.role !== "admin") {
return new Response("Forbidden: Admin access required", { status: 403 });
}
if (req.method === "GET") {
@@ -346,11 +346,8 @@ export async function handleEnrollmentRoutes(
if (req.method === "GET" && url.pathname === "/api/enrollment/banned-ips") {
const user = await authenticateRequest(req);
if (!user) return new Response("Unauthorized", { status: 401 });
try {
requirePermission(user, "clients:enroll");
} catch (error) {
if (error instanceof Response) return error;
return new Response("Forbidden", { status: 403 });
if (user.role !== "admin") {
return new Response("Forbidden: Admin access required", { status: 403 });
}
return Response.json({ items: listBannedIps() });
@@ -360,11 +357,8 @@ export async function handleEnrollmentRoutes(
if (req.method === "DELETE" && url.pathname === "/api/enrollment/banned-ips") {
const user = await authenticateRequest(req);
if (!user) return new Response("Unauthorized", { status: 401 });
try {
requirePermission(user, "clients:enroll");
} catch (error) {
if (error instanceof Response) return error;
return new Response("Forbidden", { status: 403 });
if (user.role !== "admin") {
return new Response("Forbidden: Admin access required", { status: 403 });
}
const ipToUnban = (url.searchParams.get("ip") || "").trim();
@@ -390,11 +384,8 @@ export async function handleEnrollmentRoutes(
if (req.method === "POST" && url.pathname === "/api/enrollment/ban-ip") {
const user = await authenticateRequest(req);
if (!user) return new Response("Unauthorized", { status: 401 });
try {
requirePermission(user, "clients:enroll");
} catch (error) {
if (error instanceof Response) return error;
return new Response("Forbidden", { status: 403 });
if (user.role !== "admin") {
return new Response("Forbidden: Admin access required", { status: 403 });
}
let body: any;
@@ -2,15 +2,17 @@ import { authenticateRequest } from "../../auth";
import { AuditAction, logAudit } from "../../auditLog";
import * as clientManager from "../../clientManager";
import { getConfig, updateNotificationsConfig } from "../../config";
import { savePushSubscription, deletePushSubscription, getPushSubscriptionsByUser } from "../../db";
import { savePushSubscription, deletePushSubscriptionForUser, getPushSubscriptionsByUser } from "../../db";
import { encodeMessage } from "../../protocol";
import {
canUserAccessClient,
getUserNotificationSettings,
updateUserNotificationSettings,
} from "../../users";
import {
DEFAULT_WEBHOOK_TEMPLATE,
DEFAULT_TELEGRAM_TEMPLATE,
isPrivateOrInternalHostname,
renderNotificationTemplate,
} from "../notification-delivery";
import { getVapidPublicKey } from "../web-push";
@@ -20,7 +22,7 @@ type RequestIpProvider = {
};
type NotificationsRouteDeps = {
getNotificationScreenshot: (notificationId: string) => { format?: string; bytes: Uint8Array } | null;
getNotificationScreenshot: (notificationId: string) => { format?: string; bytes: Uint8Array; clientId?: string } | null;
secureHeaders: (contentType?: string) => HeadersInit;
};
@@ -45,6 +47,13 @@ export async function handleNotificationsConfigRoutes(
return new Response("Not found", { status: 404 });
}
if (
screenshot.clientId &&
!canUserAccessClient(user.userId, user.role, screenshot.clientId)
) {
return new Response("Not found", { status: 404 });
}
const format = (screenshot.format || "jpeg").toLowerCase();
const contentType = format === "jpg" || format === "jpeg"
? "image/jpeg"
@@ -67,8 +76,8 @@ export async function handleNotificationsConfigRoutes(
headers: { "Content-Type": "application/json" },
});
}
if (user.role === "viewer") {
return new Response("Forbidden: Viewer access denied", { status: 403 });
if (user.role !== "admin") {
return new Response("Forbidden: Admin access required", { status: 403 });
}
return Response.json({ notifications: getConfig().notifications });
}
@@ -348,6 +357,13 @@ export async function handleNotificationsConfigRoutes(
return Response.json({ error: "Invalid webhook URL" }, { status: 400 });
}
if (isPrivateOrInternalHostname(parsed.hostname.toLowerCase())) {
return Response.json(
{ error: "Webhook URL points at a private/internal address" },
{ status: 400 },
);
}
const sampleRecord = {
id: "preview-notification",
clientId: "abc123def456",
@@ -489,7 +505,7 @@ export async function handleNotificationsConfigRoutes(
return Response.json({ error: "Missing endpoint" }, { status: 400 });
}
deletePushSubscription(endpoint);
deletePushSubscriptionForUser(user.userId, endpoint);
return Response.json({ ok: true });
}
}
@@ -56,6 +56,9 @@ export async function handleSavedScriptsRoutes(
: "powershell";
const item = saveSavedScript(id, user.userId, name, content, scriptType);
if (!item) {
return Response.json({ error: "Script id already in use" }, { status: 409 });
}
return Response.json({ ok: true, item });
}
@@ -1,7 +1,7 @@
import { authenticateRequest } from "../../auth";
import { logger } from "../../logger";
import { isIpBanned } from "../../db";
import { canUserAccessClient, canUserAccessFeature } from "../../users";
import { canUserAccessClient, canUserAccessFeature, hasPermission } from "../../users";
import type { FeatureName } from "../../users";
type RequestServer = {
@@ -296,6 +296,9 @@ export async function handleWsUpgradeRoutes(
if (!user) {
return new Response("Unauthorized", { status: 401 });
}
if (!hasPermission(user.role, "chat:write", user.userId)) {
return new Response("Forbidden: Chat access denied", { status: 403 });
}
const ip = server.requestIP(req)?.address || "";
if (server.upgrade(req, { data: { role: "chat_viewer", clientId: "", ip, userRole: user.role, userId: user.userId } })) {
return new Response();