- Rename repo/domain: attack-defense-platform / attackdefense.imrnes.team (all refs replaced)
- challenge_registry.json: single source of truth (28 challs across gemastik18/xvi/xvii)
- teams.py: registry-driven CHALLENGES, set_challenge_enabled, sync_challenge_runtime
(apply enable/disable to live teams: build/up or stop/remove + receiver restart)
- compose_gen.py: render per-team compose from canonical per-challenge templates
(image reuse, per-team ports 30xxx, flag mounts, passwords)
- gen_canonical_composes.py: canonical docker-compose.yml for all services
- import_new_challenges.py: import XVI/XVII services + EOL base image fixes
(debian:buster→bookworm, node:14→20, python:3.7-slim→3.11)
- receiver: xvi package (10 checkers) + xvii package (12 generic checkers),
Challenge base reads PASSWORD_<team_port> from env; gen_receiver_main.py
generates per-team main.py from registry
- main.py: /api/challenges returns full registry; PATCH /api/challenges/<name>
toggles enabled + applies to live teams
- index.html: 🏗️ Challenge Manager tab (toggle per challenge, grouped by set)
- SLA bonus now dynamic (all enabled challenges, not hardcoded 6)
64 lines
2.4 KiB
HTML
64 lines
2.4 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="id">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Attack Defense Platform — Login</title>
|
|
<style>
|
|
* { margin:0; padding:0; box-sizing:border-box; }
|
|
body {
|
|
font-family: 'JetBrains Mono','Fira Code',monospace;
|
|
background: radial-gradient(ellipse at top, #0d1b2a 0%, #0a0f1c 60%, #05070d 100%);
|
|
color: #c9d4e3; height:100vh; display:flex; align-items:center; justify-content:center;
|
|
}
|
|
.card {
|
|
background:#0e1526cc; border:1px solid #1e3a5f; border-radius:14px;
|
|
padding:42px 46px; width:360px; box-shadow:0 0 60px #0a3d6b55;
|
|
}
|
|
h1 { font-size:20px; color:#5ad1ff; letter-spacing:1px; margin-bottom:6px; }
|
|
.sub { color:#718096; font-size:12px; margin-bottom:28px; }
|
|
label { display:block; font-size:11px; color:#7d8ba1; margin:14px 0 6px; text-transform:uppercase; letter-spacing:1px; }
|
|
input {
|
|
width:100%; background:#0a101f; border:1px solid #1e3a5f; color:#dbe6f4;
|
|
border-radius:8px; padding:11px 13px; font-size:14px; font-family:inherit; outline:none;
|
|
}
|
|
input:focus { border-color:#3b82f6; box-shadow:0 0 0 3px #3b82f633; }
|
|
button {
|
|
width:100%; margin-top:24px; background:linear-gradient(135deg,#0ea5e9,#2563eb);
|
|
border:none; color:#fff; font-family:inherit; font-weight:700; font-size:14px;
|
|
padding:12px; border-radius:8px; cursor:pointer; letter-spacing:.5px; transition:filter .2s;
|
|
}
|
|
button:hover { filter:brightness(1.15); }
|
|
.err { color:#f87171; font-size:12px; margin-top:14px; min-height:16px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="card">
|
|
<h1>⚔️ ATTACK DEFENSE</h1>
|
|
<div class="sub">Node Control Panel — imrnes</div>
|
|
<form id="f">
|
|
<label>Username</label>
|
|
<input id="u" autocomplete="username" required>
|
|
<label>Password</label>
|
|
<input id="p" type="password" autocomplete="current-password" required>
|
|
<button type="submit">MASUK</button>
|
|
<div class="err" id="err"></div>
|
|
</form>
|
|
</div>
|
|
<script>
|
|
const f = document.getElementById('f');
|
|
f.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
const err = document.getElementById('err');
|
|
err.textContent = '';
|
|
const r = await fetch('/api/login', {
|
|
method: 'POST',
|
|
headers: {'Content-Type':'application/json'},
|
|
body: JSON.stringify({user: u.value, pass: p.value})
|
|
});
|
|
if (r.ok) location.href = '/';
|
|
else err.textContent = 'Kredensial salah!';
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |