RBAC changes + fix rev console and process view in shellcode
This commit is contained in:
@@ -1,19 +1,40 @@
|
||||
import { NAV_GROUPS } from "./nav/template.js";
|
||||
import { CAPTURE_FLAG } from "./keyboard-capture.js";
|
||||
|
||||
const PER_CLIENT_ACTIONS = [
|
||||
{ key: "console", label: "Console", icon: "fa-terminal", color: "text-emerald-400", href: (id) => `/${id}/console` },
|
||||
{ key: "hvnc", label: "HVNC", icon: "fa-desktop", color: "text-fuchsia-400", href: (id) => `/hvnc?clientId=${id}` },
|
||||
{ key: "rdp", label: "Remote Desktop", icon: "fa-display", color: "text-sky-400", href: (id) => `/remotedesktop?clientId=${id}` },
|
||||
{ key: "files", label: "File Browser", icon: "fa-folder-open", color: "text-cyan-400", href: (id) => `/${id}/files` },
|
||||
{ key: "processes", label: "Processes", icon: "fa-microchip", color: "text-orange-400", href: (id) => `/${id}/processes` },
|
||||
{ key: "keylogger", label: "Keylogger", icon: "fa-keyboard", color: "text-yellow-400", href: (id) => `/${id}/keylogger` },
|
||||
{ key: "webcam", label: "Webcam", icon: "fa-camera", color: "text-pink-400", href: (id) => `/webcam?clientId=${id}` },
|
||||
{ key: "voice", label: "Voice", icon: "fa-microphone", color: "text-indigo-400", href: (id) => `/voice?clientId=${id}` },
|
||||
{ key: "deploy", label: "Deploy", icon: "fa-rocket", color: "text-rose-400", href: (id) => `/deploy?clientId=${id}` },
|
||||
{ key: "winre", label: "WinRE", icon: "fa-shield-halved",color: "text-amber-400", href: (id) => `/winre?clientId=${id}` },
|
||||
const ALL_PER_CLIENT_ACTIONS = [
|
||||
{ key: "console", feature: "console", label: "Console", icon: "fa-terminal", color: "text-emerald-400", href: (id) => `/${id}/console` },
|
||||
{ key: "hvnc", feature: "hvnc", label: "HVNC", icon: "fa-desktop", color: "text-fuchsia-400", href: (id) => `/hvnc?clientId=${id}` },
|
||||
{ key: "rdp", feature: "remote_desktop", label: "Remote Desktop", icon: "fa-display", color: "text-sky-400", href: (id) => `/remotedesktop?clientId=${id}` },
|
||||
{ key: "files", feature: "file_browser", label: "File Browser", icon: "fa-folder-open", color: "text-cyan-400", href: (id) => `/${id}/files` },
|
||||
{ key: "processes", feature: "processes", label: "Processes", icon: "fa-microchip", color: "text-orange-400", href: (id) => `/${id}/processes` },
|
||||
{ key: "keylogger", feature: "keylogger", label: "Keylogger", icon: "fa-keyboard", color: "text-yellow-400", href: (id) => `/${id}/keylogger` },
|
||||
{ key: "webcam", feature: "webcam", label: "Webcam", icon: "fa-camera", color: "text-pink-400", href: (id) => `/webcam?clientId=${id}` },
|
||||
{ key: "voice", feature: "voice", label: "Voice", icon: "fa-microphone", color: "text-indigo-400", href: (id) => `/voice?clientId=${id}` },
|
||||
{ key: "deploy", feature: null, label: "Deploy", icon: "fa-rocket", color: "text-rose-400", href: (id) => `/deploy?clientId=${id}` },
|
||||
{ key: "winre", feature: null, label: "WinRE", icon: "fa-shield-halved",color: "text-amber-400", href: (id) => `/winre?clientId=${id}` },
|
||||
];
|
||||
|
||||
let featurePermsCache = null;
|
||||
|
||||
async function loadFeaturePerms() {
|
||||
if (featurePermsCache) return featurePermsCache;
|
||||
try {
|
||||
const res = await fetch("/api/auth/me", { credentials: "include" });
|
||||
if (!res.ok) return null;
|
||||
const data = await res.json();
|
||||
featurePermsCache = data?.featurePermissions || null;
|
||||
return featurePermsCache;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function PER_CLIENT_ACTIONS() {
|
||||
const perms = featurePermsCache;
|
||||
if (!perms) return ALL_PER_CLIENT_ACTIONS;
|
||||
return ALL_PER_CLIENT_ACTIONS.filter((a) => !a.feature || perms[a.feature] !== false);
|
||||
}
|
||||
|
||||
const RECENT_KEY = "cmdp_recent_v1";
|
||||
const RECENT_MAX = 8;
|
||||
|
||||
@@ -121,7 +142,7 @@ function buildResults(query, pages, clients) {
|
||||
}
|
||||
}
|
||||
|
||||
for (const a of PER_CLIENT_ACTIONS) {
|
||||
for (const a of PER_CLIENT_ACTIONS()) {
|
||||
const sc = score(query, a.label);
|
||||
if (sc > 0) results.push({ kind: "action", action: a, _score: sc });
|
||||
}
|
||||
@@ -309,7 +330,7 @@ function activate(idx, newTab) {
|
||||
if (r.kind === "client") {
|
||||
state.mode = "actions-for-client";
|
||||
state.pendingClient = r.client;
|
||||
state.results = PER_CLIENT_ACTIONS.map((a) => ({ kind: "client-action", client: r.client, action: a, _score: 0 }));
|
||||
state.results = PER_CLIENT_ACTIONS().map((a) => ({ kind: "client-action", client: r.client, action: a, _score: 0 }));
|
||||
state.active = 0;
|
||||
const input = document.getElementById("cmdp-input");
|
||||
if (input) { input.value = ""; input.placeholder = `Action on ${clientLabel(r.client)}…`; input.focus(); }
|
||||
@@ -334,6 +355,7 @@ async function open() {
|
||||
state.query = "";
|
||||
state.mode = "main";
|
||||
state.pendingAction = null;
|
||||
await loadFeaturePerms();
|
||||
const root = mountPalette();
|
||||
if (!root) return;
|
||||
const input = document.getElementById("cmdp-input");
|
||||
@@ -347,7 +369,7 @@ async function open() {
|
||||
if (state.mode === "actions-for-client" && state.pendingClient) {
|
||||
const q = state.query.toLowerCase();
|
||||
const c = state.pendingClient;
|
||||
state.results = PER_CLIENT_ACTIONS
|
||||
state.results = PER_CLIENT_ACTIONS()
|
||||
.map((a) => ({ a, sc: score(q, a.label) }))
|
||||
.filter((x) => x.sc > 0 || !q)
|
||||
.sort((a, b) => b.sc - a.sc)
|
||||
|
||||
@@ -274,6 +274,37 @@ function applyMenuSupportRules(clientId) {
|
||||
["ping", "reconnect", "disconnect", "uninstall"].forEach(action => {
|
||||
setAvailability(menu.querySelector(`[data-action="${action}"]`), isOnline, "Client is offline");
|
||||
});
|
||||
|
||||
applyFeaturePermissionRules();
|
||||
}
|
||||
|
||||
const MENU_OPEN_TO_FEATURE = {
|
||||
console: "console",
|
||||
remotedesktop: "remote_desktop",
|
||||
Backstage: "hvnc",
|
||||
webcam: "webcam",
|
||||
files: "file_browser",
|
||||
processes: "processes",
|
||||
keylogger: "keylogger",
|
||||
voice: "voice",
|
||||
};
|
||||
|
||||
function applyFeaturePermissionRules() {
|
||||
const perms = currentUser?.featurePermissions;
|
||||
if (!perms) return;
|
||||
|
||||
for (const [openKey, feature] of Object.entries(MENU_OPEN_TO_FEATURE)) {
|
||||
const btn = menu.querySelector(`[data-open="${openKey}"]`);
|
||||
if (!btn) continue;
|
||||
if (perms[feature] === false) {
|
||||
btn.disabled = true;
|
||||
btn.setAttribute("aria-disabled", "true");
|
||||
btn.classList.add("opacity-50", "cursor-not-allowed");
|
||||
btn.classList.remove("hover:bg-slate-700");
|
||||
btn.classList.add("hover:bg-slate-800/50");
|
||||
btn.title = "Feature access disabled by administrator";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function loadCurrentUser() {
|
||||
|
||||
Reference in New Issue
Block a user