null_0_1 / index.html
Dapshen's picture
Add 3 files
a83a357 verified
Raw History Blame Contribute Delete
49.2 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>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> .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; } } .scrollbar-hide::-webkit-scrollbar { display: none; } .scrollbar-hide { -ms-overflow-style: none; scrollbar-width: none; } </style> </head> <body class="bg-gray-900 text-gray-100 min-h-screen"> <div id="app" class="container mx-auto px-4 py-8 max-w-6xl"> <!-- Auth Screen --> <div id="auth-screen" class="flex flex-col items-center justify-center min-h-[80vh]"> <div class="bg-gray-800 rounded-xl p-8 w-full max-w-md shadow-2xl border border-gray-700"> <div class="text-center mb-8"> <h1 class="text-4xl font-bold text-purple-500 mb-2">NULL</h1> <p class="text-gray-400">Secure anonymous messaging</p> </div> <div id="auth-tabs" class="flex mb-6 border-b border-gray-700"> <button id="login-tab" class="flex-1 py-2 font-medium text-purple-500 border-b-2 border-purple-500">Login</button> <button id="register-tab" class="flex-1 py-2 font-medium text-gray-400 hover:text-gray-300">Register</button> </div> <!-- Login Form --> <div id="login-form" class="space-y-4"> <div> <label for="login-id" class="block text-sm font-medium mb-1">ID</label> <input type="number" id="login-id" class="w-full px-4 py-2 bg-gray-700 rounded-lg focus:ring-2 focus:ring-purple-500 focus:outline-none"> </div> <div> <label for="login-password" class="block text-sm font-medium mb-1">Password</label> <input type="password" id="login-password" class="w-full px-4 py-2 bg-gray-700 rounded-lg focus:ring-2 focus:ring-purple-500 focus:outline-none"> </div> <button id="login-btn" class="w-full bg-purple-600 hover:bg-purple-700 text-white py-2 px-4 rounded-lg font-medium transition duration-200 mt-4"> Login </button> </div> <!-- Register Form --> <div id="register-form" class="space-y-4 hidden"> <div> <label for="register-name" class="block text-sm font-medium mb-1">Name (max 20 chars)</label> <input type="text" id="register-name" maxlength="20" class="w-full px-4 py-2 bg-gray-700 rounded-lg focus:ring-2 focus:ring-purple-500 focus:outline-none"> </div> <div> <label for="register-password" class="block text-sm font-medium mb-1">Password (max 20 chars)</label> <input type="password" id="register-password" maxlength="20" class="w-full px-4 py-2 bg-gray-700 rounded-lg focus:ring-2 focus:ring-purple-500 focus:outline-none"> </div> <button id="register-btn" class="w-full bg-purple-600 hover:bg-purple-700 text-white py-2 px-4 rounded-lg font-medium transition duration-200 mt-4"> Register </button> </div> <div id="auth-message" class="mt-4 text-sm text-center text-red-500 hidden"></div> </div> </div> <!-- Chat Screen --> <div id="chat-screen" class="hidden"> <div class="flex flex-col h-[80vh] border border-gray-700 rounded-xl overflow-hidden"> <!-- Header --> <div class="bg-gray-800 p-4 flex justify-between items-center border-b border-gray-700"> <div class="flex items-center"> <h2 class="text-xl font-bold text-purple-500">NULL CHAT</h2> <span id="user-badge" class="ml-2 px-2 py-1 text-xs rounded-full bg-gray-700"></span> </div> <div class="flex space-x-2"> <button id="settings-btn" class="p-2 text-gray-400 hover:text-purple-500 rounded-full hover:bg-gray-700 transition"> <i class="fas fa-cog"></i> </button> <button id="logout-btn" class="p-2 text-gray-400 hover:text-purple-500 rounded-full hover:bg-gray-700 transition"> <i class="fas fa-sign-out-alt"></i> </button> <button id="admin-btn" class="p-2 text-gray-400 hover:text-purple-500 rounded-full hover:bg-gray-700 transition hidden"> <i class="fas fa-shield-alt"></i> </button> </div> </div> <!-- Messages --> <div id="messages-container" class="flex-1 overflow-y-auto p-4 bg-gray-800 scrollbar-hide"> <div id="messages" class="space-y-3"></div> </div> <!-- Message Input --> <div class="bg-gray-800 p-4 border-t border-gray-700"> <div class="flex space-x-2"> <input id="message-input" type="text" maxlength="1000" placeholder="Type your message..." class="flex-1 px-4 py-2 bg-gray-700 rounded-lg focus:ring-2 focus:ring-purple-500 focus:outline-none"> <button id="send-btn" class="bg-purple-600 hover:bg-purple-700 text-white px-4 py-2 rounded-lg font-medium transition duration-200"> Send </button> </div> <div id="message-counter" class="text-xs text-gray-500 mt-1 text-right"></div> <div id="message-error" class="text-xs text-red-500 mt-1 hidden"></div> </div> </div> </div> <!-- Settings Modal --> <div id="settings-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> <div class="bg-gray-800 rounded-xl p-6 w-full max-w-md border border-gray-700"> <div class="flex justify-between items-center mb-4"> <h3 class="text-xl font-bold">Settings</h3> <button id="close-settings" class="text-gray-400 hover:text-white"> <i class="fas fa-times"></i> </button> </div> <div class="space-y-4"> <div> <label class="block text-sm font-medium mb-1">Change Name (max 20 chars)</label> <div class="flex space-x-2"> <input type="text" id="new-name" maxlength="20" class="flex-1 px-4 py-2 bg-gray-700 rounded-lg focus:ring-2 focus:ring-purple-500 focus:outline-none"> <button id="change-name-btn" class="bg-purple-600 hover:bg-purple-700 text-white px-4 py-2 rounded-lg font-medium transition duration-200"> Update </button> </div> </div> <div> <label class="block text-sm font-medium mb-1">Change Password (max 20 chars)</label> <div class="flex space-x-2"> <input type="password" id="new-password" maxlength="20" class="flex-1 px-4 py-2 bg-gray-700 rounded-lg focus:ring-2 focus:ring-purple-500 focus:outline-none"> <button id="change-password-btn" class="bg-purple-600 hover:bg-purple-700 text-white px-4 py-2 rounded-lg font-medium transition duration-200"> Update </button> </div> </div> </div> <div id="settings-message" class="mt-4 text-sm text-center hidden"></div> </div> </div> <!-- Admin Panel Modal --> <div id="admin-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> <div class="bg-gray-800 rounded-xl p-6 w-full max-w-4xl border border-gray-700 max-h-[90vh] flex flex-col"> <div class="flex justify-between items-center mb-4"> <h3 class="text-xl font-bold text-purple-500">Admin Panel</h3> <button id="close-admin" class="text-gray-400 hover:text-white"> <i class="fas fa-times"></i> </button> </div> <div class="flex-1 overflow-hidden flex flex-col"> <div class="bg-gray-900 p-4 rounded-lg mb-4 overflow-y-auto scrollbar-hide flex-1"> <div id="admin-console" class="font-mono text-sm space-y-2"> <div class="text-green-400">Welcome to Admin Panel</div> <div class="text-gray-500">Type /help to see available commands</div> </div> </div> <div class="flex space-x-2"> <input id="admin-command" type="text" placeholder="Enter command..." class="flex-1 px-4 py-2 bg-gray-700 rounded-lg focus:ring-2 focus:ring-purple-500 focus:outline-none"> <button id="execute-command" class="bg-purple-600 hover:bg-purple-700 text-white px-4 py-2 rounded-lg font-medium transition duration-200"> Execute </button> </div> </div> </div> </div> </div> <script> // Data storage let users = [ { id: 0, name: "Null", password: "QWERTYnull123!", isAdmin: true } ]; let messages = []; let mutedAccounts = []; let mutedIPs = []; let messageLimit = 10; let messageCounts = {}; let accountCreationLimits = {}; // Current user state let currentUser = null; let currentIP = generateRandomIP(); // Simulated IP for demo // DOM elements const authScreen = document.getElementById('auth-screen'); const chatScreen = document.getElementById('chat-screen'); const loginForm = document.getElementById('login-form'); const registerForm = document.getElementById('register-form'); const loginTab = document.getElementById('login-tab'); const registerTab = document.getElementById('register-tab'); const loginBtn = document.getElementById('login-btn'); const registerBtn = document.getElementById('register-btn'); const loginIdInput = document.getElementById('login-id'); const loginPasswordInput = document.getElementById('login-password'); const registerNameInput = document.getElementById('register-name'); const registerPasswordInput = document.getElementById('register-password'); const authMessage = document.getElementById('auth-message'); const messagesContainer = document.getElementById('messages'); const messageInput = document.getElementById('message-input'); const sendBtn = document.getElementById('send-btn'); const messageCounter = document.getElementById('message-counter'); const messageError = document.getElementById('message-error'); const userBadge = document.getElementById('user-badge'); const settingsBtn = document.getElementById('settings-btn'); const logoutBtn = document.getElementById('logout-btn'); const adminBtn = document.getElementById('admin-btn'); const settingsModal = document.getElementById('settings-modal'); const closeSettings = document.getElementById('close-settings'); const newNameInput = document.getElementById('new-name'); const newPasswordInput = document.getElementById('new-password'); const changeNameBtn = document.getElementById('change-name-btn'); const changePasswordBtn = document.getElementById('change-password-btn'); const settingsMessage = document.getElementById('settings-message'); const adminModal = document.getElementById('admin-modal'); const closeAdmin = document.getElementById('close-admin'); const adminCommand = document.getElementById('admin-command'); const executeCommand = document.getElementById('execute-command'); const adminConsole = document.getElementById('admin-console'); // Initialize loadFromLocalStorage(); renderMessageCounter(); // Event listeners loginTab.addEventListener('click', () => { loginTab.classList.add('text-purple-500', 'border-purple-500'); loginTab.classList.remove('text-gray-400'); registerTab.classList.add('text-gray-400'); registerTab.classList.remove('text-purple-500', 'border-purple-500'); loginForm.classList.remove('hidden'); registerForm.classList.add('hidden'); authMessage.classList.add('hidden'); }); registerTab.addEventListener('click', () => { registerTab.classList.add('text-purple-500', 'border-purple-500'); registerTab.classList.remove('text-gray-400'); loginTab.classList.add('text-gray-400'); loginTab.classList.remove('text-purple-500', 'border-purple-500'); registerForm.classList.remove('hidden'); loginForm.classList.add('hidden'); authMessage.classList.add('hidden'); }); loginBtn.addEventListener('click', handleLogin); registerBtn.addEventListener('click', handleRegister); sendBtn.addEventListener('click', sendMessage); messageInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') sendMessage(); }); settingsBtn.addEventListener('click', () => { newNameInput.value = currentUser.name; newPasswordInput.value = ''; settingsMessage.classList.add('hidden'); settingsModal.classList.remove('hidden'); }); logoutBtn.addEventListener('click', handleLogout); adminBtn.addEventListener('click', () => { adminModal.classList.remove('hidden'); }); closeSettings.addEventListener('click', () => { settingsModal.classList.add('hidden'); }); closeAdmin.addEventListener('click', () => { adminModal.classList.add('hidden'); }); changeNameBtn.addEventListener('click', changeName); changePasswordBtn.addEventListener('click', changePassword); executeCommand.addEventListener('click', executeAdminCommand); adminCommand.addEventListener('keypress', (e) => { if (e.key === 'Enter') executeAdminCommand(); }); // Functions function handleLogin() { const id = parseInt(loginIdInput.value); const password = loginPasswordInput.value; if (isNaN(id)) { showAuthMessage('ID must be a number'); return; } const user = users.find(u => u.id === id); if (!user) { showAuthMessage('User not found'); return; } // Check if account is muted const muteRecord = mutedAccounts.find(m => m.id === id && m.expires > Date.now()); if (muteRecord) { const hoursLeft = Math.ceil((muteRecord.expires - Date.now()) / (1000 * 60 * 60)); showAuthMessage(`Account is muted for ${hoursLeft} more hours`); return; } // Check if IP is muted const ipMuteRecord = mutedIPs.find(m => m.ip === currentIP && m.expires > Date.now()); if (ipMuteRecord) { const hoursLeft = Math.ceil((ipMuteRecord.expires - Date.now()) / (1000 * 60 * 60)); showAuthMessage(`Your IP is muted for ${hoursLeft} more hours`); return; } if (user.password !== password) { showAuthMessage('Incorrect password'); return; } currentUser = user; authScreen.classList.add('hidden'); chatScreen.classList.remove('hidden'); if (currentUser.isAdmin) { adminBtn.classList.remove('hidden'); } userBadge.textContent = `${currentUser.name} (ID: ${currentUser.id})`; renderMessages(); renderMessageCounter(); // Clear inputs loginIdInput.value = ''; loginPasswordInput.value = ''; authMessage.classList.add('hidden'); } function handleRegister() { const name = registerNameInput.value.trim(); const password = registerPasswordInput.value; if (!name || !password) { showAuthMessage('Name and password are required'); return; } if (name.length > 20) { showAuthMessage('Name must be 20 characters or less'); return; } if (password.length > 20) { showAuthMessage('Password must be 20 characters or less'); return; } // Check if IP has created too many accounts const now = Date.now(); const lastMonth = now - 30 * 24 * 60 * 60 * 1000; if (!accountCreationLimits[currentIP]) { accountCreationLimits[currentIP] = []; } // Remove old records accountCreationLimits[currentIP] = accountCreationLimits[currentIP].filter(t => t > lastMonth); if (accountCreationLimits[currentIP].length >= 2) { showAuthMessage('You can only create 2 accounts per month from this device'); return; } // Create new user const newId = users.length > 0 ? Math.max(...users.map(u => u.id)) + 1 : 1; const newUser = { id: newId, name, password, isAdmin: false }; users.push(newUser); accountCreationLimits[currentIP].push(now); // Show success message with ID showAuthMessage(`Account created! Your ID is ${newId}`, 'green'); // Clear inputs registerNameInput.value = ''; registerPasswordInput.value = ''; saveToLocalStorage(); } function handleLogout() { currentUser = null; chatScreen.classList.add('hidden'); authScreen.classList.remove('hidden'); adminModal.classList.add('hidden'); settingsModal.classList.add('hidden'); } function sendMessage() { const text = messageInput.value.trim(); if (!text) return; // Check if user is muted const muteRecord = mutedAccounts.find(m => m.id === currentUser.id && m.expires > Date.now()); if (muteRecord) { const hoursLeft = Math.ceil((muteRecord.expires - Date.now()) / (1000 * 60 * 60)); showMessageError(`You are muted for ${hoursLeft} more hours`); return; } // Check if IP is muted const ipMuteRecord = mutedIPs.find(m => m.ip === currentIP && m.expires > Date.now()); if (ipMuteRecord) { const hoursLeft = Math.ceil((ipMuteRecord.expires - Date.now()) / (1000 * 60 * 60)); showMessageError(`Your IP is muted for ${hoursLeft} more hours`); return; } // Check message limit const now = Date.now(); const lastHour = now - 60 * 60 * 1000; if (!messageCounts[currentUser.id]) { messageCounts[currentUser.id] = []; } // Remove old records messageCounts[currentUser.id] = messageCounts[currentUser.id].filter(t => t > lastHour); if (messageCounts[currentUser.id].length >= messageLimit) { showMessageError(`You can only send ${messageLimit} messages per hour`); return; } // Create message const messageId = messages.length > 0 ? Math.max(...messages.map(m => m.id)) + 1 : 1; const newMessage = { id: messageId, userId: currentUser.id, userName: currentUser.name, text, timestamp: now, ip: currentIP }; messages.push(newMessage); messageCounts[currentUser.id].push(now); // Clear input and render messageInput.value = ''; renderMessages(); renderMessageCounter(); messageError.classList.add('hidden'); // Auto-scroll to bottom setTimeout(() => { messagesContainer.scrollTop = messagesContainer.scrollHeight; }, 100); saveToLocalStorage(); } function renderMessages() { messagesContainer.innerHTML = ''; messages.forEach(msg => { const messageElement = document.createElement('div'); messageElement.className = 'bg-gray-700 p-3 rounded-lg message-animation'; const header = document.createElement('div'); header.className = 'flex justify-between text-xs text-gray-400 mb-1'; header.innerHTML = ` <span>${msg.userName} / ID: ${msg.userId} / mID: ${msg.id}</span> <span>${formatTime(msg.timestamp)}</span> `; const content = document.createElement('div'); content.className = 'text-gray-100'; content.textContent = msg.text; messageElement.appendChild(header); messageElement.appendChild(content); messagesContainer.appendChild(messageElement); }); } function renderMessageCounter() { if (!currentUser) return; const now = Date.now(); const lastHour = now - 60 * 60 * 1000; if (!messageCounts[currentUser.id]) { messageCounts[currentUser.id] = []; } // Remove old records messageCounts[currentUser.id] = messageCounts[currentUser.id].filter(t => t > lastHour); const count = messageCounts[currentUser.id].length; const remaining = Math.max(0, messageLimit - count); messageCounter.textContent = `Messages this hour: ${count}/${messageLimit} (${remaining} remaining)`; if (count >= messageLimit) { messageCounter.classList.add('text-red-400'); messageCounter.classList.remove('text-gray-500'); } else { messageCounter.classList.add('text-gray-500'); messageCounter.classList.remove('text-red-400'); } } function changeName() { const newName = newNameInput.value.trim(); if (!newName) { showSettingsMessage('Name cannot be empty', 'red'); return; } if (newName.length > 20) { showSettingsMessage('Name must be 20 characters or less', 'red'); return; } currentUser.name = newName; userBadge.textContent = `${currentUser.name} (ID: ${currentUser.id})`; // Update name in all messages messages.forEach(msg => { if (msg.userId === currentUser.id) { msg.userName = newName; } }); showSettingsMessage('Name updated successfully', 'green'); renderMessages(); saveToLocalStorage(); } function changePassword() { const newPassword = newPasswordInput.value; if (!newPassword) { showSettingsMessage('Password cannot be empty', 'red'); return; } if (newPassword.length > 20) { showSettingsMessage('Password must be 20 characters or less', 'red'); return; } currentUser.password = newPassword; showSettingsMessage('Password updated successfully', 'green'); newPasswordInput.value = ''; saveToLocalStorage(); } function executeAdminCommand() { if (!currentUser || !currentUser.isAdmin) return; const command = adminCommand.value.trim(); adminCommand.value = ''; if (!command) return; // Add command to console addToConsole(`> ${command}`, 'text-purple-400'); // Parse command const parts = command.split(' '); const cmd = parts[0].toLowerCase(); const args = parts.slice(1); // Process commands switch (cmd) { case '/mute': if (args.length !== 2) { addToConsole('Usage: /mute id hours', 'text-red-400'); break; } const muteId = parseInt(args[0]); const muteHours = parseInt(args[1]); if (isNaN(muteId) || isNaN(muteHours)) { addToConsole('Invalid id or hours', 'text-red-400'); break; } muteAccount(muteId, muteHours); break; case '/unmute': if (args.length !== 1) { addToConsole('Usage: /unmute id', 'text-red-400'); break; } const unmuteId = parseInt(args[0]); if (isNaN(unmuteId)) { addToConsole('Invalid id', 'text-red-400'); break; } unmuteAccount(unmuteId); break; case '/del_m': if (args.length !== 1) { addToConsole('Usage: /del_m mid', 'text-red-400'); break; } const delMid = parseInt(args[0]); if (isNaN(delMid)) { addToConsole('Invalid message id', 'text-red-400'); break; } deleteMessage(delMid); break; case '/del_um': if (args.length !== 1) { addToConsole('Usage: /del_um id', 'text-red-400'); break; } const delUserId = parseInt(args[0]); if (isNaN(delUserId)) { addToConsole('Invalid user id', 'text-red-400'); break; } deleteUserMessages(delUserId); break; case '/limit_m': if (args.length !== 1) { addToConsole('Usage: /limit_m x', 'text-red-400'); break; } const newLimit = parseInt(args[0]); if (isNaN(newLimit) || newLimit < 1) { addToConsole('Invalid limit (must be positive number)', 'text-red-400'); break; } setMessageLimit(newLimit); break; case '/limit_reset': resetMessageCounts(); break; case '/vipe_chat': clearChat(); break; case '/vipe_all': clearAll(); break; case '/change_n': if (args.length < 2) { addToConsole('Usage: /change_n id name', 'text-red-400'); break; } const changeNameId = parseInt(args[0]); if (isNaN(changeNameId)) { addToConsole('Invalid id', 'text-red-400'); break; } const newUserName = args.slice(1).join(' '); changeUserName(changeNameId, newUserName); break; case '/change_p': if (args.length !== 2) { addToConsole('Usage: /change_p id password', 'text-red-400'); break; } const changePassId = parseInt(args[0]); if (isNaN(changePassId)) { addToConsole('Invalid id', 'text-red-400'); break; } const newUserPass = args[1]; changeUserPassword(changeNameId, newUserPass); break; case '/check_ip': if (args.length !== 1) { addToConsole('Usage: /check_ip mid', 'text-red-400'); break; } const checkIpMid = parseInt(args[0]); if (isNaN(checkIpMid)) { addToConsole('Invalid message id', 'text-red-400'); break; } checkMessageIP(checkIpMid); break; case '/mute_ip': if (args.length !== 2) { addToConsole('Usage: /mute_ip ip hours', 'text-red-400'); break; } const muteIp = args[0]; const muteIpHours = parseInt(args[1]); if (isNaN(muteIpHours)) { addToConsole('Invalid hours', 'text-red-400'); break; } muteIP(muteIp, muteIpHours); break; case '/unmute_ip': if (args.length !== 1) { addToConsole('Usage: /unmute_ip ip', 'text-red-400'); break; } const unmuteIp = args[0]; unmuteIP(unmuteIp); break; case '/mutes': showMutes(); break; case '/create': if (args.length < 2) { addToConsole('Usage: /create name password', 'text-red-400'); break; } const createName = args[0]; const createPass = args.slice(1).join(' '); createUser(createName, createPass); break; case '/info_n': if (args.length !== 1) { addToConsole('Usage: /info_n id', 'text-red-400'); break; } const infoId = parseInt(args[0]); if (isNaN(infoId)) { addToConsole('Invalid id', 'text-red-400'); break; } getUserName(infoId); break; case '/list': listUsers(); break; case '/help': showHelp(); break; default: addToConsole('Unknown command. Type /help for list of commands', 'text-red-400'); } // Auto-scroll console to bottom setTimeout(() => { adminConsole.scrollTop = adminConsole.scrollHeight; }, 10); } // Admin command functions function muteAccount(id, hours) { const user = users.find(u => u.id === id); if (!user) { addToConsole(`User with ID ${id} not found`, 'text-red-400'); return; } if (id === 0) { addToConsole('Cannot mute admin account', 'text-red-400'); return; } const expires = Date.now() + hours * 60 * 60 * 1000; // Remove existing mute if any mutedAccounts = mutedAccounts.filter(m => m.id !== id); mutedAccounts.push({ id, expires }); addToConsole(`User ${user.name} (ID: ${id}) muted for ${hours} hours`, 'text-green-400'); saveToLocalStorage(); } function unmuteAccount(id) { const user = users.find(u => u.id === id); if (!user) { addToConsole(`User with ID ${id} not found`, 'text-red-400'); return; } const wasMuted = mutedAccounts.some(m => m.id === id); mutedAccounts = mutedAccounts.filter(m => m.id !== id); if (wasMuted) { addToConsole(`User ${user.name} (ID: ${id}) unmuted`, 'text-green-400'); } else { addToConsole(`User ${user.name} (ID: ${id}) was not muted`, 'text-yellow-400'); } saveToLocalStorage(); } function deleteMessage(mid) { const messageIndex = messages.findIndex(m => m.id === mid); if (messageIndex === -1) { addToConsole(`Message with ID ${mid} not found`, 'text-red-400'); return; } messages.splice(messageIndex, 1); addToConsole(`Message ${mid} deleted`, 'text-green-400'); renderMessages(); saveToLocalStorage(); } function deleteUserMessages(id) { const user = users.find(u => u.id === id); if (!user) { addToConsole(`User with ID ${id} not found`, 'text-red-400'); return; } const count = messages.filter(m => m.userId === id).length; messages = messages.filter(m => m.userId !== id); addToConsole(`Deleted ${count} messages from user ${user.name} (ID: ${id})`, 'text-green-400'); renderMessages(); saveToLocalStorage(); } function setMessageLimit(limit) { messageLimit = limit; addToConsole(`Message limit set to ${limit} per hour`, 'text-green-400'); renderMessageCounter(); saveToLocalStorage(); } function resetMessageCounts() { messageCounts = {}; addToConsole('All message counts reset to 0', 'text-green-400'); renderMessageCounter(); saveToLocalStorage(); } function clearChat() { messages = []; addToConsole('Chat cleared', 'text-green-400'); renderMessages(); saveToLocalStorage(); } function clearAll() { // Keep only admin account users = users.filter(u => u.id === 0); messages = []; mutedAccounts = []; mutedIPs = []; messageCounts = {}; accountCreationLimits = {}; addToConsole('All data cleared except admin account', 'text-green-400'); if (currentUser && currentUser.id !== 0) { handleLogout(); } else { renderMessages(); } saveToLocalStorage(); } function changeUserName(id, newName) { const user = users.find(u => u.id === id); if (!user) { addToConsole(`User with ID ${id} not found`, 'text-red-400'); return; } if (newName.length > 20) { addToConsole('Name must be 20 characters or less', 'text-red-400'); return; } const oldName = user.name; user.name = newName; // Update name in messages messages.forEach(msg => { if (msg.userId === id) { msg.userName = newName; } }); addToConsole(`Changed name for user ${id} from "${oldName}" to "${newName}"`, 'text-green-400'); if (currentUser && currentUser.id === id) { userBadge.textContent = `${newName} (ID: ${id})`; } renderMessages(); saveToLocalStorage(); } function changeUserPassword(id, newPassword) { const user = users.find(u => u.id === id); if (!user) { addToConsole(`User with ID ${id} not found`, 'text-red-400'); return; } if (newPassword.length > 20) { addToConsole('Password must be 20 characters or less', 'text-red-400'); return; } user.password = newPassword; addToConsole(`Password changed for user ${user.name} (ID: ${id})`, 'text-green-400'); saveToLocalStorage(); } function checkMessageIP(mid) { const message = messages.find(m => m.id === mid); if (!message) { addToConsole(`Message with ID ${mid} not found`, 'text-red-400'); return; } addToConsole(`Message ${mid} was sent from IP: ${message.ip}`, 'text-green-400'); } function muteIP(ip, hours) { const expires = Date.now() + hours * 60 * 60 * 1000; // Remove existing mute if any mutedIPs = mutedIPs.filter(m => m.ip !== ip); mutedIPs.push({ ip, expires }); addToConsole(`IP ${ip} muted for ${hours} hours`, 'text-green-400'); saveToLocalStorage(); } function unmuteIP(ip) { const wasMuted = mutedIPs.some(m => m.ip === ip); mutedIPs = mutedIPs.filter(m => m.ip !== ip); if (wasMuted) { addToConsole(`IP ${ip} unmuted`, 'text-green-400'); } else { addToConsole(`IP ${ip} was not muted`, 'text-yellow-400'); } saveToLocalStorage(); } function showMutes() { if (mutedAccounts.length === 0 && mutedIPs.length === 0) { addToConsole('No active mutes', 'text-yellow-400'); return; } addToConsole('Active account mutes:', 'text-blue-400'); mutedAccounts.forEach(m => { const user = users.find(u => u.id === m.id); const name = user ? user.name : 'Unknown'; const hoursLeft = Math.ceil((m.expires - Date.now()) / (1000 * 60 * 60)); addToConsole(`- ${name} (ID: ${m.id}): ${hoursLeft} hours remaining`); }); addToConsole('Active IP mutes:', 'text-blue-400'); mutedIPs.forEach(m => { const hoursLeft = Math.ceil((m.expires - Date.now()) / (1000 * 60 * 60)); addToConsole(`- ${m.ip}: ${hoursLeft} hours remaining`); }); } function createUser(name, password) { if (name.length > 20) { addToConsole('Name must be 20 characters or less', 'text-red-400'); return; } if (password.length > 20) { addToConsole('Password must be 20 characters or less', 'text-red-400'); return; } const newId = users.length > 0 ? Math.max(...users.map(u => u.id)) + 1 : 1; const newUser = { id: newId, name, password, isAdmin: false }; users.push(newUser); addToConsole(`Created new user: ${name} (ID: ${newId})`, 'text-green-400'); saveToLocalStorage(); } function getUserName(id) { const user = users.find(u => u.id === id); if (!user) { addToConsole(`User with ID ${id} not found`, 'text-red-400'); return; } addToConsole(`User ${id} name: ${user.name}`, 'text-green-400'); } function listUsers() { if (users.length === 0) { addToConsole('No users found', 'text-yellow-400'); return; } addToConsole('User list (ID - Name):', 'text-blue-400'); users.forEach(user => { addToConsole(`- ${user.id}: ${user.name}${user.isAdmin ? ' (Admin)' : ''}`); }); } function showHelp() { addToConsole('Available commands:', 'text-blue-400'); addToConsole('/mute id x - Mute account by ID for x hours'); addToConsole('/unmute id - Unmute account by ID'); addToConsole('/del_m mid - Delete message by message ID'); addToConsole('/del_um id - Delete all messages by user ID'); addToConsole('/limit_m x - Set message limit per hour to x'); addToConsole('/limit_reset - Reset all message counts to 0'); addToConsole('/vipe_chat - Delete all messages'); addToConsole('/vipe_all - Delete all messages and accounts (except admin)'); addToConsole('/change_n id x - Change username of ID to x'); addToConsole('/change_p id x - Change password of ID to x'); addToConsole('/check_ip mid - Check IP of message by message ID'); addToConsole('/mute_ip ip x - Mute IP for x hours'); addToConsole('/unmute_ip ip - Unmute IP'); addToConsole('/mutes - Show all active mutes'); addToConsole('/create x y - Create account with name x and password y'); addToConsole('/info_n id - Get username by ID'); addToConsole('/list - List all accounts'); addToConsole('/help - Show this help'); } // Helper functions function showAuthMessage(message, color = 'red') { authMessage.textContent = message; authMessage.classList.remove('hidden'); authMessage.classList.remove('text-red-500', 'text-green-500'); authMessage.classList.add(color === 'green' ? 'text-green-500' : 'text-red-500'); } function showMessageError(message) { messageError.textContent = message; messageError.classList.remove('hidden'); } function showSettingsMessage(message, color = 'green') { settingsMessage.textContent = message; settingsMessage.classList.remove('hidden'); settingsMessage.classList.remove('text-red-500', 'text-green-500'); settingsMessage.classList.add(color === 'green' ? 'text-green-500' : 'text-red-500'); } function addToConsole(text, colorClass = 'text-gray-300') { const div = document.createElement('div'); div.className = colorClass; div.textContent = text; adminConsole.appendChild(div); } function formatTime(timestamp) { const date = new Date(timestamp); return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); } function generateRandomIP() { // For demo purposes only - generates a random IP return `${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}`; } // Local storage function saveToLocalStorage() { const data = { users, messages, mutedAccounts, mutedIPs, messageLimit, messageCounts, accountCreationLimits }; localStorage.setItem('nullMessenger', JSON.stringify(data)); } function loadFromLocalStorage() { const data = localStorage.getItem('nullMessenger'); if (!data) return; try { const parsed = JSON.parse(data); if (parsed.users) users = parsed.users; if (parsed.messages) messages = parsed.messages; if (parsed.mutedAccounts) mutedAccounts = parsed.mutedAccounts; if (parsed.mutedIPs) mutedIPs = parsed.mutedIPs; if (parsed.messageLimit) messageLimit = parsed.messageLimit; if (parsed.messageCounts) messageCounts = parsed.messageCounts; if (parsed.accountCreationLimits) accountCreationLimits = parsed.accountCreationLimits; // Ensure admin account exists if (!users.some(u => u.id === 0)) { users.unshift({ id: 0, name: "Null", password: "QWERTYnull123!", isAdmin: true }); } } catch (e) { console.error('Failed to load from localStorage', e); } } </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-1" 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>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>
.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; }
}
.scrollbar-hide::-webkit-scrollbar {
display: none;
}
.scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
}
</style>
</head>
<body class="bg-gray-900 text-gray-100 min-h-screen">
<div id="app" class="container mx-auto px-4 py-8 max-w-6xl">
<!-- Auth Screen -->
<div id="auth-screen" class="flex flex-col items-center justify-center min-h-[80vh]">
<div class="bg-gray-800 rounded-xl p-8 w-full max-w-md shadow-2xl border border-gray-700">
<div class="text-center mb-8">
<h1 class="text-4xl font-bold text-purple-500 mb-2">NULL</h1>
<p class="text-gray-400">Secure anonymous messaging</p>
</div>
<div id="auth-tabs" class="flex mb-6 border-b border-gray-700">
<button id="login-tab" class="flex-1 py-2 font-medium text-purple-500 border-b-2 border-purple-500">Login</button>
<button id="register-tab" class="flex-1 py-2 font-medium text-gray-400 hover:text-gray-300">Register</button>
</div>
<!-- Login Form -->
<div id="login-form" class="space-y-4">
<div>
<label for="login-id" class="block text-sm font-medium mb-1">ID</label>
<input type="number" id="login-id" class="w-full px-4 py-2 bg-gray-700 rounded-lg focus:ring-2 focus:ring-purple-500 focus:outline-none">
</div>
<div>
<label for="login-password" class="block text-sm font-medium mb-1">Password</label>
<input type="password" id="login-password" class="w-full px-4 py-2 bg-gray-700 rounded-lg focus:ring-2 focus:ring-purple-500 focus:outline-none">
</div>
<button id="login-btn" class="w-full bg-purple-600 hover:bg-purple-700 text-white py-2 px-4 rounded-lg font-medium transition duration-200 mt-4">
Login
</button>
</div>
<!-- Register Form -->
<div id="register-form" class="space-y-4 hidden">
<div>
<label for="register-name" class="block text-sm font-medium mb-1">Name (max 20 chars)</label>
<input type="text" id="register-name" maxlength="20" class="w-full px-4 py-2 bg-gray-700 rounded-lg focus:ring-2 focus:ring-purple-500 focus:outline-none">
</div>
<div>
<label for="register-password" class="block text-sm font-medium mb-1">Password (max 20 chars)</label>
<input type="password" id="register-password" maxlength="20" class="w-full px-4 py-2 bg-gray-700 rounded-lg focus:ring-2 focus:ring-purple-500 focus:outline-none">
</div>
<button id="register-btn" class="w-full bg-purple-600 hover:bg-purple-700 text-white py-2 px-4 rounded-lg font-medium transition duration-200 mt-4">
Register
</button>
</div>
<div id="auth-message" class="mt-4 text-sm text-center text-red-500 hidden"></div>
</div>
</div>
<!-- Chat Screen -->
<div id="chat-screen" class="hidden">
<div class="flex flex-col h-[80vh] border border-gray-700 rounded-xl overflow-hidden">
<!-- Header -->
<div class="bg-gray-800 p-4 flex justify-between items-center border-b border-gray-700">
<div class="flex items-center">
<h2 class="text-xl font-bold text-purple-500">NULL CHAT</h2>
<span id="user-badge" class="ml-2 px-2 py-1 text-xs rounded-full bg-gray-700"></span>
</div>
<div class="flex space-x-2">
<button id="settings-btn" class="p-2 text-gray-400 hover:text-purple-500 rounded-full hover:bg-gray-700 transition">
<i class="fas fa-cog"></i>
</button>
<button id="logout-btn" class="p-2 text-gray-400 hover:text-purple-500 rounded-full hover:bg-gray-700 transition">
<i class="fas fa-sign-out-alt"></i>
</button>
<button id="admin-btn" class="p-2 text-gray-400 hover:text-purple-500 rounded-full hover:bg-gray-700 transition hidden">
<i class="fas fa-shield-alt"></i>