Detach DB queries from HTTP request context so HTMX polling doesn't
cancel in-flight queries when the browser aborts previous XHRs. Add
indexes on login_attempts and sessions to speed up frequent dashboard
queries. Bump version to 0.17.1.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace client-side session table filtering with server-side filtering
via a new /fragments/recent-sessions htmx endpoint. Add InputBytes column
to session tables, Human score > 0 checkbox filter, and Sort by Input
Bytes option to help identify sessions with actual shell interaction.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The SVG world map uses <g> group elements for countries with complex
shapes (US, CN, RU, GB, etc.), but the JS only queried <path> elements,
causing 36 countries to be missing from the map. Also removes the SVG
<title> element that was overriding the custom tooltip.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Chart.js line/bar charts for attack trends (attempts over time,
hourly pattern), an SVG world map choropleth colored by attack origin
country, and a collapsible filter form (date range, IP, country,
username) that narrows both charts and top-N tables.
New store methods: GetAttemptsOverTime, GetHourlyPattern, GetCountryStats,
and filtered variants of dashboard stats/top-N queries. New JSON API
endpoints at /api/charts/* and an htmx fragment at
/fragments/dashboard-content for filtered table updates.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Increase minimum column width from 280px to 380px so the 3-column Top
IPs table fits without clipping. Add overflow/min-width safety net for
narrow viewports.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add visual indicators to session tables (replay badge when events exist,
exec badge for exec sessions) and a new "Top Exec Commands" table on the
dashboard. Includes EventCount field on Session, GetTopExecCommands on
Store interface, and truncateCommand template function.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bots often send commands via `ssh user@host <command>` (exec request)
rather than requesting an interactive shell. These were previously
rejected silently. Now exec commands are captured, stored on the session
record, and displayed in the web UI session detail page.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 6 new Prometheus metrics for richer observability:
- auth_attempts_by_country_total (counter by country)
- commands_executed_total (counter by shell via OnCommand callback)
- human_score (histogram of final detection scores)
- storage_login_attempts_total, storage_unique_ips, storage_sessions_total
(gauges via custom collector querying GetDashboardStats on each scrape)
Add optional bearer token authentication for the /metrics endpoint via
web.metrics_token config option. Uses crypto/subtle.ConstantTimeCompare.
Empty token (default) means no auth for backwards compatibility.
Also adds "cisco" to pre-initialized session/command metric labels.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Embeds a DB-IP Lite country MMDB (~5MB) in the binary via go:embed,
keeping the single-binary deployment story clean. Country codes are
stored alongside login attempts and sessions, shown in the dashboard
(Top IPs, Top Countries card, Recent/Active Sessions, session detail).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add internal/metrics package with dedicated Prometheus registry exposing
SSH connection, auth attempt, session, and build info metrics. Wire into
SSH server (4 instrumentation points) and web server (/metrics endpoint).
Add dockerImage output to flake.nix via dockerTools.buildLayeredImage.
Bump version to 0.7.0.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Persist byte-level I/O events from SSH sessions to SQLite and add a web
UI to replay them with original timing. Events are buffered in memory
and flushed every 2s to avoid blocking SSH I/O on database writes.
- Add session_events table (migration 002)
- Add SessionEvent type and storage methods (SQLite + MemoryStore)
- Change RecordingChannel to support multiple callbacks
- Add EventRecorder for buffered event persistence
- Add session detail page with xterm.js terminal replay
- Add /api/sessions/{id}/events JSON endpoint
- Linkify session IDs in dashboard and active sessions
- Vendor xterm.js v5.3.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement phase 2.1 (human detection) and 2.2 (notifications):
- Detection scorer computes 0.0-1.0 human likelihood from keystroke
timing variance, special key usage, typing speed, command diversity,
and session duration
- Webhook notifier sends JSON POST to configured endpoints with
deduplication, custom headers, and event filtering
- RecordingChannel gains an event callback for feeding keystrokes
to the scorer without coupling shell and detection packages
- Server wires scorer into session lifecycle with periodic updates
and threshold-based notification triggers
- Web UI shows human score in session tables with highlighting
- New config sections: [detection] and [[notify.webhooks]]
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements Phase 1.5 — an embedded web UI using Go templates, Pico CSS
(dark theme), and htmx for auto-refreshing stats and active sessions.
Adds read query methods to the Store interface (GetDashboardStats,
GetTopUsernames, GetTopPasswords, GetTopIPs, GetRecentSessions) with
implementations for both SQLite and MemoryStore. Introduces the
internal/web package with server, handlers, templates, and tests.
Web server is opt-in via [web] config section and runs alongside
SSH with graceful shutdown. Bumps version to 0.2.0.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>