Restyle fake UI and inputs, hide scrollbars

This commit is contained in:
dan
2025-12-06 19:34:00 +03:00
parent 2ea0140cf6
commit 096628b25f
6 changed files with 331 additions and 127 deletions

View File

@@ -200,6 +200,10 @@ public class FakeAdminResponder {
const textEl = document.getElementById('typed-text');
const pick = (list) => list[Math.floor(Math.random() * list.length)];
const specialLink = {
text: 'Your special guide to get flag!',
href: 'https://youtu.be/rrw-Pv3rc0E?si=-ZQmhZVxh4HF6luD'
};
function renderImage() {
const chosen = (images && images.length) ? pick(images) : '';
@@ -242,25 +246,45 @@ public class FakeAdminResponder {
function typewriter() {
const phrase = pick(phrases);
const isSpecial = phrase === specialLink.text;
textEl.textContent = '';
let linkEl = null;
if (isSpecial) {
linkEl = document.createElement('a');
linkEl.href = specialLink.href;
linkEl.target = '_blank';
linkEl.rel = 'noreferrer noopener';
linkEl.style.color = '#aaf6ff';
textEl.appendChild(linkEl);
}
let i = 0;
const typeDelay = phrase.length ? 5000 / phrase.length : 120;
const typeInterval = setInterval(() => {
textEl.textContent += phrase.charAt(i);
const target = isSpecial ? linkEl : textEl;
target.textContent += phrase.charAt(i);
i++;
if (i >= phrase.length) {
clearInterval(typeInterval);
setTimeout(() => erase(phrase), 3000);
setTimeout(() => erase(phrase, isSpecial), 3000);
}
}, typeDelay);
}
function erase(phrase) {
function erase(phrase, isSpecial) {
const eraseDelay = phrase.length ? 2000 / phrase.length : 80;
const eraser = setInterval(() => {
textEl.textContent = textEl.textContent.slice(0, -1);
if (!textEl.textContent.length) {
const target = isSpecial ? textEl.querySelector('a') : textEl;
if (!target) {
clearInterval(eraser);
setTimeout(typewriter, 200);
return;
}
target.textContent = target.textContent.slice(0, -1);
if (!target.textContent.length) {
if (isSpecial) {
target.remove();
}
clearInterval(eraser);
setTimeout(typewriter, 200);
}
@@ -284,158 +308,323 @@ public class FakeAdminResponder {
<html lang="en">
<head>
<meta charset="UTF-8">
<title>0xb00b5 team Packmate // fake packets</title>
<title>0xb00b5 PM // packets</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.2/css/bootstrap.min.css">
<style>
@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&family=JetBrains+Mono:wght@500&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&family=JetBrains+Mono:wght@400;600&display=swap');
:root {
--bg: #04040f;
--accent: #ff5fd2;
--accent-2: #59f3ff;
--glass: rgba(8, 12, 30, 0.85);
--bg: #05030a;
--bg-2: #0a0a18;
--panel: rgba(9, 7, 18, 0.9);
--panel-strong: rgba(14, 10, 24, 0.95);
--accent: #c66bff;
--accent-2: #7a1dff;
--text: #e6e0ff;
--muted: #9b90c8;
--mono: 'JetBrains Mono', 'Ubuntu Mono', monospace;
--pixel: 'Press Start 2P', 'JetBrains Mono', monospace;
}
* { box-sizing: border-box; }
* { box-sizing: border-box; scrollbar-width: none; }
*::-webkit-scrollbar { width: 0; height: 0; }
body {
margin: 0;
min-height: 100vh;
background: linear-gradient(160deg, #04040f 0%, #06081a 50%, #0b1535 100%);
color: #e9f7ff;
font-family: 'Press Start 2P', 'JetBrains Mono', monospace;
padding: 34px 18px 60px;
}
.matrix {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 14px;
margin-bottom: 18px;
}
.banner {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 10px 12px;
border-radius: 12px;
border: 1px solid rgba(89, 243, 255, 0.35);
box-shadow: 0 0 12px rgba(89, 243, 255, 0.25);
background: rgba(6, 18, 40, 0.8);
margin-bottom: 16px;
}
.card {
background: var(--glass);
border: 1px solid rgba(255, 95, 210, 0.35);
border-radius: 16px;
padding: 12px 14px;
box-shadow: 0 0 18px rgba(255, 95, 210, 0.18);
}
.card h3 {
margin: 0 0 8px;
font-size: 14px;
color: #ffb3f1;
}
.card .meta {
font-size: 10px;
letter-spacing: 0.5px;
color: rgba(233, 247, 255, 0.8);
}
.storm {
background: rgba(6, 12, 28, 0.9);
border-radius: 16px;
border: 1px solid rgba(89, 243, 255, 0.35);
box-shadow: inset 0 0 24px rgba(0,0,0,0.4), 0 0 14px rgba(89, 243, 255, 0.2);
padding: 16px;
height: 320px;
background:
radial-gradient(circle at 18% 24%, rgba(198, 107, 255, 0.18), transparent 25%),
radial-gradient(circle at 82% 12%, rgba(122, 29, 255, 0.12), transparent 25%),
linear-gradient(135deg, #020107 0%, #0a0820 50%, #03010b 100%);
color: var(--text);
font-family: var(--pixel);
letter-spacing: 0.6px;
overflow: hidden;
}
.bg-lines {
position: fixed; inset: 0; pointer-events: none; z-index: 0;
background-image: linear-gradient(rgba(122, 29, 255, 0.1) 1px, transparent 1px),
linear-gradient(90deg, rgba(198, 107, 255, 0.12) 1px, transparent 1px);
background-size: 120px 120px;
}
.app-shell {
position: relative;
z-index: 1;
}
.navbar {
background: var(--panel-strong);
border-bottom: 1px solid rgba(122, 29, 255, 0.45);
box-shadow: 0 10px 35px rgba(0, 0, 0, 0.55), 0 0 28px rgba(122, 29, 255, 0.35);
padding: 12px 18px;
}
.brand {
display: flex;
align-items: center;
gap: 10px;
color: var(--accent);
}
.brand .dot {
width: 12px;
height: 12px;
border-radius: 50%;
background: linear-gradient(135deg, var(--accent), var(--accent-2));
box-shadow: 0 0 10px rgba(122, 29, 255, 0.65);
}
.metrics {
display: flex;
gap: 10px;
align-items: center;
margin-left: 12px;
flex-wrap: wrap;
}
.chip {
background: rgba(122, 29, 255, 0.12);
border: 1px solid rgba(122, 29, 255, 0.28);
color: var(--text);
padding: 8px 10px;
border-radius: 10px;
display: grid;
grid-template-columns: auto auto;
column-gap: 8px;
align-items: center;
font-size: 11px;
box-shadow: 0 0 14px rgba(122, 29, 255, 0.24);
}
.chip .label { color: var(--muted); }
.chip .value { color: var(--accent); }
.patterns-dropdown {
display: inline-flex;
width: 128px;
min-width: 128px;
max-width: 128px;
flex: 0 0 128px;
flex-shrink: 0;
box-sizing: border-box;
margin-left: 14px;
}
.patterns-dropdown > button {
display: inline-flex;
justify-content: center;
align-items: center;
font-family: var(--pixel);
font-size: 9.6px;
letter-spacing: 0.05px;
width: 128px;
min-width: 128px;
max-width: 128px;
padding-left: 8px;
padding-right: 8px;
white-space: nowrap;
}
.layout {
display: grid;
grid-template-columns: 280px 1fr;
gap: 0;
min-height: calc(100vh - 72px);
}
.sidebar {
background: var(--panel);
border-right: 1px solid rgba(122, 29, 255, 0.25);
box-shadow: inset -10px 0 24px rgba(0, 0, 0, 0.35);
padding: 16px 12px;
overflow-y: auto;
}
.sidebar-title {
font-size: 10px;
text-transform: uppercase;
color: var(--muted);
margin-bottom: 10px;
}
.service {
margin: 8px 0;
border-radius: 14px;
border: 1px solid rgba(122, 29, 255, 0.25);
background: linear-gradient(125deg, rgba(122, 29, 255, 0.12), rgba(7, 4, 15, 0.9));
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.3);
padding: 12px;
}
.service .name {
color: var(--text);
font-size: 10px;
}
.service .meta {
color: var(--muted);
font-size: 9px;
margin-top: 4px;
line-height: 1.5;
}
.content {
background: var(--panel);
border-left: 1px solid rgba(122, 29, 255, 0.15);
padding: 18px 22px 26px;
box-shadow: inset 0 0 30px rgba(0, 0, 0, 0.45), 0 0 38px rgba(122, 29, 255, 0.18);
position: relative;
}
.packet-line {
font-size: 11px;
.content-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 14px;
}
.title {
font-size: 12px;
color: var(--text);
}
.mode-pill {
background: rgba(122, 29, 255, 0.12);
border: 1px solid rgba(122, 29, 255, 0.35);
color: var(--accent);
padding: 6px 10px;
border-radius: 10px;
font-size: 9px;
letter-spacing: 0.5px;
color: #c8f7ff;
padding: 4px 0;
border-bottom: 1px dashed rgba(255, 95, 210, 0.15);
pointer-events: none;
opacity: 0.85;
animation: flicker 1.5s infinite;
}
.packet-line:nth-child(2n) { color: #aee3ff; }
.packet-line:nth-child(3n) { color: #ffb3f1; }
.packet-line.ghosted { opacity: 0.3; }
@keyframes flicker {
0% { text-shadow: 0 0 6px rgba(89, 243, 255, 0.35); }
50% { text-shadow: 0 0 12px rgba(255, 95, 210, 0.3); }
100% { text-shadow: 0 0 6px rgba(89, 243, 255, 0.35); }
.packet-board {
background: rgba(9, 7, 18, 0.9);
border: 1px solid rgba(122, 29, 255, 0.35);
border-radius: 14px;
min-height: calc(100vh - 160px);
padding: 14px;
overflow: hidden;
}
.footer {
margin-top: 16px;
.packet-feed {
font-family: var(--mono);
font-size: 11px;
color: rgba(233, 247, 255, 0.6);
max-height: calc(100vh - 200px);
overflow-y: auto;
padding-right: 6px;
}
.mute {
opacity: 0.02;
.packet-line {
display: flex;
align-items: baseline;
gap: 10px;
padding: 6px 0;
border-bottom: 1px dashed rgba(122, 29, 255, 0.2);
color: var(--text);
}
.packet-line .pill {
display: inline-block;
padding: 2px 8px;
border-radius: 8px;
background: rgba(122, 29, 255, 0.2);
border: 1px solid rgba(122, 29, 255, 0.35);
font-size: 9px;
letter-spacing: 0.4px;
color: var(--accent);
}
.packet-line .meta {
color: var(--muted);
font-size: 10px;
margin-top: 6px;
}
.packet-line .bytes { color: #9ff8ff; }
.muted-bar {
color: rgba(230, 224, 255, 0.4);
font-size: 10px;
margin-top: 10px;
}
</style>
</head>
<body>
<div class="banner">0xb00b5 team Packmate // decoy panel</div>
<div class="matrix" id="service-grid"></div>
<div class="storm" id="packet-feed"></div>
<div class="footer">admin:admin only gets noise. Real API stays sealed.</div>
<div class="mute">You're stupid:)</div>
<div class="bg-lines"></div>
<div class="app-shell">
<nav class="navbar navbar-dark navbar-expand fixed-top">
<div class="d-flex align-items-center">
<span class="brand">
<span class="dot"></span>
0xb00b5 PM
</span>
</div>
<div class="metrics">
<span class="chip"><span class="label">SPM</span><span class="value" id="metric-spm">0</span></span>
<span class="chip"><span class="label">PPS</span><span class="value" id="metric-pps">0</span></span>
</div>
<div class="patterns-dropdown">
<button class="btn btn-dark btn-block" disabled>Patterns</button>
</div>
<span class="ml-auto text-monospace text-muted" style="font-size: 10px;">[Selected: none]</span>
</nav>
<div class="layout" style="margin-top: 64px;">
<aside class="sidebar">
<div class="sidebar-title">Services</div>
<div id="service-list"></div>
</aside>
<main class="content">
<div class="content-header">
<div class="title">Streams</div>
<div class="mode-pill">mode: fake</div>
</div>
<div class="packet-board">
<div class="packet-feed" id="packet-feed"></div>
<div class="muted-bar">Decoy feed only. Real capture stays sealed.</div>
</div>
</main>
</div>
</div>
<script>
const serviceGrid = document.getElementById('service-grid');
const packetFeed = document.getElementById('packet-feed');
let packetId = Math.floor(Math.random() * 100000) + 1;
const servicesEl = document.getElementById('service-list');
const feedEl = document.getElementById('packet-feed');
const spmEl = document.getElementById('metric-spm');
const ppsEl = document.getElementById('metric-pps');
let services = [];
let packetId = Math.floor(Math.random() * 5000) + 10;
fetch('/api/fake/services')
.then(r => r.json())
.then(data => {
services = data;
renderServices();
startStorm();
startFeed();
})
.catch(() => {
services = [{ name: 'ghost', port: 0, packetKind: 'tcp' }];
renderServices();
startStorm();
startFeed();
});
function renderServices() {
serviceGrid.innerHTML = '';
services.forEach(svc => {
const card = document.createElement('div');
card.className = 'card';
card.innerHTML = `
<h3>${svc.name} #${svc.port}</h3>
<div class="meta">packets: ${svc.packetKind || 'tcp'} stream</div>
<div class="meta">interface: locked</div>
servicesEl.innerHTML = '';
services.forEach((svc, idx) => {
const wrap = document.createElement('div');
wrap.className = 'service';
wrap.innerHTML = `
<div class="name">${svc.name} #${svc.port}</div>
<div class="meta">kind: ${(svc.packetKind || 'tcp').toUpperCase()}</div>
<div class="meta">streams per min: ${Math.floor(Math.random() * 80) + 4}</div>
`;
serviceGrid.appendChild(card);
servicesEl.appendChild(wrap);
});
}
function spawnPacket() {
if (!services.length) {
return;
}
if (!services.length) return;
const svc = services[Math.floor(Math.random() * services.length)];
const proto = (svc.packetKind || 'tcp').toUpperCase();
const ts = new Date();
const clock = ts.toTimeString().slice(0, 8);
const bytes = Math.floor(Math.random() * 1800) + 40;
const line = document.createElement('div');
line.className = 'packet-line';
const protocol = (svc.packetKind || 'tcp').toUpperCase();
line.textContent = `#${packetId} ${protocol} // :${svc.port} ${svc.name} // payload ${Math.floor(Math.random() * 1800)}b`;
line.innerHTML = `
<span class="pill">${proto}</span>
<span class="meta">${clock}</span>
<span class="meta">:${svc.port} ${svc.name}</span>
<span class="bytes">${bytes} bytes</span>
<span class="meta">id #${packetId}</span>
`;
packetId++;
packetFeed.prepend(line);
while (packetFeed.children.length > 140) {
packetFeed.removeChild(packetFeed.lastChild);
feedEl.prepend(line);
while (feedEl.children.length > 120) {
feedEl.removeChild(feedEl.lastChild);
}
setTimeout(() => line.classList.add('ghosted'), 1200);
updateMetrics();
}
function startStorm() {
setInterval(spawnPacket, 50);
function updateMetrics() {
const total = feedEl.children.length;
spmEl.textContent = Math.min(total, 999);
ppsEl.textContent = Math.floor(total / 2);
}
function startFeed() {
setInterval(spawnPacket, 55);
}
</script>
</body>
@@ -460,7 +649,7 @@ public class FakeAdminResponder {
"b00b5 is not a fresh meat:(",
"marcus, send your packmate credits pls",
"Marcus, fuck off",
"<a href='https://youtu.be/rrw-Pv3rc0E?si=-ZQmhZVxh4HF6luD'>Your special guide to get flag!</a>"
"Your special guide to get flag!"
);
}