Files
cloud-ip-validator/internal/dashboard/templates/login.html
T
ayurishchevandClaude Sonnet 5.5 debf2afed2 Add authentication: admin/agent bearer tokens for the API, login for the dashboard
control-api: every route now carries a mandatory access level (admin / agent /
open) in a route table. All /api/v1/admin/* require the admin token; the
write calls of validator-agent and prober (self-check, events, results,
complete) require a separate static agent token; register, heartbeat and
fetching the assignment stay open. Tokens come from env vars, are compared in
constant time and never logged. An empty token leaves that level open with a
startup warning (backward compatible).

validator-agent / prober: apiclient sends the agent token only to control-api.

admin-dashboard: login/password (from env) with a stateless HMAC session
cookie, Origin-based CSRF check, per-IP brute-force throttle, HX-Redirect for
htmx polls, logout in the sidebar; the dashboard calls control-api with the
admin token. Login page layout fixed after review.

Also: env plumbing in docker-compose/rxprod-compose/systemd/config examples,
e2e script with token assertions, tests, docs (API, SETUP, USAGE, DASHBOARD,
README), plan and review under docs/changes/, bin/ rebuilt with new
SHA256SUMS.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 11:35:24 +03:00

30 lines
964 B
HTML

{{define "login_page"}}
<!doctype html>
<html lang="ru">
<head>{{template "html_head" .}}</head>
<body>
<div class="bg-grid"></div>
<main class="login-shell">
<div class="login-card">
<form class="panel" method="post" action="/login" autocomplete="on">
<div class="panel-head"><h2>Cloud IP Validator — вход</h2></div>
<div class="panel-body">
{{if .Error}}<div class="alert alert-warning" role="alert">{{.Error}}</div>{{end}}
<input type="hidden" name="next" value="{{.Next}}">
<div class="field">
<label for="login-username">Логин</label>
<input type="text" id="login-username" name="username" autocomplete="username" autofocus required>
</div>
<div class="field">
<label for="login-password">Пароль</label>
<input type="password" id="login-password" name="password" autocomplete="current-password" required>
</div>
<button type="submit" class="btn btn-primary btn-block">Войти</button>
</div>
</form>
</div>
</main>
</body>
</html>
{{end}}