null_0_1 / index.html
Dapshen's picture
Add 3 files
a83a357 verified
<!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>