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:
@@ -7,6 +7,7 @@ import { runEventManagerTabsSmoke } from "./browser_event_manager_tabs.js";
|
||||
import { runEventScheduleSmoke } from "./browser_event_schedule.js";
|
||||
import { runSettingsTabsSmoke } from "./browser_settings_tabs.js";
|
||||
import { runGuideTabsSmoke } from "./browser_guide_tabs.js";
|
||||
import { runAuthSmoke } from "./browser_auth.js";
|
||||
import { runObsPopupSmoke } from "./browser_obs_popup.js";
|
||||
import { runDecoderReconnectSmoke } from "./browser_decoder_reconnect.js";
|
||||
import assert from "node:assert/strict";
|
||||
@@ -144,6 +145,7 @@ try {
|
||||
await runEventScheduleSmoke({ evaluate, navigate, fill, savedState, waitFor, base });
|
||||
await runSettingsTabsSmoke({ evaluate, navigate });
|
||||
await runGuideTabsSmoke({ evaluate, navigate });
|
||||
await runAuthSmoke({ evaluate, navigate, fill, savedState, waitFor });
|
||||
await runRaceDaySmoke({ evaluate, navigate, fill, savedState, waitFor, pause, base, dialogs });
|
||||
await runRaceDayStartSequencesSmoke({ evaluate, navigate, waitFor, pause, base, dialogs });
|
||||
await runObsPopupSmoke({ evaluate, navigate, fill, savedState, waitFor, pause, base, debugPort, dialogs, realClick });
|
||||
|
||||
Reference in New Issue
Block a user