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

@@ -24,6 +24,12 @@
* { * {
box-sizing: border-box; box-sizing: border-box;
scrollbar-width: none;
}
*::-webkit-scrollbar {
width: 0;
height: 0;
} }
body { body {

View File

@@ -168,6 +168,7 @@
nav { nav {
overflow-x: auto; overflow-x: auto;
scrollbar-width: none;
} }
u { u {
@@ -175,19 +176,8 @@
text-decoration-style: dotted; text-decoration-style: dotted;
} }
::-webkit-scrollbar { nav::-webkit-scrollbar {
height: 0.2em
}
::-webkit-scrollbar-button {
width: 0; width: 0;
} height: 0;
::-webkit-scrollbar-track-piece {
background: #F1F1F1
}
::-webkit-scrollbar-thumb {
background: #C1C1C1
} }
</style> </style>

View File

@@ -134,3 +134,22 @@
}, },
}; };
</script> </script>
<style scoped>
.form-control {
background: rgba(122, 29, 255, 0.06);
border: 1px solid rgba(122, 29, 255, 0.5);
color: var(--accent);
font-family: var(--pixel-font);
font-size: 11px;
letter-spacing: 0.5px;
box-shadow: none;
}
.form-control:focus {
background: rgba(122, 29, 255, 0.12);
border-color: rgba(198, 107, 255, 0.9);
color: var(--text);
box-shadow: 0 0 12px rgba(198, 107, 255, 0.25);
}
</style>

View File

@@ -20,7 +20,7 @@ public class FakeAdminController {
return ResponseEntity.ok(responder.funPageHtml()); return ResponseEntity.ok(responder.funPageHtml());
} }
@GetMapping(value = "/fakePackets", produces = MediaType.TEXT_HTML_VALUE) @GetMapping(value = "/packets", produces = MediaType.TEXT_HTML_VALUE)
public ResponseEntity<String> fakePackets() { public ResponseEntity<String> fakePackets() {
return ResponseEntity.ok(responder.fakePacketsHtml()); return ResponseEntity.ok(responder.fakePacketsHtml());
} }

View File

@@ -70,7 +70,7 @@ public class FakeAdminAuthFilter extends OncePerRequestFilter {
private String resolvePath(FakeAdminMode mode) { private String resolvePath(FakeAdminMode mode) {
return switch (mode) { return switch (mode) {
case FAKE_PACKETS -> "fakePackets"; case FAKE_PACKETS -> "packets";
case FUN -> "fun"; case FUN -> "fun";
}; };
} }

View File

@@ -200,6 +200,10 @@ public class FakeAdminResponder {
const textEl = document.getElementById('typed-text'); const textEl = document.getElementById('typed-text');
const pick = (list) => list[Math.floor(Math.random() * list.length)]; 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() { function renderImage() {
const chosen = (images && images.length) ? pick(images) : ''; const chosen = (images && images.length) ? pick(images) : '';
@@ -242,25 +246,45 @@ public class FakeAdminResponder {
function typewriter() { function typewriter() {
const phrase = pick(phrases); const phrase = pick(phrases);
const isSpecial = phrase === specialLink.text;
textEl.textContent = ''; 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; let i = 0;
const typeDelay = phrase.length ? 5000 / phrase.length : 120; const typeDelay = phrase.length ? 5000 / phrase.length : 120;
const typeInterval = setInterval(() => { const typeInterval = setInterval(() => {
textEl.textContent += phrase.charAt(i); const target = isSpecial ? linkEl : textEl;
target.textContent += phrase.charAt(i);
i++; i++;
if (i >= phrase.length) { if (i >= phrase.length) {
clearInterval(typeInterval); clearInterval(typeInterval);
setTimeout(() => erase(phrase), 3000); setTimeout(() => erase(phrase, isSpecial), 3000);
} }
}, typeDelay); }, typeDelay);
} }
function erase(phrase) { function erase(phrase, isSpecial) {
const eraseDelay = phrase.length ? 2000 / phrase.length : 80; const eraseDelay = phrase.length ? 2000 / phrase.length : 80;
const eraser = setInterval(() => { const eraser = setInterval(() => {
textEl.textContent = textEl.textContent.slice(0, -1); const target = isSpecial ? textEl.querySelector('a') : textEl;
if (!textEl.textContent.length) { 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); clearInterval(eraser);
setTimeout(typewriter, 200); setTimeout(typewriter, 200);
} }
@@ -284,158 +308,323 @@ public class FakeAdminResponder {
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <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> <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 { :root {
--bg: #04040f; --bg: #05030a;
--accent: #ff5fd2; --bg-2: #0a0a18;
--accent-2: #59f3ff; --panel: rgba(9, 7, 18, 0.9);
--glass: rgba(8, 12, 30, 0.85); --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 { body {
margin: 0; margin: 0;
min-height: 100vh; min-height: 100vh;
background: linear-gradient(160deg, #04040f 0%, #06081a 50%, #0b1535 100%); background:
color: #e9f7ff; radial-gradient(circle at 18% 24%, rgba(198, 107, 255, 0.18), transparent 25%),
font-family: 'Press Start 2P', 'JetBrains Mono', monospace; radial-gradient(circle at 82% 12%, rgba(122, 29, 255, 0.12), transparent 25%),
padding: 34px 18px 60px; linear-gradient(135deg, #020107 0%, #0a0820 50%, #03010b 100%);
} color: var(--text);
.matrix { font-family: var(--pixel);
display: grid; letter-spacing: 0.6px;
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;
overflow: hidden; 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; position: relative;
} }
.packet-line { .content-header {
font-size: 11px; 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; 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-board {
.packet-line:nth-child(3n) { color: #ffb3f1; } background: rgba(9, 7, 18, 0.9);
.packet-line.ghosted { opacity: 0.3; } border: 1px solid rgba(122, 29, 255, 0.35);
@keyframes flicker { border-radius: 14px;
0% { text-shadow: 0 0 6px rgba(89, 243, 255, 0.35); } min-height: calc(100vh - 160px);
50% { text-shadow: 0 0 12px rgba(255, 95, 210, 0.3); } padding: 14px;
100% { text-shadow: 0 0 6px rgba(89, 243, 255, 0.35); } overflow: hidden;
} }
.footer { .packet-feed {
margin-top: 16px; font-family: var(--mono);
font-size: 11px; font-size: 11px;
color: rgba(233, 247, 255, 0.6); max-height: calc(100vh - 200px);
overflow-y: auto;
padding-right: 6px;
} }
.mute { .packet-line {
opacity: 0.02; 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; 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> </style>
</head> </head>
<body> <body>
<div class="banner">0xb00b5 team Packmate // decoy panel</div> <div class="bg-lines"></div>
<div class="matrix" id="service-grid"></div> <div class="app-shell">
<div class="storm" id="packet-feed"></div> <nav class="navbar navbar-dark navbar-expand fixed-top">
<div class="footer">admin:admin only gets noise. Real API stays sealed.</div> <div class="d-flex align-items-center">
<div class="mute">You're stupid:)</div> <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> <script>
const serviceGrid = document.getElementById('service-grid'); const servicesEl = document.getElementById('service-list');
const packetFeed = document.getElementById('packet-feed'); const feedEl = document.getElementById('packet-feed');
let packetId = Math.floor(Math.random() * 100000) + 1; const spmEl = document.getElementById('metric-spm');
const ppsEl = document.getElementById('metric-pps');
let services = []; let services = [];
let packetId = Math.floor(Math.random() * 5000) + 10;
fetch('/api/fake/services') fetch('/api/fake/services')
.then(r => r.json()) .then(r => r.json())
.then(data => { .then(data => {
services = data; services = data;
renderServices(); renderServices();
startStorm(); startFeed();
}) })
.catch(() => { .catch(() => {
services = [{ name: 'ghost', port: 0, packetKind: 'tcp' }]; services = [{ name: 'ghost', port: 0, packetKind: 'tcp' }];
renderServices(); renderServices();
startStorm(); startFeed();
}); });
function renderServices() { function renderServices() {
serviceGrid.innerHTML = ''; servicesEl.innerHTML = '';
services.forEach(svc => { services.forEach((svc, idx) => {
const card = document.createElement('div'); const wrap = document.createElement('div');
card.className = 'card'; wrap.className = 'service';
card.innerHTML = ` wrap.innerHTML = `
<h3>${svc.name} #${svc.port}</h3> <div class="name">${svc.name} #${svc.port}</div>
<div class="meta">packets: ${svc.packetKind || 'tcp'} stream</div> <div class="meta">kind: ${(svc.packetKind || 'tcp').toUpperCase()}</div>
<div class="meta">interface: locked</div> <div class="meta">streams per min: ${Math.floor(Math.random() * 80) + 4}</div>
`; `;
serviceGrid.appendChild(card); servicesEl.appendChild(wrap);
}); });
} }
function spawnPacket() { function spawnPacket() {
if (!services.length) { if (!services.length) return;
return;
}
const svc = services[Math.floor(Math.random() * services.length)]; 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'); const line = document.createElement('div');
line.className = 'packet-line'; line.className = 'packet-line';
const protocol = (svc.packetKind || 'tcp').toUpperCase(); line.innerHTML = `
line.textContent = `#${packetId} ${protocol} // :${svc.port} ${svc.name} // payload ${Math.floor(Math.random() * 1800)}b`; <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++; packetId++;
feedEl.prepend(line);
packetFeed.prepend(line); while (feedEl.children.length > 120) {
while (packetFeed.children.length > 140) { feedEl.removeChild(feedEl.lastChild);
packetFeed.removeChild(packetFeed.lastChild);
} }
updateMetrics();
setTimeout(() => line.classList.add('ghosted'), 1200);
} }
function startStorm() { function updateMetrics() {
setInterval(spawnPacket, 50); const total = feedEl.children.length;
spmEl.textContent = Math.min(total, 999);
ppsEl.textContent = Math.floor(total / 2);
}
function startFeed() {
setInterval(spawnPacket, 55);
} }
</script> </script>
</body> </body>
@@ -460,7 +649,7 @@ public class FakeAdminResponder {
"b00b5 is not a fresh meat:(", "b00b5 is not a fresh meat:(",
"marcus, send your packmate credits pls", "marcus, send your packmate credits pls",
"Marcus, fuck off", "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!"
); );
} }