v0.26.0
This commit is contained in:
1 parent
d168ee2afa
commit
ddc5c6593f
70 files changed
+2293
-594
No files matched your search
@@ -61,7 +61,7 @@ function updateAdminPreferences(patch) {
|
||||
}
|
||||
function resetAdminPreferences() { adminPreferences = null; adminPreferencesLoading = null; adminPreferencesWrite = Promise.resolve(); }
|
||||
window.rustProxyPreferences = { load: loadAdminPreferences, update: updateAdminPreferences, current: () => adminPreferences, applyTheme: applyAdminTheme };
|
||||
const PANEL_PATHS = { overview: "/overview", vhosts: "/vhosts", "web-server": "/web-server", "docker-vhosts": "/docker-vhosts", redirects: "/redirects", notfound: "/404-hosts", streams: "/streams", "acl-profiles": "/acl-profiles", tls: "/tls", traffic: "/traffic", cache: "/cache", transform: "/transform", settings: "/settings" };
|
||||
const PANEL_PATHS = { overview: "/overview", vhosts: "/vhosts", "web-server": "/web-server", "docker-vhosts": "/docker-vhosts", redirects: "/redirects", notfound: "/404-hosts", streams: "/streams", "acl-profiles": "/acl-profiles", tls: "/tls", traffic: "/traffic", cache: "/cache", transform: "/transform", filelogs: "/logs", settings: "/settings" };
|
||||
function panelFromLocation() { if (typeof location === "undefined") return "overview"; if (location.pathname === "/configuration" || location.pathname === "/logging") return "settings"; const found = Object.entries(PANEL_PATHS).find(([, path]) => path === location.pathname); return found?.[0] || "overview"; }
|
||||
let envelope = null, busy = false, connected = false, currentPanel = panelFromLocation(), previous = null;
|
||||
let samples = [], protocolSamples = { h1: [], h2: [], h3: [] }, websocketProtocolSamples = { h1: [], h2: [], h3: [] }, transformSamples = [], polling = false, toastTimer, editingBackend = null, editingRoute = null;
|
||||
@@ -162,6 +162,7 @@ function apiArea(path) {
|
||||
if (path.startsWith("/api/certificates") || path.startsWith("/api/acme")) return "tls";
|
||||
if (path.startsWith("/api/certificate-api")) return "settings";
|
||||
if (path.startsWith("/api/docker")) return "dockerVhosts";
|
||||
if (path.startsWith("/api/file-logs")) return "filelogs";
|
||||
if (path.startsWith("/api/logs")) return "logging";
|
||||
if (path.startsWith("/api/audit") || path.startsWith("/api/preferences") || path.startsWith("/api/auth/password") || path.startsWith("/api/auth/logout")) return "security";
|
||||
return null;
|
||||
@@ -194,6 +195,7 @@ function setPanel(name, navigate = true) {
|
||||
if (navigate && typeof location !== "undefined" && ["http:", "https:"].includes(location.protocol) && location.pathname !== PANEL_PATHS[name]) history.pushState({ panel: name }, "", PANEL_PATHS[name]);
|
||||
if (name === "settings") window.rustProxySettings?.syncLocation?.();
|
||||
if (name === "tls") window.rustProxyAcme?.syncLocation?.();
|
||||
if (name === "filelogs") void window.rustProxyFileLogs?.refresh();
|
||||
if (name === "traffic") void window.rustProxyTrafficPanel?.refresh(); if (name === "cache") void window.rustProxyCachePanel?.refresh(); if (name === "transform") void window.rustProxyTransformPanel?.refresh(); if (name === "docker-vhosts") void window.rustProxyDocker?.refresh(false); if (name === "tls") { void window.rustProxyAcme?.refresh(); void refreshCertificateInventory().then(() => { if (authenticated && currentPanel === "tls") renderCertificates(); }); }
|
||||
}
|
||||
function bytes(value) { if (value < 1024) return `${value} B`; for (const unit of ["KiB", "MiB", "GiB", "TiB"]) { value /= 1024; if (value < 1024 || unit === "TiB") return `${value.toFixed(value < 10 ? 1 : 0)} ${unit}`; } }
|
||||
@@ -342,7 +344,7 @@ function authReturnDestination() {
|
||||
}
|
||||
function lock(notify = true) {
|
||||
const destination = pendingAuthDestination || authReturnDestination(), navigating = typeof location !== "undefined" && (location.protocol === "http:" || location.protocol === "https:");
|
||||
pendingAuthDestination = destination; if (notify) adminAuthChannel?.postMessage("locked"); $("api-docs").hidden = true; resetAdminPreferences(); window.rustProxyCertificates?.reset(); window.rustProxySettings?.reset(); window.rustProxyTrafficPanel?.reset(); window.rustProxyCachePanel?.reset(); window.rustProxyTransformPanel?.reset(); window.rustProxyAcme?.reset(); window.rustProxyIntegrations?.reset(); window.rustProxyLogs?.reset(); $("logs-open").hidden = true; window.rustProxyAclProfiles?.reset(); window.rustProxyVhosts?.reset(); window.rustProxyWebServer?.reset(); window.rustProxyDocker?.reset(); window.rustProxyRedirects?.reset(); window.rustProxyNotFound?.reset(); window.rustProxyStreams?.reset(); authEpoch++; stopLive(); csrf = ""; authenticated = false; sessionInfo = null; envelope = null; certificateInventory = new Map(); previous = null; samples = []; protocolSamples = { h1: [], h2: [], h3: [] }; transformSamples = []; systemSamples = []; connectionOpenSamples = []; connectionExchangeSamples = []; networkInterfaceSamples.clear(); lastLogs = null; latestStatus = null; clearSettingsDirty(); connected = false; busy = false; $("workspace").hidden = true; $("login").hidden = navigating; $("logout").hidden = true; $("password").value = ""; $("password-confirm").value = ""; $("setup-token").value = ""; $("password-form").reset(); $("config-editor").value = ""; $("logs").replaceChildren(); $("audit-rows").replaceChildren(); authMessage("");
|
||||
pendingAuthDestination = destination; if (notify) adminAuthChannel?.postMessage("locked"); $("api-docs").hidden = true; resetAdminPreferences(); window.rustProxyCertificates?.reset(); window.rustProxySettings?.reset(); window.rustProxyTrafficPanel?.reset(); window.rustProxyCachePanel?.reset(); window.rustProxyTransformPanel?.reset(); window.rustProxyAcme?.reset(); window.rustProxyIntegrations?.reset(); window.rustProxyLogs?.reset(); window.rustProxyFileLogs?.reset(); $("logs-open").hidden = true; $("file-logs-open").hidden = true; window.rustProxyAclProfiles?.reset(); window.rustProxyVhosts?.reset(); window.rustProxyWebServer?.reset(); window.rustProxyDocker?.reset(); window.rustProxyRedirects?.reset(); window.rustProxyNotFound?.reset(); window.rustProxyStreams?.reset(); authEpoch++; stopLive(); csrf = ""; authenticated = false; sessionInfo = null; envelope = null; certificateInventory = new Map(); previous = null; samples = []; protocolSamples = { h1: [], h2: [], h3: [] }; transformSamples = []; systemSamples = []; connectionOpenSamples = []; connectionExchangeSamples = []; networkInterfaceSamples.clear(); lastLogs = null; latestStatus = null; clearSettingsDirty(); connected = false; busy = false; $("workspace").hidden = true; $("login").hidden = navigating; $("logout").hidden = true; $("password").value = ""; $("password-confirm").value = ""; $("setup-token").value = ""; $("password-form").reset(); $("config-editor").value = ""; $("logs").replaceChildren(); $("audit-rows").replaceChildren(); authMessage("");
|
||||
for (const id of ["certificate-list", "host-policy-list"]) { $(id)?.replaceChildren(); }
|
||||
$("workspace").querySelectorAll("form").forEach(form => form.reset());
|
||||
$("workspace").querySelectorAll("input:not([type=checkbox]):not([type=radio]),textarea").forEach(input => { input.value = ""; });
|
||||
@@ -353,7 +355,7 @@ function lock(notify = true) {
|
||||
if (navigating) { document.documentElement.classList.add("app-loading"); location.replace(destination); }
|
||||
}
|
||||
|
||||
async function activate(info) { pendingAuthDestination = null; authMessage(""); $("api-docs").hidden = false; $("logs-open").hidden = false; authEpoch++; sessionInfo = info; csrf = info.csrf_token; authenticated = true; const preferences = await loadAdminPreferences(); window.rustProxyLogs?.applyPreferences(preferences); window.rustProxyVhosts?.applyPreferences(preferences); await loadConfig(); $("password").value = ""; $("password-confirm").value = ""; $("setup-token").value = ""; $("login").hidden = true; $("workspace").hidden = false; $("logout").hidden = false; renderSession(); await refresh(true); startLive(); document.documentElement.classList.remove("app-loading"); }
|
||||
async function activate(info) { pendingAuthDestination = null; authMessage(""); $("api-docs").hidden = false; $("logs-open").hidden = false; $("file-logs-open").hidden = false; authEpoch++; sessionInfo = info; csrf = info.csrf_token; authenticated = true; const preferences = await loadAdminPreferences(); window.rustProxyLogs?.applyPreferences(preferences); window.rustProxyVhosts?.applyPreferences(preferences); await loadConfig(); $("password").value = ""; $("password-confirm").value = ""; $("setup-token").value = ""; $("login").hidden = true; $("workspace").hidden = false; $("logout").hidden = false; renderSession(); await refresh(true); startLive(); document.documentElement.classList.remove("app-loading"); }
|
||||
async function loadAudit() { if (!authenticated) return; const epoch = authEpoch; try { const data = await api("/api/audit"); if (!authenticated || epoch !== authEpoch) return; const rows = data.entries.map(item => { const tr = el("tr"); for (const value of [new Date(item.time * 1000).toLocaleString(locale()), item.actor, item.action, item.detail]) { const td = el("td", value); td.title = value; tr.append(td); } return tr; }); $("audit-rows").replaceChildren(...rows); $("empty-audit").hidden = rows.length > 0; } catch (e) { toast(e.message, true); } }
|
||||
let tunnelRefreshTimer = null;
|
||||
function tunnelMessage(value = "", error = false) { const node = $("tunnels-status"); if (!node) return; node.textContent = value; node.classList.toggle("error", !!error); }
|
||||
|
||||
@@ -6,7 +6,7 @@ function renderSettings() {
|
||||
if (!settingsDirty.has("response-form")) {
|
||||
const server = config.server_header || {}, compression = config.compression || {}, diagnostics = config.diagnostic_headers || {};
|
||||
$("expose-request-id").checked = !!diagnostics.request_id;
|
||||
$("server-mode").value = server.mode || "preserve"; $("server-value").value = server.value || "RustProxy/v0.25.7";
|
||||
$("server-mode").value = server.mode || "preserve"; $("server-value").value = server.value || "RustProxy/v0.26.0";
|
||||
for (const name of ["gzip", "br", "zstd", "deflate"]) $(`compress-${name}`).checked = !!compression[name];
|
||||
$("compress-min").value = compression.min_bytes ?? 1024; syncServerMode();
|
||||
}
|
||||
@@ -296,14 +296,14 @@ bindSettingsForm("transform-form", next => {
|
||||
max_inflight: Number($("transform-max-inflight").value)
|
||||
};
|
||||
}, "transform");
|
||||
const LOGGING_SOURCE_FIELDS = ["vhost", "route", "cache_effective_enabled", "transform_effective_enabled", "backend", "id", "time_ms", "method", "host", "path", "http_version", "transport", "websocket_bootstrap", "websocket_phase", "websocket_error", "h3_reset_code", "upstream_status", "upstream_error", "client_ip", "user_agent", "country", "status", "duration_ms", "request_bytes", "response_bytes", "outcome", "cache", "cache_reason"];
|
||||
const LOGGING_SOURCE_FIELDS = ["event", "protocol_error", "error_detail", "local_addr", "tls_sni", "vhost", "route", "cache_effective_enabled", "transform_effective_enabled", "backend", "id", "time_ms", "method", "host", "path", "http_version", "transport", "websocket_bootstrap", "websocket_phase", "websocket_error", "h3_reset_code", "upstream_status", "upstream_error", "client_ip", "user_agent", "country", "status", "duration_ms", "request_bytes", "response_bytes", "outcome", "cache", "cache_reason"];
|
||||
const LOGGING_PRESETS = {
|
||||
standard: {},
|
||||
minimal: { time_ms: "time_ms", method: "method", host: "host", path: "path", status: "status", duration_ms: "duration_ms" },
|
||||
nginx: { time_ms: "time_ms", remote_addr: "client_ip", http_user_agent: "user_agent", country: "country", request_method: "method", host: "host", request_uri: "path", status: "status", request_time_ms: "duration_ms", request_length: "request_bytes", bytes_sent: "response_bytes", upstream: "backend", cache: "cache", cache_reason: "cache_reason" },
|
||||
ecs: { "event.created_ms": "time_ms", "client.address": "client_ip", "user_agent.original": "user_agent", "client.geo.country_iso_code": "country", "http.request.method": "method", "server.address": "host", "url.path": "path", "http.response.status_code": "status", "event.duration_ms": "duration_ms", "http.request.body.bytes": "request_bytes", "http.response.body.bytes": "response_bytes", "service.target.name": "backend", "event.outcome": "outcome", "cache.result": "cache", "cache.reason": "cache_reason" }
|
||||
};
|
||||
const LOGGING_PREVIEW_VALUES = { vhost: "app", route: "root", cache_effective_enabled: true, transform_effective_enabled: false, backend: "origin-1", id: 1842, time_ms: 1769328123456, method: "CONNECT", host: "app.example", path: "/socket.io/", http_version: "3", transport: "h3", websocket_bootstrap: "h3_extended_connect", websocket_phase: "tunnel_closed", websocket_error: null, h3_reset_code: null, upstream_status: 101, client_ip: "203.0.113.24", user_agent: "Mozilla/5.0 RustProxy-Test", country: "PL", status: 200, duration_ms: 12, request_bytes: 0, response_bytes: 4821, outcome: "websocket_closed", cache: "BYPASS", cache_reason: "request_upgrade" };
|
||||
const LOGGING_PREVIEW_VALUES = { event: "request", protocol_error: null, error_detail: null, local_addr: "192.0.2.1:443", tls_sni: "app.example", vhost: "app", route: "root", cache_effective_enabled: true, transform_effective_enabled: false, backend: "origin-1", id: 1842, time_ms: 1769328123456, method: "CONNECT", host: "app.example", path: "/socket.io/", http_version: "3", transport: "h3", websocket_bootstrap: "h3_extended_connect", websocket_phase: "tunnel_closed", websocket_error: null, h3_reset_code: null, upstream_status: 101, client_ip: "203.0.113.24", user_agent: "Mozilla/5.0 RustProxy-Test", country: "PL", status: 200, duration_ms: 12, request_bytes: 0, response_bytes: 4821, outcome: "websocket_closed", cache: "BYPASS", cache_reason: "request_upgrade" };
|
||||
function parseJsonObjectValue(value, target = null) { let parsed; try { parsed = JSON.parse(value || "{}"); } catch { throw fieldError(target, t("loggingJsonInvalid")); } if (!parsed || Array.isArray(parsed) || typeof parsed !== "object") throw fieldError(target, t("loggingJsonInvalid")); return parsed; }
|
||||
function loggingMappingKey(mapping) { return JSON.stringify(Object.entries(mapping || {}).sort(([a], [b]) => a.localeCompare(b))); }
|
||||
function detectLoggingPreset(mapping) { const key = loggingMappingKey(mapping); for (const [name, preset] of Object.entries(LOGGING_PRESETS)) if (loggingMappingKey(preset) === key) return name; return "custom"; }
|
||||
|
||||
Reference in new issue
Block a user