v0.34.10
This commit is contained in:
1 parent
66ff9dfaa2
commit
ee54aa6875
30 files changed
+939
-68
No files matched your search
@@ -0,0 +1,94 @@
|
||||
"use strict";
|
||||
(() => {
|
||||
const form = $("certificate-form"), file = $("certificate-file"), source = $("certificate-file-source");
|
||||
const names = $("certificate-hosts"), button = $("certificate-inspect"), status = $("certificate-inspect-status");
|
||||
let timer = null, sequence = 0, namesRevision = 0, resetGeneration = 0, applying = false;
|
||||
let manuallyEdited = !!names.value.trim(), pending = null, lastSuccess = "";
|
||||
|
||||
const identity = () => JSON.stringify([source.value, file.value.trim(), authEpoch]);
|
||||
function validFile() {
|
||||
const value = file.value.trim();
|
||||
return source.value === "external"
|
||||
? value.startsWith("/") && value.length <= 4096 && !/[\x00-\x1f\x7f]/.test(value)
|
||||
: value.length <= 96 && value !== "." && value !== ".." && /^[A-Za-z0-9_.-]+$/.test(value);
|
||||
}
|
||||
function message(key = "", detail = "") {
|
||||
if (key && !detail) status.dataset.i18n = key;
|
||||
else delete status.dataset.i18n;
|
||||
status.textContent = key ? `${t(key)}${detail ? ` ${detail}` : ""}` : "";
|
||||
status.classList.toggle("status-error", !!detail);
|
||||
}
|
||||
function refresh() { button.disabled = !validFile() || !!pending; }
|
||||
function invalidate() {
|
||||
clearTimeout(timer); timer = null; sequence++;
|
||||
pending?.controller.abort(); pending = null; lastSuccess = "";
|
||||
refresh();
|
||||
}
|
||||
function writeNames(value) {
|
||||
names.value = value; applying = true;
|
||||
try { names.dispatchEvent(new Event("input", { bubbles: true })); }
|
||||
finally { applying = false; }
|
||||
}
|
||||
function reset({ preserveNames = false } = {}) {
|
||||
invalidate(); manuallyEdited = preserveNames && !!names.value.trim(); namesRevision++; resetGeneration++;
|
||||
message(); refresh();
|
||||
}
|
||||
async function read(force = false) {
|
||||
clearTimeout(timer); timer = null;
|
||||
if (!authenticated || !validFile()) { refresh(); return; }
|
||||
const id = identity();
|
||||
if (!force && pending?.id === id) return pending.promise;
|
||||
if (!force && lastSuccess === id) return;
|
||||
invalidate();
|
||||
const current = sequence, epoch = authEpoch, revision = namesRevision, previousNames = names.value;
|
||||
const certFile = file.value.trim(), controller = new AbortController();
|
||||
message("certificateInspectReading");
|
||||
const active = { id, controller, promise: null };
|
||||
pending = active; refresh();
|
||||
active.promise = (async () => {
|
||||
try {
|
||||
const result = await api("/api/certificates/inspect", {
|
||||
method: "POST", body: JSON.stringify({ cert_file: certFile }), signal: controller.signal,
|
||||
});
|
||||
if (current !== sequence || epoch !== authEpoch || !authenticated || identity() !== id) return;
|
||||
const hosts = Array.isArray(result.covered_hosts) ? result.covered_hosts.filter(host => typeof host === "string") : [];
|
||||
lastSuccess = id;
|
||||
const update = revision === namesRevision && names.value === previousNames && (force || !manuallyEdited);
|
||||
if (update) { writeNames(hosts.join(", ")); manuallyEdited = false; }
|
||||
message(!hosts.length ? "certificateInspectNoNames" : update ? "certificateInspectReady" : "certificateInspectKept");
|
||||
} catch (error) {
|
||||
if (current === sequence && epoch === authEpoch && authenticated && identity() === id && error.name !== "AbortError") {
|
||||
message("certificateInspectFailed", error.message);
|
||||
}
|
||||
} finally {
|
||||
if (pending === active) { pending = null; refresh(); }
|
||||
}
|
||||
})();
|
||||
return active.promise;
|
||||
}
|
||||
function schedule() {
|
||||
invalidate();
|
||||
if (!manuallyEdited && names.value) writeNames("");
|
||||
message();
|
||||
if (validFile()) timer = setTimeout(() => { void read(); }, 400);
|
||||
}
|
||||
async function beforeSave() {
|
||||
const generation = resetGeneration;
|
||||
let id;
|
||||
do { id = identity(); await read(); }
|
||||
while (authenticated && generation === resetGeneration && id !== identity());
|
||||
return generation === resetGeneration;
|
||||
}
|
||||
names.addEventListener("input", () => {
|
||||
if (applying) return;
|
||||
manuallyEdited = true; namesRevision++;
|
||||
});
|
||||
file.addEventListener("input", schedule);
|
||||
file.addEventListener("change", () => { void read(); });
|
||||
file.addEventListener("blur", () => { void read(); });
|
||||
source.addEventListener("change", schedule);
|
||||
form.addEventListener("reset", () => reset());
|
||||
button.addEventListener("click", () => { void read(true); });
|
||||
window.rustProxyCertificateInspection = { reset, schedule, read, beforeSave, refresh };
|
||||
refresh();
|
||||
})();
|
||||
Reference in new issue
Block a user