new mac update for permission issues.
This commit is contained in:
@@ -109,6 +109,9 @@ try {
|
||||
try {
|
||||
db.run(`ALTER TABLE clients ADD COLUMN elevation TEXT`);
|
||||
} catch {}
|
||||
try {
|
||||
db.run(`ALTER TABLE clients ADD COLUMN permissions TEXT`);
|
||||
} catch {}
|
||||
|
||||
db.run(`
|
||||
CREATE TABLE IF NOT EXISTS banned_ips (
|
||||
@@ -424,8 +427,8 @@ export function upsertClientRow(
|
||||
) {
|
||||
const now = partial.lastSeen ?? Date.now();
|
||||
db.run(
|
||||
`INSERT INTO clients (id, hwid, role, ip, host, os, arch, version, user, nickname, custom_tag, custom_tag_note, monitors, country, last_seen, online, ping_ms, enrollment_status, public_key, key_fingerprint, cpu, gpu, ram, is_admin, elevation)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, COALESCE(?, 0), ?)
|
||||
`INSERT INTO clients (id, hwid, role, ip, host, os, arch, version, user, nickname, custom_tag, custom_tag_note, monitors, country, last_seen, online, ping_ms, enrollment_status, public_key, key_fingerprint, cpu, gpu, ram, is_admin, elevation, permissions)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, COALESCE(?, 0), ?, ?)
|
||||
ON CONFLICT(id) DO UPDATE SET
|
||||
hwid=COALESCE(excluded.hwid, clients.hwid),
|
||||
role=COALESCE(excluded.role, clients.role),
|
||||
@@ -450,7 +453,8 @@ export function upsertClientRow(
|
||||
gpu=COALESCE(excluded.gpu, clients.gpu),
|
||||
ram=COALESCE(excluded.ram, clients.ram),
|
||||
is_admin=COALESCE(excluded.is_admin, clients.is_admin),
|
||||
elevation=COALESCE(excluded.elevation, clients.elevation)
|
||||
elevation=COALESCE(excluded.elevation, clients.elevation),
|
||||
permissions=COALESCE(excluded.permissions, clients.permissions)
|
||||
`,
|
||||
partial.id,
|
||||
partial.hwid ?? partial.id,
|
||||
@@ -477,6 +481,7 @@ export function upsertClientRow(
|
||||
partial.ram ?? null,
|
||||
partial.isAdmin !== undefined ? (partial.isAdmin ? 1 : 0) : null,
|
||||
partial.elevation ?? null,
|
||||
partial.permissions ? JSON.stringify(partial.permissions) : null,
|
||||
);
|
||||
|
||||
if (partial.hwid) {
|
||||
@@ -736,7 +741,7 @@ export function listClients(filters: ListFilters): ListResult {
|
||||
|
||||
const rows = db
|
||||
.query<any>(
|
||||
`SELECT id, hwid, role, host, os, arch, version, user, nickname, custom_tag as customTag, custom_tag_note as customTagNote, monitors, country, last_seen as lastSeen, online, ping_ms as pingMs, bookmarked, enrollment_status as enrollmentStatus, public_key as publicKey, key_fingerprint as keyFingerprint, cpu, gpu, ram, is_admin as isAdmin, elevation, disconnect_reason as disconnectReason, disconnect_detail as disconnectDetail
|
||||
`SELECT id, hwid, role, host, os, arch, version, user, nickname, custom_tag as customTag, custom_tag_note as customTagNote, monitors, country, last_seen as lastSeen, online, ping_ms as pingMs, bookmarked, enrollment_status as enrollmentStatus, public_key as publicKey, key_fingerprint as keyFingerprint, cpu, gpu, ram, is_admin as isAdmin, elevation, permissions, disconnect_reason as disconnectReason, disconnect_detail as disconnectDetail
|
||||
FROM clients
|
||||
${whereSql}
|
||||
${orderBy}
|
||||
@@ -770,6 +775,7 @@ export function listClients(filters: ListFilters): ListResult {
|
||||
ram: c.ram || null,
|
||||
isAdmin: c.isAdmin === 1,
|
||||
elevation: c.elevation || null,
|
||||
permissions: c.permissions ? (() => { try { return JSON.parse(c.permissions); } catch { return null; } })() : null,
|
||||
disconnectReason: c.disconnectReason || null,
|
||||
disconnectDetail: c.disconnectDetail || null,
|
||||
thumbnail: getThumbnail(c.id),
|
||||
|
||||
@@ -30,6 +30,7 @@ export function handleClientsRequest(req: Request): Response {
|
||||
...item,
|
||||
isAdmin: live.isAdmin ?? item.isAdmin,
|
||||
elevation: live.elevation ?? item.elevation,
|
||||
permissions: live.permissions ?? item.permissions,
|
||||
...(live.monitorInfo?.length ? {
|
||||
monitors: live.monitorInfo.length,
|
||||
monitorInfo: live.monitorInfo,
|
||||
|
||||
@@ -666,6 +666,50 @@ export async function handleClientRoutes(
|
||||
details: "Agent uninstall requested - persistence will be removed",
|
||||
success: true,
|
||||
});
|
||||
} else if (action === "elevate") {
|
||||
if (user.role !== "admin") {
|
||||
return new Response("Forbidden: Admin access required", { status: 403 });
|
||||
}
|
||||
|
||||
const password = typeof body?.password === "string" ? body.password : "";
|
||||
if (!password) {
|
||||
return new Response("Bad request: password required", { status: 400 });
|
||||
}
|
||||
|
||||
const cmdId = uuidv4();
|
||||
const replyPromise: Promise<{ ok: boolean; message?: string }> = new Promise((resolve, reject) => {
|
||||
const timeout = setTimeout(() => {
|
||||
deps.pendingCommandReplies.delete(cmdId);
|
||||
reject(new Error("Elevation timed out"));
|
||||
}, 30_000);
|
||||
deps.pendingCommandReplies.set(cmdId, { resolve, reject, timeout, clientId: targetId });
|
||||
});
|
||||
|
||||
target.ws.send(
|
||||
encodeMessage({
|
||||
type: "command",
|
||||
commandType: "elevate",
|
||||
id: cmdId,
|
||||
payload: { password },
|
||||
}),
|
||||
);
|
||||
metrics.recordCommand("elevate");
|
||||
logAudit({
|
||||
timestamp: Date.now(),
|
||||
username: user.username,
|
||||
ip,
|
||||
action: AuditAction.COMMAND,
|
||||
targetClientId: targetId,
|
||||
success: true,
|
||||
details: "elevate (sudo)",
|
||||
});
|
||||
|
||||
try {
|
||||
const result = await replyPromise;
|
||||
return Response.json({ ok: result.ok, message: result.message || "" }, { headers: deps.CORS_HEADERS });
|
||||
} catch (error: any) {
|
||||
return Response.json({ ok: false, error: error.message || "Elevation failed" }, { status: 504 });
|
||||
}
|
||||
} else {
|
||||
success = false;
|
||||
return new Response("Bad request", { status: 400 });
|
||||
|
||||
@@ -314,6 +314,21 @@ export function handleRemoteDesktopViewerMessage(ws: ServerWebSocket<SocketData>
|
||||
switch (payload.type) {
|
||||
case "desktop_start":
|
||||
if (!state.isStreaming) {
|
||||
if (target.os === "darwin" && target.permissions) {
|
||||
const missing: string[] = [];
|
||||
if (!target.permissions.screenRecording) missing.push("screenRecording");
|
||||
if (!target.permissions.accessibility) missing.push("accessibility");
|
||||
if (missing.length > 0) {
|
||||
logger.info(`[rd] macOS permission gate: client ${clientId} missing ${missing.join(", ")}`);
|
||||
safeSendViewer(ws, {
|
||||
type: "status",
|
||||
status: "permissions_denied",
|
||||
missing,
|
||||
permissions: target.permissions,
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
sendDesktopCommand(target, "desktop_start", {});
|
||||
state.isStreaming = true;
|
||||
rdStreamingState.set(clientId, state);
|
||||
|
||||
@@ -30,6 +30,7 @@ export type ClientInfo = {
|
||||
ram?: string;
|
||||
isAdmin?: boolean;
|
||||
elevation?: string;
|
||||
permissions?: Record<string, boolean>;
|
||||
enrollmentStatus?: EnrollmentStatus;
|
||||
publicKey?: string;
|
||||
keyFingerprint?: string;
|
||||
|
||||
@@ -91,6 +91,9 @@ export function handleHello(
|
||||
info.inMemory = !!(payload as any).inMemory;
|
||||
info.isAdmin = !!(payload as any).isAdmin;
|
||||
info.elevation = typeof (payload as any).elevation === "string" ? (payload as any).elevation : info.elevation;
|
||||
if ((payload as any).permissions && typeof (payload as any).permissions === "object") {
|
||||
info.permissions = (payload as any).permissions;
|
||||
}
|
||||
info.cpu = (payload as any).cpu || info.cpu;
|
||||
info.gpu = (payload as any).gpu || info.gpu;
|
||||
info.ram = (payload as any).ram || info.ram;
|
||||
@@ -121,6 +124,7 @@ export function handleHello(
|
||||
ram: info.ram,
|
||||
isAdmin: info.isAdmin,
|
||||
elevation: info.elevation,
|
||||
permissions: info.permissions,
|
||||
lastSeen: info.lastSeen,
|
||||
online: 1,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user