feat(auth): add optional admin PIN for all API writes
Off by default. Once a PIN is set in Settings -> System & backup, every non-GET /api/* request (plus GET /api/ammc/config) needs a signed 30-day HttpOnly cookie, which also closes the unauthenticated /api/update/run restart trigger. A 401 opens a PIN dialog and the pending save is retried after login. Reads stay open because the public overlay hydrates through GET /api/state. Optional RC_ADMIN_ALLOWED_CIDRS restricts the same routes by client address. The PIN hash and signing secret live in data/, outside the app_state blob, so they never leak through GET /api/state, exports or backups. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { decoderDiagnosticsMarkup, mountDecoderDiagnostics } from "./decoder_diagnostics_view.js";
|
||||
import { mountAuthSettings } from "./auth_view.js";
|
||||
|
||||
let activeSettingsTab = "connection";
|
||||
|
||||
@@ -496,6 +497,11 @@ export function renderSettings(deps) {
|
||||
</div>
|
||||
|
||||
<div data-settings-panel="system">
|
||||
<section class="panel mt-16">
|
||||
<div class="panel-header"><h3>${t("auth.title")}</h3></div>
|
||||
<div class="panel-body" id="authSettings"></div>
|
||||
</section>
|
||||
|
||||
<section class="panel mt-16">
|
||||
<div class="panel-header"><h3>${t("settings.update_title")}</h3></div>
|
||||
<div class="panel-body">
|
||||
@@ -634,6 +640,7 @@ Erik Eriksson;654321;4WD;Associated;;</code></pre>
|
||||
button.addEventListener("click", () => applySettingsTab(button.dataset.settingsTab));
|
||||
});
|
||||
applySettingsTab(settingsTabButtons.some((button) => button.dataset.settingsTab === activeSettingsTab) ? activeSettingsTab : "connection");
|
||||
mountAuthSettings(document.getElementById("authSettings"), { t, escapeHtml });
|
||||
|
||||
const applyRaceAudioFormValues = (form) => {
|
||||
const events = {};
|
||||
|
||||
Reference in New Issue
Block a user