aaa
🧩 Syntax:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CE Dashboard v2.0</title>
<style>
body {
background-color: #0d0d0d;
color: #33ff33;
font-family: 'Courier New', Courier, monospace;
display: flex;
flex-direction: column;
align-items: center;
margin: 0;
padding: 20px;
}
.glitch {
font-size: 2.5em;
animation: flicker 2s infinite alternate;
}
@keyframes flicker {
0% { opacity: 1; }
45% { opacity: 0.8; }
50% { opacity: 0.6; transform: translate(1px, -1px); }
52% { opacity: 0.9; transform: translate(-1px, 1px); }
55% { opacity: 1; transform: translate(0, 0); }
100% { opacity: 1; }
}
.dashboard-container {
width: 90%;
max-width: 1200px;
display: grid;
grid-template-columns: 1fr 2fr;
gap: 20px;
margin-top: 30px;
}
.panel {
border: 1px solid #33ff33;
background-color: #111;
padding: 15px;
box-shadow: 0 0 15px #33ff33;
display: flex;
flex-direction: column;
}
.panel h2 {
margin-top: 0;
font-size: 1.2em;
color: #33ff33;
}
.terminal-line {
margin: 5px 0;
}
.form-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
}
select,
input[type="text"] {
width: 100%;
padding: 5px;
background-color: #0d0d0d;
border: 1px solid #33ff33;
color: #33ff33;
font-family: 'Courier New', Courier, monospace;
}
.launch-button {
margin-top: 10px;
padding: 10px;
border: 1px solid #33ff33;
background: transparent;
color: #33ff33;
font-family: 'Courier New', Courier, monospace;
cursor: pointer;
}
.launch-button:hover {
background-color: #33ff33;
color: #0d0d0d;
}
.remove-ami {
margin-top: 5px;
font-size: 0.9em;
background: none;
border: none;
color: #ff3333;
cursor: pointer;
}
.remove-ami:hover {
text-decoration: underline;
}
.counter {
margin-top: 10px;
font-size: 1em;
color: #33ff33;
}
.machine-box {
border: 1px solid #33ff33;
padding: 10px;
margin-bottom: 10px;
background-color: #000;
}
</style>
<script>
function updateCounter() {
const customAmiCount = document.querySelectorAll('.custom-ami-entry').length;
const total = customAmiCount;
document.getElementById('total-counter').textContent = `Total Requested Machines: ${total}/14`;
const errorMsg = document.getElementById('error-message');
errorMsg.style.display = total > 14 ? 'block' : 'none';
}
function addCustomAmiField() {
const container = document.getElementById('custom-ami-container');
const entry = document.createElement('div');
entry.className = 'custom-ami-entry form-group';
entry.innerHTML = `
<label>AMI:</label>
<input list="ami-options" name="custom_ami[]" style="width: 100%; padding: 5px; background-color: #0d0d0d; border: 1px solid #33ff33; color: #33ff33; font-family: 'Courier New', Courier, monospace; appearance: menulist-button; -webkit-appearance: menulist-button;">
<datalist id="ami-options">
<option value="ami-kali">Kali Linux</option>
<option value="ami-windows-2022">Windows Server 2022</option>
<option value="ami-amazon-linux">Amazon Linux</option>
</datalist>
<label>Instance Type:</label>
<select name="custom_instance_type[]">
<option value="t2.micro">t2.micro</option>
<option value="t2.small">t2.small</option>
<option value="t3.medium">t3.medium</option>
<option value="t3.large">t3.large</option>
<option value="m5.large">m5.large</option>
</select>
<button type="button" class="remove-ami" onclick="removeCustomAmiField(this)">Remove</button>`;
container.appendChild(entry);
updateCounter();
}
function removeCustomAmiField(button) {
const entry = button.closest('.custom-ami-entry');
entry.remove();
updateCounter();
}
function submitLab(event) {
event.preventDefault();
const labName = document.getElementById('lab-name').value.trim();
const labNameRegex = /^[a-zA-Z0-9_-]+$/;
if (!labNameRegex.test(labName)) {
document.getElementById('labname-error').style.display = 'block';
return;
} else {
document.getElementById('labname-error').style.display = 'none';
}
const customAmis = Array.from(document.querySelectorAll('.custom-ami-entry')).map(entry => {
const ami = entry.querySelector('input[name="custom_ami[]"]').value;
const type = entry.querySelector('select[name="custom_instance_type[]"]').value;
return { ami, instance_type: type };
});
const payload = { lab_name: labName, custom_amis: customAmis };
fetch('/launchlab', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
})
.then(res => res.json())
.then(data => {
document.getElementById('debug-box').innerText = 'Launch Response:\n' + JSON.stringify(data, null, 2);
})
.catch(error => {
document.getElementById('debug-box').innerText = 'Launch Failed';
console.error('Error launching lab:', error);
});
}
function validateLab(event) {
event.preventDefault();
const labName = document.getElementById('lab-name').value.trim();
const labNameRegex = /^[a-zA-Z0-9_-]+$/;
if (!labNameRegex.test(labName)) {
document.getElementById('labname-error').style.display = 'block';
return;
} else {
document.getElementById('labname-error').style.display = 'none';
}
const customAmis = Array.from(document.querySelectorAll('.custom-ami-entry')).map(entry => {
const ami = entry.querySelector('input[name="custom_ami[]"]').value;
const type = entry.querySelector('select[name="custom_instance_type[]"]').value;
return { ami, instance_type: type };
});
const payload = { lab_name: labName, custom_amis: customAmis };
fetch('/validatelab', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
})
.then(res => res.json())
.then(data => {
if (data.validated === true) {
const launchBtn = document.getElementById('launch-btn');
launchBtn.disabled = false;
launchBtn.style.border = '1px solid #33ff33';
launchBtn.style.color = '#33ff33';
document.getElementById('debug-box').innerText = `Validation Successful:
${JSON.stringify(data, null, 2)}`;
} else {
document.getElementById('debug-box').innerText = 'Validation Failed:\n' + JSON.stringify(data, null, 2);
}
})
.catch(error => {
console.error('Error validating lab:', error);
document.getElementById('debug-box').innerText = 'Validation Failed';
});
}
function confirmDestroyLab() {
const messageBox = document.getElementById('destroy-lab-message');
if (messageBox.style.display === 'none') {
messageBox.style.display = 'block';
return;
}
const labName = document.getElementById('lab-name').value.trim();
if (!labName) {
alert('Lab name is required to destroy the lab.');
return;
}
fetch('/destroylab', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ lab_name: labName })
})
.then(res => res.json())
.then(data => {
messageBox.textContent = 'Lab destroyed.';
document.getElementById('lab-name-display').textContent = '-';
document.getElementById('hosts-active').textContent = '-';
document.getElementById('lab-uptime').textContent = '-';
document.getElementById('lab-subnet').textContent = '-';
document.getElementById('machines-list').innerHTML = '<div class="terminal-line">No machines launched yet.</div>';
setTimeout(() => { messageBox.style.display = 'none'; }, 3000);
})
.catch(err => {
messageBox.textContent = 'Failed to destroy lab.';
});
}
document.addEventListener('DOMContentLoaded', () => {
document.getElementById('add-ami-btn').addEventListener('click', (e) => {
e.preventDefault();
addCustomAmiField();
});
updateCounter();
});
</script>
</head>
<body>
<div class="glitch">ICE Dashboard</div>
<div class="panel" style="margin-top: 10px; margin-bottom: 20px; width: 90%; max-width: 1200px; text-align: center;">
<h2>> SSH KEY DOWNLOAD</h2>
<a href="/download/keys.zip" download class="launch-button" style="display: inline-block; text-decoration: none;">Download SSH Keys (.zip)</a>
</div>
<div class="dashboard-container">
<div class="panel" style="justify-content: space-between;">
<h2>> LAUNCH LAB</h2>
<form id="launch-form" style="display: flex; flex-direction: column; height: 100%; justify-content: space-between;">
<div>
<div class="form-group">
<label for="lab-name">Lab Name (no spaces or special characters):</label>
<input type="text" id="lab-name" name="lab_name" pattern="^[a-zA-Z0-9_-]+$" title="Only letters, numbers, hyphens, and underscores allowed" required>
<div id="labname-error" style="color: #ff3333; display: none; font-family: 'Courier New', Courier, monospace; margin-top: 5px;">Error: Lab name may only contain letters, numbers, hyphens, and underscores.</div>
</div>
<div class="form-group">
<div id="custom-ami-container"></div>
<button id="add-ami-btn" type="button" class="launch-button">+ Add Instance</button>
</div>
<div id="total-counter" class="counter">Total Requested Machines: 0/14</div>
<div id="error-message" style="color: #ff3333; display: none; font-family: 'Courier New', Courier, monospace; margin-top: 5px;">Error: You cannot request more than 14 machines.</div>
</div>
<div style="display: flex; gap: 10px;">
<button type="button" class="launch-button" onclick="validateLab(event)">Validate Lab</button>
<button type="submit" class="launch-button" id="launch-btn" onclick="submitLab(event)" disabled style="border: 1px solid red; color: red;">Launch</button>
</div>
</form>
</div>
<div>
<div class="panel">
<h2>> CURRENT LAB</h2>
<div class="terminal-line">> Lab Name: <span id="lab-name-display" style="color:lime">-</span></div>
<div class="terminal-line">> Hosts Active: <span id="hosts-active" style="color:lime">-</span></div>
<div class="terminal-line">> Uptime: <span id="lab-uptime" style="color:lime">-</span></div>
<div class="terminal-line">> Subnet: <span id="lab-subnet" style="color:lime">-</span></div>
<div style="text-align:center; margin-top:10px;">
<button class="launch-button" onclick="confirmDestroyLab()">Destroy Lab</button>
<div id="destroy-lab-message" style="display:none; margin-top:5px; font-size:0.9em; color:#ff3333;">Click again to confirm lab destruction.</div>
</div>
</div>
<div class="panel">
<h2>> MACHINES</h2>
<div id="machines-list">
<div class="terminal-line">No machines launched yet.</div>
</div>
</div>
<div class="panel">
<h2>> DEBUG</h2>
<div id="debug-box" style="font-family: 'Courier New', Courier, monospace; color: #33ff33; background-color: #000; padding: 10px; border: 1px solid #33ff33; height: 300px; overflow-y: auto; scroll-behavior: smooth;">
No messages.
</div>
</div>
</div>
</div>
</body>
</html>