null-v-0 / index.html
Dapshen's picture
Add 3 files
3a2e0ad verified
Raw History Blame Contribute Delete
50.8 kB
<!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>
<!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>