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>
81 lines
2.8 KiB
HTML
81 lines
2.8 KiB
HTML
{{define "content"}}
|
|
<section>
|
|
<h3>Session {{.Session.ID}}</h3>
|
|
<div class="top-grid">
|
|
<article>
|
|
<header>Session Info</header>
|
|
<table>
|
|
<tbody>
|
|
<tr><td><strong>IP</strong></td><td>{{.Session.IP}}</td></tr>
|
|
<tr><td><strong>Country</strong></td><td>{{.Session.Country}}</td></tr>
|
|
<tr><td><strong>Username</strong></td><td>{{.Session.Username}}</td></tr>
|
|
<tr><td><strong>Shell</strong></td><td>{{.Session.ShellName}}</td></tr>
|
|
<tr><td><strong>Score</strong></td><td>{{formatScore .Session.HumanScore}}</td></tr>
|
|
<tr><td><strong>Connected</strong></td><td>{{formatTime .Session.ConnectedAt}}</td></tr>
|
|
<tr>
|
|
<td><strong>Disconnected</strong></td>
|
|
<td>{{if .Session.DisconnectedAt}}{{formatTime (derefTime .Session.DisconnectedAt)}}{{else}}<mark>active</mark>{{end}}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</article>
|
|
</div>
|
|
</section>
|
|
|
|
{{if gt .EventCount 0}}
|
|
<section>
|
|
<h3>Session Replay</h3>
|
|
<div style="margin-bottom: 1rem;">
|
|
<button id="btn-play" onclick="replayPlayer.play()">Play</button>
|
|
<button id="btn-pause" onclick="replayPlayer.pause()">Pause</button>
|
|
<button id="btn-reset" onclick="replayPlayer.reset()">Reset</button>
|
|
<label for="speed-select" style="margin-left: 1rem;">Speed:</label>
|
|
<select id="speed-select" onchange="replayPlayer.setSpeed(parseFloat(this.value))">
|
|
<option value="0.5">0.5x</option>
|
|
<option value="1" selected>1x</option>
|
|
<option value="2">2x</option>
|
|
<option value="5">5x</option>
|
|
<option value="10">10x</option>
|
|
</select>
|
|
</div>
|
|
<div id="terminal" style="background: #000; padding: 4px; border-radius: 4px;"></div>
|
|
</section>
|
|
<link rel="stylesheet" href="/static/xterm.css">
|
|
<script src="/static/xterm.min.js"></script>
|
|
<script src="/static/replay.js"></script>
|
|
<script>
|
|
var replayPlayer = new ReplayPlayer("terminal", "{{.Session.ID}}");
|
|
</script>
|
|
{{else}}
|
|
<section>
|
|
<p>No recorded events for this session.</p>
|
|
</section>
|
|
{{end}}
|
|
|
|
{{if .Logs}}
|
|
<section>
|
|
<h3>Command Log</h3>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Time</th>
|
|
<th>Input</th>
|
|
<th>Output</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{range .Logs}}
|
|
<tr>
|
|
<td>{{formatTime .Timestamp}}</td>
|
|
<td><code>{{.Input}}</code></td>
|
|
<td><pre style="margin:0; white-space:pre-wrap;">{{.Output}}</pre></td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</section>
|
|
{{end}}
|
|
|
|
<p><a href="/">← Back to dashboard</a></p>
|
|
{{end}}
|