mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
feat(web): protect launcher dashboard with token and SPA login (#1953)
Add token-based authentication for the Launcher's embedded Web Dashboard. - Ephemeral token generated in-memory each run (or via PICOCLAW_LAUNCHER_TOKEN env var) - HMAC-SHA256 session cookie (HttpOnly, SameSite=Lax, Secure when HTTPS) - Bearer token support for API/script access - Rate limiting on login (10 attempts/IP/min) - Referrer-Policy: no-referrer on all responses - POST-only logout with JSON content-type (CSRF-safe) - System tray "Copy dashboard token" action - Login page shows contextual help (console/tray/log file path) - Path traversal protection via path.Clean - X-Forwarded-Host/Port/Proto support for reverse proxy deployments - Full i18n support (English, Chinese) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Dashboard launcher token login. Uses plain fetch (not launcherFetch) to avoid
|
||||
* redirect loops on 401 while on the login page.
|
||||
*/
|
||||
export async function postLauncherDashboardLogin(
|
||||
token: string,
|
||||
): Promise<boolean> {
|
||||
const res = await fetch("/api/auth/login", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
credentials: "same-origin",
|
||||
body: JSON.stringify({ token: token.trim() }),
|
||||
})
|
||||
return res.ok
|
||||
}
|
||||
|
||||
export type LauncherAuthTokenHelp = {
|
||||
env_var_name: string
|
||||
log_file?: string
|
||||
tray_copy_menu: boolean
|
||||
console_stdout: boolean
|
||||
}
|
||||
|
||||
export type LauncherAuthStatus = {
|
||||
authenticated: boolean
|
||||
token_help?: LauncherAuthTokenHelp
|
||||
}
|
||||
|
||||
export async function getLauncherAuthStatus(): Promise<LauncherAuthStatus> {
|
||||
const res = await fetch("/api/auth/status", {
|
||||
method: "GET",
|
||||
credentials: "same-origin",
|
||||
})
|
||||
if (!res.ok) {
|
||||
throw new Error(`status ${res.status}`)
|
||||
}
|
||||
return (await res.json()) as LauncherAuthStatus
|
||||
}
|
||||
|
||||
export async function postLauncherDashboardLogout(): Promise<boolean> {
|
||||
const res = await fetch("/api/auth/logout", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
credentials: "same-origin",
|
||||
body: "{}",
|
||||
})
|
||||
return res.ok
|
||||
}
|
||||
Reference in New Issue
Block a user