Add authenticated LuCI remote access

This commit is contained in:
benya
2026-06-04 17:25:50 +03:00
parent b722d09edf
commit 785e502b99
13 changed files with 275 additions and 21 deletions
+8
View File
@@ -66,6 +66,7 @@ const els = {
remoteServerPort: document.querySelector("#remoteServerPort"),
remotePort: document.querySelector("#remotePort"),
remoteLocalPort: document.querySelector("#remoteLocalPort"),
remoteLuCIScheme: document.querySelector("#remoteLuCIScheme"),
remoteDuration: document.querySelector("#remoteDuration"),
createRemoteSessionBtn: document.querySelector("#createRemoteSessionBtn"),
reloadRemoteSessionsBtn: document.querySelector("#reloadRemoteSessionsBtn"),
@@ -667,6 +668,7 @@ function renderRemoteSessions(sessions) {
const canClose = ["requested", "queued", "active"].includes(session.status);
const endpoint = `${session.server_host || "-"}:${session.remote_port || "-"}`;
const connectCommand = session.remote_port ? `ssh -p ${session.remote_port} root@${session.server_host || "server"}` : "-";
const canOpenLuCI = session.status === "active" && session.luci_port;
const row = document.createElement("div");
row.className = "row remote-session-row";
row.innerHTML = `
@@ -678,10 +680,14 @@ function renderRemoteSessions(sessions) {
<span>expires ${escapeHtml(formatShortDate(session.expires_at))}</span>
<code>${escapeHtml(connectCommand)}</code>
<div class="row-actions">
<button type="button" data-action="luci" ${canOpenLuCI ? "" : "disabled"}>Open LuCI</button>
<button type="button" data-action="commands">Commands</button>
<button type="button" data-action="close" ${canClose ? "" : "disabled"}>Close</button>
</div>
`;
row.querySelector('[data-action="luci"]').addEventListener("click", () => {
window.open(`/luci/${encodeURIComponent(session.device_id)}/${encodeURIComponent(session.id)}/`, "_blank", "noopener");
});
row.querySelector('[data-action="commands"]').addEventListener("click", scrollToCommands);
row.querySelector('[data-action="close"]').addEventListener("click", () => closeRemoteSession(session.id));
els.remoteSessionList.appendChild(row);
@@ -796,6 +802,7 @@ async function createRemoteSession() {
const serverPort = Number(els.remoteServerPort.value || 2222);
const remotePort = Number(els.remotePort.value || 0);
const localPort = Number(els.remoteLocalPort.value || 22);
const luciScheme = els.remoteLuCIScheme.value || "http";
const durationSeconds = Number(els.remoteDuration.value || 900);
if (!serverHost) {
setStatus("Tunnel server is required");
@@ -811,6 +818,7 @@ async function createRemoteSession() {
server_port: serverPort,
remote_port: remotePort,
local_port: localPort,
luci_scheme: luciScheme,
duration_seconds: durationSeconds,
}),
});
+9 -2
View File
@@ -328,6 +328,13 @@
Router SSH port
<input id="remoteLocalPort" type="number" min="1" max="65535" value="22">
</label>
<label>
LuCI protocol
<select id="remoteLuCIScheme">
<option value="http">HTTP</option>
<option value="https">HTTPS</option>
</select>
</label>
<label>
Duration
<select id="remoteDuration">
@@ -337,10 +344,10 @@
<option value="7200">2 hours</option>
</select>
</label>
<button id="createRemoteSessionBtn" type="button">Open SSH access</button>
<button id="createRemoteSessionBtn" type="button">Open remote access</button>
</div>
<div class="remote-hint">
Docker/Linux: tunnel endpoint must accept SSH for user <strong>rmm-tunnel</strong> and allow reverse ports.
Active sessions provide SSH and an authenticated Open LuCI button. Choose the protocol used by this router.
</div>
<div id="remoteSessionList" class="table-list remote-session-list"></div>
</section>
+2 -1
View File
@@ -251,7 +251,7 @@ select {
.remote-form {
display: grid;
grid-template-columns: minmax(180px, 1.2fr) repeat(4, minmax(110px, 0.6fr)) auto;
grid-template-columns: minmax(180px, 1.2fr) repeat(5, minmax(110px, 0.6fr)) auto;
gap: 10px;
align-items: end;
}
@@ -780,6 +780,7 @@ select {
.command-form,
.fleet-form,
.package-grid,
.remote-form,
.health-summary,
.diagnostic-grid,
.uci-grid,