new mac update for permission issues.

This commit is contained in:
KingKDot
2026-04-13 10:49:36 -05:00
parent 66393d5ba4
commit 792de1e22c
21 changed files with 480 additions and 29 deletions
@@ -281,6 +281,20 @@ import { encodeMsgpack, decodeMsgpack } from "./msgpack-helpers.js";
scheduleOffline(msg.reason);
return;
}
if (msg.status === "permissions_denied") {
clearOfflineTimer();
desiredStreaming = false;
const missing = Array.isArray(msg.missing) ? msg.missing : [];
const labels = {
screenRecording: "Screen Recording",
accessibility: "Accessibility",
fullDiskAccess: "Full Disk Access",
};
const list = missing.map(k => labels[k] || k).join(", ");
setStreamState("error", `macOS permissions required: ${list}`);
showElevateOffer(missing);
return;
}
if (msg.status === "connecting") {
clearOfflineTimer();
setStreamState("connecting", "Connecting");
@@ -306,6 +320,102 @@ import { encodeMsgpack, decodeMsgpack } from "./msgpack-helpers.js";
}
}
function showElevateOffer(missing) {
// Remove previous elevate banner if any
const prev = document.getElementById("rdElevateBanner");
if (prev) prev.remove();
const banner = document.createElement("div");
banner.id = "rdElevateBanner";
banner.className = "flex flex-col items-center gap-3 p-4 rounded-lg border border-amber-700/70 bg-amber-900/30 text-amber-100 text-sm";
const labels = {
screenRecording: "Screen Recording",
accessibility: "Accessibility",
fullDiskAccess: "Full Disk Access",
};
const list = missing.map(k => labels[k] || k).join(", ");
banner.innerHTML = `
<div class="flex items-center gap-2">
<i class="fa-solid fa-triangle-exclamation text-amber-400"></i>
<span><strong>macOS permissions missing:</strong> ${list}</span>
</div>
<div class="text-xs text-amber-300/80">
The client needs elevated privileges to grant these permissions. Enter the user's password to elevate.
</div>
<div class="flex items-center gap-2">
<input id="rdElevatePwd" type="password" placeholder="User password" autocomplete="off"
class="px-3 py-1.5 rounded bg-slate-800 border border-slate-600 text-slate-100 text-sm focus:outline-none focus:border-amber-500" />
<button id="rdElevateBtn" class="button primary text-sm px-4 py-1.5">
<i class="fa-solid fa-bolt"></i> Elevate
</button>
<button id="rdElevateDismiss" class="button ghost text-sm px-3 py-1.5">Dismiss</button>
</div>
<div id="rdElevateStatus" class="text-xs text-slate-400 hidden"></div>
`;
// Insert banner above the canvas area
if (canvasContainer && canvasContainer.parentNode) {
canvasContainer.parentNode.insertBefore(banner, canvasContainer);
}
const elevateBtn = document.getElementById("rdElevateBtn");
const pwdInput = document.getElementById("rdElevatePwd");
const statusDiv = document.getElementById("rdElevateStatus");
const dismissBtn = document.getElementById("rdElevateDismiss");
if (dismissBtn) {
dismissBtn.addEventListener("click", () => banner.remove());
}
if (elevateBtn && pwdInput) {
elevateBtn.addEventListener("click", async () => {
const password = pwdInput.value.trim();
if (!password) {
pwdInput.focus();
return;
}
elevateBtn.disabled = true;
elevateBtn.innerHTML = '<i class="fa-solid fa-circle-notch fa-spin"></i> Elevating...';
if (statusDiv) {
statusDiv.classList.remove("hidden");
statusDiv.textContent = "Sending elevation request...";
}
try {
const res = await fetch(`/api/clients/${encodeURIComponent(activeClientId)}/command`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ action: "elevate", password }),
});
const data = await res.json();
if (data.ok) {
if (statusDiv) {
statusDiv.textContent = "Elevation successful — client is restarting with elevated permissions. It will reconnect shortly.";
statusDiv.className = "text-xs text-emerald-400";
}
elevateBtn.textContent = "Done";
// The client will disconnect and reconnect; the viewer should auto-recover
} else {
if (statusDiv) {
statusDiv.textContent = `Elevation failed: ${data.message || "Unknown error"}`;
statusDiv.className = "text-xs text-rose-400";
}
elevateBtn.disabled = false;
elevateBtn.innerHTML = '<i class="fa-solid fa-bolt"></i> Retry';
}
} catch (err) {
if (statusDiv) {
statusDiv.textContent = `Request failed: ${err.message}`;
statusDiv.className = "text-xs text-rose-400";
}
elevateBtn.disabled = false;
elevateBtn.innerHTML = '<i class="fa-solid fa-bolt"></i> Retry';
}
});
}
}
function sendCmd(type, payload) {
if (!activeClientId) {
console.warn("No active client selected");