more permissions

This commit is contained in:
KingKDot
2026-07-17 22:48:43 -05:00
parent 1cdeae0bc3
commit b619658a95
6 changed files with 186 additions and 5 deletions
@@ -41,12 +41,20 @@ import {
addDashboardSession,
deleteDashboardSession,
getDashboardSessionCount,
notifyDashboardClientEvent,
safeSendViewerFrame,
getAllConsoleSessions,
getAllRdSessions,
} from "./sessionManager";
import type { ServerWebSocket } from "bun";
import type { SocketData } from "./types";
import {
createUser,
deleteUser,
getUserById,
setUserClientAccessRule,
setUserClientAccessScope,
} from "../users";
// Minimal mock ws that records sends
function mockWs(): ServerWebSocket<SocketData> {
@@ -220,6 +228,47 @@ describe("sessionManager - dashboard sessions", () => {
expect(getDashboardSessionCount()).toBeGreaterThanOrEqual(1);
expect(deleteDashboardSession("ds-1")).toBe(true);
});
test("only sends client metadata events to dashboard viewers with client access", async () => {
const username = `dashboard_scope_${Date.now().toString(36)}${Math.floor(Math.random() * 1e6).toString(36)}`;
const created = await createUser(username, "Aa1!DashboardScopeTestPass123", "operator", "test");
expect(created.success).toBe(true);
const user = getUserById(created.userId!);
expect(user).not.toBeNull();
expect(setUserClientAccessScope(user!.id, "allowlist").success).toBe(true);
expect(setUserClientAccessRule(user!.id, "dashboard-allowed", "allow").success).toBe(true);
const ws = mockWs() as any;
const sessionId = `ds-scope-${user!.id}`;
addDashboardSession({
id: sessionId,
viewer: ws,
createdAt: Date.now(),
userId: user!.id,
userRole: user!.role,
});
try {
notifyDashboardClientEvent("client_online", {
id: "dashboard-allowed",
host: "allowed-host",
ip: "192.0.2.10",
});
notifyDashboardClientEvent("client_online", {
id: "dashboard-denied",
host: "secret-host",
ip: "192.0.2.20",
});
const events = ws._sent.map((message: string) => JSON.parse(message));
expect(events).toHaveLength(1);
expect(events[0].clientId).toBe("dashboard-allowed");
expect(events[0].host).toBe("allowed-host");
} finally {
deleteDashboardSession(sessionId);
deleteUser(user!.id);
}
});
});
describe("safeSendViewerFrame", () => {
@@ -11,6 +11,7 @@ import type {
ChatViewer,
SocketData,
} from "./types";
import { canUserAccessClient, type UserRole } from "../users";
export type DashboardViewer = {
id: string;
@@ -542,6 +543,15 @@ export function notifyDashboardClientEvent(
});
for (const [id, session] of dashboardSessions) {
try {
const userId = session.userId ?? session.viewer.data.userId;
const userRole = session.userRole ?? session.viewer.data.userRole;
if (
userId === undefined ||
!userRole ||
!canUserAccessClient(userId, userRole as UserRole, info.id)
) {
continue;
}
if (viewerHasBackpressure(session.viewer)) continue;
session.viewer.send(msg);
} catch {