null-v-0 / index.html
Dapshen's picture
Add 3 files
3a2e0ad verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tech Null Messenger</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.gradient-bg {
background: linear-gradient(135deg, #1e3a8a 0%, #0ea5e9 100%);
}
.chat-container {
height: calc(100vh - 200px);
}
.message-animation {
animation: fadeIn 0.3s ease-in-out;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.blink {
animation: blink 1s infinite;
}
@keyframes blink {
0% { opacity: 1; }
50% { opacity: 0.5; }
100% { opacity: 1; }
}
</style>
</head>
<body class="bg-gray-100 font-sans">
<div id="app" class="min-h-screen flex flex-col">
<!-- Header -->
<header class="gradient-bg text-white p-4 shadow-lg">
<div class="container mx-auto flex justify-between items-center">
<h1 class="text-2xl font-bold flex items-center">
<i class="fas fa-robot mr-2"></i> Tech Null
</h1>
<div id="auth-status" class="flex items-center space-x-4">
<span id="user-info" class="hidden">
<span id="username-display" class="font-semibold"></span>
<button id="logout-btn" class="ml-2 bg-red-500 hover:bg-red-600 text-white px-3 py-1 rounded text-sm">
<i class="fas fa-sign-out-alt mr-1"></i> Logout
</button>
</span>
</div>
</div>
</header>
<!-- Main Content -->
<main class="flex-grow container mx-auto p-4">
<!-- Auth Screens -->
<div id="auth-screens" class="max-w-md mx-auto">
<!-- Login Screen -->
<div id="login-screen" class="bg-white rounded-lg shadow-md p-6 mb-4">
<h2 class="text-xl font-bold mb-4 text-gray-800">Login</h2>
<div class="mb-4">
<label for="login-id" class="block text-gray-700 mb-2">ID</label>
<input type="number" id="login-id" class="w-full px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
<div class="mb-4">
<label for="login-password" class="block text-gray-700 mb-2">Password</label>
<input type="password" id="login-password" class="w-full px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
<button id="login-btn" class="w-full bg-blue-500 hover:bg-blue-600 text-white py-2 px-4 rounded font-medium">
<i class="fas fa-sign-in-alt mr-2"></i> Login
</button>
<p class="text-center mt-4 text-gray-600">Don't have an account? <button id="show-register-btn" class="text-blue-500 hover:text-blue-700 font-medium">Register</button></p>
</div>
<!-- Register Screen -->
<div id="register-screen" class="bg-white rounded-lg shadow-md p-6 hidden">
<h2 class="text-xl font-bold mb-4 text-gray-800">Register</h2>
<div class="mb-4">
<label for="register-username" class="block text-gray-700 mb-2">Username (max 20 chars)</label>
<input type="text" id="register-username" maxlength="20" class="w-full px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
<div class="mb-4">
<label for="register-password" class="block text-gray-700 mb-2">Password (max 20 chars)</label>
<input type="password" id="register-password" maxlength="20" class="w-full px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
<button id="register-btn" class="w-full bg-green-500 hover:bg-green-600 text-white py-2 px-4 rounded font-medium">
<i class="fas fa-user-plus mr-2"></i> Register
</button>
<p class="text-center mt-4 text-gray-600">Already have an account? <button id="show-login-btn" class="text-blue-500 hover:text-blue-700 font-medium">Login</button></p>
</div>
</div>
<!-- Chat Screen -->
<div id="chat-screen" class="hidden">
<div class="flex flex-col lg:flex-row gap-4">
<!-- Chat Area -->
<div class="flex-grow">
<div class="bg-white rounded-lg shadow-md overflow-hidden">
<div class="p-4 border-b border-gray-200 bg-gray-50">
<h2 class="text-xl font-bold text-gray-800">Global Chat</h2>
<div id="message-stats" class="text-sm text-gray-600 mt-1">
Messages: <span id="message-count">0</span> • Users: <span id="user-count">1</span>
</div>
</div>
<div id="chat-messages" class="chat-container overflow-y-auto p-4 space-y-4">
<!-- Messages will appear here -->
</div>
<div class="p-4 border-t border-gray-200 bg-gray-50">
<div class="flex items-center">
<input type="text" id="message-input" maxlength="1000" placeholder="Type your message..." class="flex-grow px-3 py-2 border border-gray-300 rounded-l focus:outline-none focus:ring-2 focus:ring-blue-500">
<button id="send-btn" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-r">
<i class="fas fa-paper-plane"></i>
</button>
</div>
<div id="message-counter" class="text-sm text-gray-600 mt-2">
Messages this hour: <span id="messages-sent">0</span>/<span id="message-limit">10</span>
</div>
</div>
</div>
</div>
<!-- User Panel -->
<div class="w-full lg:w-64">
<div class="bg-white rounded-lg shadow-md overflow-hidden">
<div class="p-4 border-b border-gray-200 bg-gray-50">
<h2 class="text-xl font-bold text-gray-800">User Panel</h2>
</div>
<div class="p-4 space-y-4">
<div>
<h3 class="font-semibold text-gray-700 mb-2">Account Info</h3>
<div class="text-sm text-gray-600 space-y-1">
<p>ID: <span id="user-id-display" class="font-medium"></span></p>
<p>Username: <span id="user-name-display" class="font-medium"></span></p>
<p>Registered: <span id="user-registered" class="font-medium"></span></p>
</div>
</div>
<div>
<h3 class="font-semibold text-gray-700 mb-2">Settings</h3>
<div class="space-y-2">
<button id="change-username-btn" class="w-full text-left bg-gray-100 hover:bg-gray-200 text-gray-800 px-3 py-2 rounded text-sm">
<i class="fas fa-user-edit mr-1"></i> Change Username
</button>
<button id="change-password-btn" class="w-full text-left bg-gray-100 hover:bg-gray-200 text-gray-800 px-3 py-2 rounded text-sm">
<i class="fas fa-key mr-1"></i> Change Password
</button>
</div>
</div>
<div id="admin-panel" class="hidden">
<h3 class="font-semibold text-gray-700 mb-2">Admin Panel</h3>
<div class="space-y-2">
<div class="flex items-center">
<input type="text" id="admin-command" placeholder="Enter command..." class="flex-grow px-2 py-1 text-sm border border-gray-300 rounded-l focus:outline-none focus:ring-1 focus:ring-blue-500">
<button id="execute-command-btn" class="bg-blue-500 hover:bg-blue-600 text-white px-2 py-1 rounded-r text-sm">
<i class="fas fa-terminal"></i>
</button>
</div>
<button id="help-btn" class="w-full text-left bg-gray-100 hover:bg-gray-200 text-gray-800 px-3 py-2 rounded text-sm">
<i class="fas fa-question-circle mr-1"></i> Show Help
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
<!-- Modals -->
<!-- Change Username Modal -->
<div id="username-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50">
<div class="bg-white rounded-lg shadow-xl p-6 w-full max-w-md">
<h3 class="text-lg font-bold mb-4">Change Username</h3>
<div class="mb-4">
<label for="new-username" class="block text-gray-700 mb-2">New Username (max 20 chars)</label>
<input type="text" id="new-username" maxlength="20" class="w-full px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
<div class="flex justify-end space-x-3">
<button id="cancel-username-btn" class="px-4 py-2 border border-gray-300 rounded text-gray-700 hover:bg-gray-100">Cancel</button>
<button id="save-username-btn" class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">Save</button>
</div>
</div>
</div>
<!-- Change Password Modal -->
<div id="password-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50">
<div class="bg-white rounded-lg shadow-xl p-6 w-full max-w-md">
<h3 class="text-lg font-bold mb-4">Change Password</h3>
<div class="mb-4">
<label for="current-password" class="block text-gray-700 mb-2">Current Password</label>
<input type="password" id="current-password" class="w-full px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
<div class="mb-4">
<label for="new-password" class="block text-gray-700 mb-2">New Password (max 20 chars)</label>
<input type="password" id="new-password" maxlength="20" class="w-full px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
<div class="flex justify-end space-x-3">
<button id="cancel-password-btn" class="px-4 py-2 border border-gray-300 rounded text-gray-700 hover:bg-gray-100">Cancel</button>
<button id="save-password-btn" class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">Save</button>
</div>
</div>
</div>
<!-- Admin Help Modal -->
<div id="help-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50">
<div class="bg-white rounded-lg shadow-xl p-6 w-full max-w-2xl max-h-[80vh] overflow-y-auto">
<h3 class="text-lg font-bold mb-4">Admin Commands Help</h3>
<div class="space-y-3 text-sm">
<div class="p-3 bg-gray-50 rounded">
<p class="font-semibold">/mute id x</p>
<p class="text-gray-600">Mute account by ID for x hours</p>
</div>
<div class="p-3 bg-gray-50 rounded">
<p class="font-semibold">/unmute id</p>
<p class="text-gray-600">Unmute account by ID</p>
</div>
<div class="p-3 bg-gray-50 rounded">
<p class="font-semibold">/del_m mid</p>
<p class="text-gray-600">Delete message by message ID</p>
</div>
<div class="p-3 bg-gray-50 rounded">
<p class="font-semibold">/del_um id</p>
<p class="text-gray-600">Delete all messages by user ID</p>
</div>
<div class="p-3 bg-gray-50 rounded">
<p class="font-semibold">/limit_m x</p>
<p class="text-gray-600">Set message limit per hour to x</p>
</div>
<div class="p-3 bg-gray-50 rounded">
<p class="font-semibold">/limit_reset</p>
<p class="text-gray-600">Reset message counters for all users</p>
</div>
<div class="p-3 bg-gray-50 rounded">
<p class="font-semibold">/vipe_chat</p>
<p class="text-gray-600">Delete all messages from chat</p>
</div>
<div class="p-3 bg-gray-50 rounded">
<p class="font-semibold">/vipe_all</p>
<p class="text-gray-600">Delete all messages and accounts (except ID 0)</p>
</div>
<div class="p-3 bg-gray-50 rounded">
<p class="font-semibold">/change_n id x</p>
<p class="text-gray-600">Change username of user ID to x</p>
</div>
<div class="p-3 bg-gray-50 rounded">
<p class="font-semibold">/change_p id x</p>
<p class="text-gray-600">Change password of user ID to x</p>
</div>
<div class="p-3 bg-gray-50 rounded">
<p class="font-semibold">/check_ip mid</p>
<p class="text-gray-600">Check IP of message by message ID</p>
</div>
<div class="p-3 bg-gray-50 rounded">
<p class="font-semibold">/mute_ip ip x</p>
<p class="text-gray-600">Mute IP address for x hours</p>
</div>
<div class="p-3 bg-gray-50 rounded">
<p class="font-semibold">/unmute_ip ip</p>
<p class="text-gray-600">Unmute IP address</p>
</div>
<div class="p-3 bg-gray-50 rounded">
<p class="font-semibold">/list</p>
<p class="text-gray-600">List all muted IPs/accounts</p>
</div>
<div class="p-3 bg-gray-50 rounded">
<p class="font-semibold">/help</p>
<p class="text-gray-600">Show this help</p>
</div>
</div>
<div class="mt-4 flex justify-end">
<button id="close-help-btn" class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">Close</button>
</div>
</div>
</div>
<!-- Registration Success Modal -->
<div id="register-success-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50">
<div class="bg-white rounded-lg shadow-xl p-6 w-full max-w-md">
<h3 class="text-lg font-bold mb-4 text-green-600">Registration Successful!</h3>
<div class="mb-4">
<p class="text-gray-700">Your account has been created.</p>
<div class="mt-3 p-3 bg-gray-50 rounded">
<p class="font-semibold">ID: <span id="registered-id" class="font-normal"></span></p>
<p class="font-semibold">Username: <span id="registered-username" class="font-normal"></span></p>
</div>
<p class="mt-3 text-sm text-gray-600">Please remember your ID as you'll need it to login.</p>
</div>
<div class="flex justify-end">
<button id="ok-register-btn" class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">OK</button>
</div>
</div>
</div>
</div>
<script>
// Data storage
const data = {
users: [
{
id: 0,
username: "Null",
password: "QWERTYnull123!",
registered: new Date().toISOString(),
ip: "127.0.0.1",
deviceId: "admin-device"
}
],
messages: [],
mutedUsers: {},
mutedIPs: {},
messageCounters: {},
deviceRegistrations: {},
messageLimit: 10,
nextMessageId: 1
};
// Simulate localStorage for demo purposes
function saveData() {
localStorage.setItem('techNullData', JSON.stringify(data));
}
function loadData() {
const savedData = localStorage.getItem('techNullData');
if (savedData) {
Object.assign(data, JSON.parse(savedData));
}
}
// Initialize
loadData();
// Current user state
let currentUser = null;
let currentIP = "127.0.0.1"; // In a real app, this would come from the server
let currentDeviceId = "demo-device"; // In a real app, generate a unique device ID
// DOM Elements
const loginScreen = document.getElementById('login-screen');
const registerScreen = document.getElementById('register-screen');
const chatScreen = document.getElementById('chat-screen');
const loginIdInput = document.getElementById('login-id');
const loginPasswordInput = document.getElementById('login-password');
const registerUsernameInput = document.getElementById('register-username');
const registerPasswordInput = document.getElementById('register-password');
const messageInput = document.getElementById('message-input');
const chatMessages = document.getElementById('chat-messages');
const userInfo = document.getElementById('user-info');
const usernameDisplay = document.getElementById('username-display');
const logoutBtn = document.getElementById('logout-btn');
const showRegisterBtn = document.getElementById('show-register-btn');
const showLoginBtn = document.getElementById('show-login-btn');
const loginBtn = document.getElementById('login-btn');
const registerBtn = document.getElementById('register-btn');
const sendBtn = document.getElementById('send-btn');
const userIdDisplay = document.getElementById('user-id-display');
const userNameDisplay = document.getElementById('user-name-display');
const userRegistered = document.getElementById('user-registered');
const adminPanel = document.getElementById('admin-panel');
const adminCommand = document.getElementById('admin-command');
const executeCommandBtn = document.getElementById('execute-command-btn');
const changeUsernameBtn = document.getElementById('change-username-btn');
const changePasswordBtn = document.getElementById('change-password-btn');
const usernameModal = document.getElementById('username-modal');
const newUsernameInput = document.getElementById('new-username');
const saveUsernameBtn = document.getElementById('save-username-btn');
const cancelUsernameBtn = document.getElementById('cancel-username-btn');
const passwordModal = document.getElementById('password-modal');
const currentPasswordInput = document.getElementById('current-password');
const newPasswordInput = document.getElementById('new-password');
const savePasswordBtn = document.getElementById('save-password-btn');
const cancelPasswordBtn = document.getElementById('cancel-password-btn');
const helpModal = document.getElementById('help-modal');
const helpBtn = document.getElementById('help-btn');
const closeHelpBtn = document.getElementById('close-help-btn');
const registerSuccessModal = document.getElementById('register-success-modal');
const registeredId = document.getElementById('registered-id');
const registeredUsername = document.getElementById('registered-username');
const okRegisterBtn = document.getElementById('ok-register-btn');
const messageCount = document.getElementById('message-count');
const userCount = document.getElementById('user-count');
const messagesSent = document.getElementById('messages-sent');
const messageLimit = document.getElementById('message-limit');
// Event Listeners
showRegisterBtn.addEventListener('click', () => {
loginScreen.classList.add('hidden');
registerScreen.classList.remove('hidden');
});
showLoginBtn.addEventListener('click', () => {
registerScreen.classList.add('hidden');
loginScreen.classList.remove('hidden');
});
loginBtn.addEventListener('click', handleLogin);
registerBtn.addEventListener('click', handleRegister);
logoutBtn.addEventListener('click', handleLogout);
sendBtn.addEventListener('click', sendMessage);
messageInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
sendMessage();
}
});
changeUsernameBtn.addEventListener('click', () => {
newUsernameInput.value = currentUser.username;
usernameModal.classList.remove('hidden');
});
changePasswordBtn.addEventListener('click', () => {
currentPasswordInput.value = '';
newPasswordInput.value = '';
passwordModal.classList.remove('hidden');
});
saveUsernameBtn.addEventListener('click', saveUsername);
cancelUsernameBtn.addEventListener('click', () => usernameModal.classList.add('hidden'));
savePasswordBtn.addEventListener('click', savePassword);
cancelPasswordBtn.addEventListener('click', () => passwordModal.classList.add('hidden'));
executeCommandBtn.addEventListener('click', executeAdminCommand);
adminCommand.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
executeAdminCommand();
}
});
helpBtn.addEventListener('click', () => helpModal.classList.remove('hidden'));
closeHelpBtn.addEventListener('click', () => helpModal.classList.add('hidden'));
okRegisterBtn.addEventListener('click', () => {
registerSuccessModal.classList.add('hidden');
registerScreen.classList.add('hidden');
loginScreen.classList.remove('hidden');
});
// Functions
function handleLogin() {
const id = parseInt(loginIdInput.value);
const password = loginPasswordInput.value;
if (isNaN(id)) {
showAlert('Please enter a valid ID');
return;
}
if (!password) {
showAlert('Please enter your password');
return;
}
const user = data.users.find(u => u.id === id);
if (!user) {
showAlert('User not found');
return;
}
// Check if user is muted
if (data.mutedUsers[user.id] && new Date(data.mutedUsers[user.id]) > new Date()) {
const muteTime = new Date(data.mutedUsers[user.id]);
showAlert(`You are muted until ${muteTime.toLocaleString()}`);
return;
}
// Check if IP is muted
if (data.mutedIPs[currentIP] && new Date(data.mutedIPs[currentIP]) > new Date()) {
const muteTime = new Date(data.mutedIPs[currentIP]);
showAlert(`Your IP is muted until ${muteTime.toLocaleString()}`);
return;
}
if (user.password !== password) {
showAlert('Incorrect password');
return;
}
currentUser = user;
loginSuccess();
}
function handleRegister() {
const username = registerUsernameInput.value.trim();
const password = registerPasswordInput.value;
if (!username) {
showAlert('Please enter a username');
return;
}
if (username.length > 20) {
showAlert('Username must be 20 characters or less');
return;
}
if (!password) {
showAlert('Please enter a password');
return;
}
if (password.length > 20) {
showAlert('Password must be 20 characters or less');
return;
}
// Check device registration limit (2 per month)
const now = new Date();
const month = now.getFullYear() + '-' + now.getMonth();
if (!data.deviceRegistrations[currentDeviceId]) {
data.deviceRegistrations[currentDeviceId] = {};
}
if (!data.deviceRegistrations[currentDeviceId][month]) {
data.deviceRegistrations[currentDeviceId][month] = 0;
}
if (data.deviceRegistrations[currentDeviceId][month] >= 2) {
showAlert('You can only create 2 accounts per month from this device');
return;
}
// Create new user
const newId = data.users.length > 0 ? Math.max(...data.users.map(u => u.id)) + 1 : 1;
const newUser = {
id: newId,
username,
password,
registered: new Date().toISOString(),
ip: currentIP,
deviceId: currentDeviceId
};
data.users.push(newUser);
data.deviceRegistrations[currentDeviceId][month]++;
saveData();
// Show success modal
registeredId.textContent = newId;
registeredUsername.textContent = username;
registerSuccessModal.classList.remove('hidden');
}
function loginSuccess() {
loginScreen.classList.add('hidden');
registerScreen.classList.add('hidden');
chatScreen.classList.remove('hidden');
usernameDisplay.textContent = currentUser.username;
userInfo.classList.remove('hidden');
userIdDisplay.textContent = currentUser.id;
userNameDisplay.textContent = currentUser.username;
userRegistered.textContent = new Date(currentUser.registered).toLocaleString();
// Show admin panel if admin
if (currentUser.id === 0) {
adminPanel.classList.remove('hidden');
} else {
adminPanel.classList.add('hidden');
}
// Initialize message counter
if (!data.messageCounters[currentUser.id]) {
data.messageCounters[currentUser.id] = {
count: 0,
lastReset: new Date().toISOString()
};
}
// Update UI
updateMessageCounter();
updateStats();
loadMessages();
}
function handleLogout() {
currentUser = null;
chatScreen.classList.add('hidden');
loginScreen.classList.remove('hidden');
userInfo.classList.add('hidden');
loginIdInput.value = '';
loginPasswordInput.value = '';
messageInput.value = '';
}
function sendMessage() {
if (!currentUser) return;
const text = messageInput.value.trim();
if (!text) return;
// Check if user is muted
if (data.mutedUsers[currentUser.id] && new Date(data.mutedUsers[currentUser.id]) > new Date()) {
const muteTime = new Date(data.mutedUsers[currentUser.id]);
showAlert(`You are muted until ${muteTime.toLocaleString()}`);
return;
}
// Check if IP is muted
if (data.mutedIPs[currentIP] && new Date(data.mutedIPs[currentIP]) > new Date()) {
const muteTime = new Date(data.mutedIPs[currentIP]);
showAlert(`Your IP is muted until ${muteTime.toLocaleString()}`);
return;
}
// Check message limit
const now = new Date();
const lastReset = new Date(data.messageCounters[currentUser.id].lastReset);
const hoursDiff = Math.abs(now - lastReset) / 36e5;
if (hoursDiff >= 1) {
// Reset counter if more than an hour has passed
data.messageCounters[currentUser.id] = {
count: 0,
lastReset: now.toISOString()
};
}
if (data.messageCounters[currentUser.id].count >= data.messageLimit) {
showAlert(`You can only send ${data.messageLimit} messages per hour`);
return;
}
// Create message
const message = {
id: data.nextMessageId++,
userId: currentUser.id,
username: currentUser.username,
text,
timestamp: now.toISOString(),
ip: currentIP
};
data.messages.push(message);
data.messageCounters[currentUser.id].count++;
saveData();
// Update UI
messageInput.value = '';
appendMessage(message);
updateMessageCounter();
updateStats();
}
function loadMessages() {
chatMessages.innerHTML = '';
data.messages.forEach(message => {
appendMessage(message);
});
}
function appendMessage(message) {
const user = data.users.find(u => u.id === message.userId);
if (!user) return;
const messageDiv = document.createElement('div');
messageDiv.className = 'message-animation bg-gray-50 p-3 rounded-lg border border-gray-200';
const header = document.createElement('div');
header.className = 'flex justify-between items-center text-sm mb-1';
const userInfo = document.createElement('span');
userInfo.className = 'font-semibold';
userInfo.textContent = `${user.username} / ${user.id} / m${message.id}`;
const time = document.createElement('span');
time.className = 'text-gray-500';
time.textContent = new Date(message.timestamp).toLocaleTimeString();
header.appendChild(userInfo);
header.appendChild(time);
const content = document.createElement('div');
content.className = 'text-gray-800';
content.textContent = message.text;
messageDiv.appendChild(header);
messageDiv.appendChild(content);
chatMessages.appendChild(messageDiv);
chatMessages.scrollTop = chatMessages.scrollHeight;
}
function updateMessageCounter() {
if (!currentUser) return;
const now = new Date();
const lastReset = new Date(data.messageCounters[currentUser.id].lastReset);
const hoursDiff = Math.abs(now - lastReset) / 36e5;
if (hoursDiff >= 1) {
// Reset counter if more than an hour has passed
data.messageCounters[currentUser.id] = {
count: 0,
lastReset: now.toISOString()
};
saveData();
}
messagesSent.textContent = data.messageCounters[currentUser.id].count;
messageLimit.textContent = data.messageLimit;
}
function updateStats() {
messageCount.textContent = data.messages.length;
userCount.textContent = data.users.length;
}
function saveUsername() {
const newUsername = newUsernameInput.value.trim();
if (!newUsername) {
showAlert('Please enter a username');
return;
}
if (newUsername.length > 20) {
showAlert('Username must be 20 characters or less');
return;
}
currentUser.username = newUsername;
usernameDisplay.textContent = newUsername;
userNameDisplay.textContent = newUsername;
// Update all messages with new username
data.messages.forEach(message => {
if (message.userId === currentUser.id) {
message.username = newUsername;
}
});
saveData();
usernameModal.classList.add('hidden');
loadMessages();
showAlert('Username updated successfully');
}
function savePassword() {
const currentPassword = currentPasswordInput.value;
const newPassword = newPasswordInput.value;
if (!currentPassword) {
showAlert('Please enter your current password');
return;
}
if (currentUser.password !== currentPassword) {
showAlert('Current password is incorrect');
return;
}
if (!newPassword) {
showAlert('Please enter a new password');
return;
}
if (newPassword.length > 20) {
showAlert('Password must be 20 characters or less');
return;
}
currentUser.password = newPassword;
saveData();
passwordModal.classList.add('hidden');
showAlert('Password updated successfully');
}
function executeAdminCommand() {
if (!currentUser || currentUser.id !== 0) return;
const command = adminCommand.value.trim();
if (!command) return;
adminCommand.value = '';
const parts = command.split(' ');
const cmd = parts[0].toLowerCase();
const args = parts.slice(1);
let response = '';
switch (cmd) {
case '/mute':
if (args.length !== 2) {
response = 'Usage: /mute id hours';
break;
}
const muteId = parseInt(args[0]);
const muteHours = parseInt(args[1]);
if (isNaN(muteId) || isNaN(muteHours) || muteHours <= 0) {
response = 'Invalid arguments';
break;
}
if (muteId === 0) {
response = 'Cannot mute admin';
break;
}
const muteUser = data.users.find(u => u.id === muteId);
if (!muteUser) {
response = 'User not found';
break;
}
const muteTime = new Date();
muteTime.setHours(muteTime.getHours() + muteHours);
data.mutedUsers[muteId] = muteTime.toISOString();
saveData();
response = `User ${muteUser.username} (ID: ${muteId}) muted for ${muteHours} hours`;
break;
case '/unmute':
if (args.length !== 1) {
response = 'Usage: /unmute id';
break;
}
const unmuteId = parseInt(args[0]);
if (isNaN(unmuteId)) {
response = 'Invalid ID';
break;
}
if (!data.mutedUsers[unmuteId]) {
response = 'User is not muted';
break;
}
delete data.mutedUsers[unmuteId];
saveData();
response = `User ID ${unmuteId} unmuted`;
break;
case '/del_m':
if (args.length !== 1) {
response = 'Usage: /del_m mid';
break;
}
const messageId = parseInt(args[0]);
if (isNaN(messageId)) {
response = 'Invalid message ID';
break;
}
const messageIndex = data.messages.findIndex(m => m.id === messageId);
if (messageIndex === -1) {
response = 'Message not found';
break;
}
data.messages.splice(messageIndex, 1);
saveData();
loadMessages();
response = `Message m${messageId} deleted`;
break;
case '/del_um':
if (args.length !== 1) {
response = 'Usage: /del_um id';
break;
}
const userId = parseInt(args[0]);
if (isNaN(userId)) {
response = 'Invalid user ID';
break;
}
const userMessages = data.messages.filter(m => m.userId === userId);
if (userMessages.length === 0) {
response = 'No messages found for this user';
break;
}
data.messages = data.messages.filter(m => m.userId !== userId);
saveData();
loadMessages();
response = `Deleted ${userMessages.length} messages from user ID ${userId}`;
break;
case '/limit_m':
if (args.length !== 1) {
response = 'Usage: /limit_m x';
break;
}
const newLimit = parseInt(args[0]);
if (isNaN(newLimit) || newLimit <= 0) {
response = 'Invalid limit';
break;
}
data.messageLimit = newLimit;
saveData();
updateMessageCounter();
response = `Message limit set to ${newLimit} per hour`;
break;
case '/limit_reset':
for (const userId in data.messageCounters) {
data.messageCounters[userId] = {
count: 0,
lastReset: new Date().toISOString()
};
}
saveData();
updateMessageCounter();
response = 'All message counters reset';
break;
case '/vipe_chat':
data.messages = [];
saveData();
loadMessages();
response = 'Chat cleared';
break;
case '/vipe_all':
data.messages = [];
data.users = data.users.filter(u => u.id === 0);
data.mutedUsers = {};
data.mutedIPs = {};
data.messageCounters = {};
data.deviceRegistrations = {};
data.messageLimit = 10;
data.nextMessageId = 1;
saveData();
loadMessages();
response = 'All data cleared except admin account';
break;
case '/change_n':
if (args.length < 2) {
response = 'Usage: /change_n id new_username';
break;
}
const changeId = parseInt(args[0]);
const newName = args.slice(1).join(' ');
if (isNaN(changeId)) {
response = 'Invalid ID';
break;
}
if (newName.length > 20) {
response = 'Username must be 20 characters or less';
break;
}
const changeUser = data.users.find(u => u.id === changeId);
if (!changeUser) {
response = 'User not found';
break;
}
changeUser.username = newName;
// Update all messages with new username
data.messages.forEach(message => {
if (message.userId === changeId) {
message.username = newName;
}
});
saveData();
loadMessages();
if (currentUser.id === changeId) {
usernameDisplay.textContent = newName;
userNameDisplay.textContent = newName;
}
response = `Username for ID ${changeId} changed to "${newName}"`;
break;
case '/change_p':
if (args.length !== 2) {
response = 'Usage: /change_p id new_password';
break;
}
const passId = parseInt(args[0]);
const newPass = args[1];
if (isNaN(passId)) {
response = 'Invalid ID';
break;
}
if (newPass.length > 20) {
response = 'Password must be 20 characters or less';
break;
}
const passUser = data.users.find(u => u.id === passId);
if (!passUser) {
response = 'User not found';
break;
}
passUser.password = newPass;
saveData();
response = `Password for ID ${passId} changed`;
break;
case '/check_ip':
if (args.length !== 1) {
response = 'Usage: /check_ip mid';
break;
}
const checkId = parseInt(args[0]);
if (isNaN(checkId)) {
response = 'Invalid message ID';
break;
}
const checkMessage = data.messages.find(m => m.id === checkId);
if (!checkMessage) {
response = 'Message not found';
break;
}
response = `Message m${checkId} was sent from IP: ${checkMessage.ip}`;
break;
case '/mute_ip':
if (args.length !== 2) {
response = 'Usage: /mute_ip ip hours';
break;
}
const muteIp = args[0];
const muteIpHours = parseInt(args[1]);
if (isNaN(muteIpHours) || muteIpHours <= 0) {
response = 'Invalid hours';
break;
}
const muteIpTime = new Date();
muteIpTime.setHours(muteIpTime.getHours() + muteIpHours);
data.mutedIPs[muteIp] = muteIpTime.toISOString();
saveData();
response = `IP ${muteIp} muted for ${muteIpHours} hours`;
break;
case '/unmute_ip':
if (args.length !== 1) {
response = 'Usage: /unmute_ip ip';
break;
}
const unmuteIp = args[0];
if (!data.mutedIPs[unmuteIp]) {
response = 'IP is not muted';
break;
}
delete data.mutedIPs[unmuteIp];
saveData();
response = `IP ${unmuteIp} unmuted`;
break;
case '/list':
const mutedUsersList = Object.entries(data.mutedUsers)
.map(([id, time]) => {
const user = data.users.find(u => u.id === parseInt(id));
const username = user ? user.username : 'Unknown';
return `User: ${username} (ID: ${id}) until ${new Date(time).toLocaleString()}`;
})
.join('\n');
const mutedIPsList = Object.entries(data.mutedIPs)
.map(([ip, time]) => `IP: ${ip} until ${new Date(time).toLocaleString()}`)
.join('\n');
response = 'Muted Users:\n' + (mutedUsersList || 'None') + '\n\nMuted IPs:\n' + (mutedIPsList || 'None');
break;
case '/help':
helpModal.classList.remove('hidden');
break;
default:
response = 'Unknown command. Type /help for available commands';
}
if (response) {
showAlert(response);
}
}
function showAlert(message) {
const alertDiv = document.createElement('div');
alertDiv.className = 'fixed bottom-4 right-4 bg-gray-800 text-white px-4 py-3 rounded shadow-lg message-animation';
alertDiv.textContent = message;
document.body.appendChild(alertDiv);
setTimeout(() => {
alertDiv.classList.add('opacity-0', 'transition-opacity', 'duration-300');
setTimeout(() => {
document.body.removeChild(alertDiv);
}, 300);
}, 3000);
}
// Initialize
updateStats();
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Dapshen/null-v-0" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>