let allResults = []; let filteredResults = []; let selectedFilters = { countries: new Set(), asns: new Set(), owners: new Set() }; // Theme Management function toggleTheme() { const html = document.documentElement; const currentTheme = html.getAttribute('data-bs-theme'); const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; html.setAttribute('data-bs-theme', newTheme); localStorage.setItem('theme', newTheme); const icon = document.getElementById('themeIcon'); if (icon) { icon.className = newTheme === 'dark' ? 'fas fa-moon' : 'fas fa-sun'; } } // Load saved theme window.addEventListener('DOMContentLoaded', () => { const savedTheme = localStorage.getItem('theme') || 'dark'; document.documentElement.setAttribute('data-bs-theme', savedTheme); const icon = document.getElementById('themeIcon'); if (icon) { icon.className = savedTheme === 'dark' ? 'fas fa-moon' : 'fas fa-sun'; } }); // Main Analysis Function async function analyzeIPs() { const input = document.getElementById('ipInput').value; const loading = document.getElementById('loading'); const results = document.getElementById('results'); const error = document.getElementById('error'); if (!input.trim()) { showError('⚠️ Please paste a list of IP addresses'); return; } error.classList.add('d-none'); results.classList.add('d-none'); loading.classList.remove('d-none'); try { const response = await fetch('/api/analyze', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ ips: input }) }); if (!response.ok) { throw new Error('Analysis failed - check connection'); } const data = await response.json(); allResults = data.results; filteredResults = [...allResults]; displayResults(data); } catch (e) { showError('❌ ' + e.message); } finally { loading.classList.add('d-none'); } } // Display Results function displayResults(data) { displayStats(data.stats); displayFilters(data.stats); displayTable(filteredResults); const resultsDiv = document.getElementById('results'); resultsDiv.classList.remove('d-none'); resultsDiv.scrollIntoView({ behavior: 'smooth' }); } // Display Statistics function displayStats(stats) { const statsDiv = document.getElementById('stats'); statsDiv.innerHTML = `
Countries

${Object.keys(stats.countries).length}

ASNs

${Object.keys(stats.asns).length}

IP Addresses

${allResults.length}

`; } // Display Filters function displayFilters(stats) { // Countries (top 15) const countries = Object.entries(stats.countries) .sort((a, b) => b[1] - a[1]) .slice(0, 15); document.getElementById('countryFilters').innerHTML = countries.map(([country, count]) => ` ${country} (${count}) ` ).join(''); // ASNs (top 15) const asns = Object.entries(stats.asns) .sort((a, b) => b[1] - a[1]) .slice(0, 15); document.getElementById('asnFilters').innerHTML = asns.map(([asn, count]) => ` ${asn} (${count}) ` ).join(''); // Owners (top 15) const owners = Object.entries(stats.owners) .sort((a, b) => b[1] - a[1]) .slice(0, 15); document.getElementById('ownerFilters').innerHTML = owners.map(([owner, count]) => { const shortOwner = owner.length > 30 ? owner.substring(0, 30) + '...' : owner; return ` ${shortOwner} (${count}) `; }).join(''); } // Toggle Filter function toggleFilter(type, value) { if (selectedFilters[type].has(value)) { selectedFilters[type].delete(value); } else { selectedFilters[type].add(value); } document.querySelectorAll(`[data-type="${type}"][data-value="${value}"]`).forEach(chip => { chip.classList.toggle('active'); }); applyFilters(); } // Clear All Filters function clearFilters() { selectedFilters = { countries: new Set(), asns: new Set(), owners: new Set() }; document.querySelectorAll('.filter-chip').forEach(chip => chip.classList.remove('active')); applyFilters(); } // Apply Filters function applyFilters() { const hasFilters = selectedFilters.countries.size > 0 || selectedFilters.asns.size > 0 || selectedFilters.owners.size > 0; if (!hasFilters) { filteredResults = [...allResults]; } else { filteredResults = allResults.filter(item => { return (selectedFilters.countries.size === 0 || selectedFilters.countries.has(item.country)) && (selectedFilters.asns.size === 0 || selectedFilters.asns.has(item.asn)) && (selectedFilters.owners.size === 0 || selectedFilters.owners.has(item.owner)); }); } displayTable(filteredResults); updateFilterCount(); } // Update Filter Count function updateFilterCount() { const total = selectedFilters.countries.size + selectedFilters.asns.size + selectedFilters.owners.size; const countEl = document.getElementById('filterCount'); if (countEl) { countEl.textContent = total > 0 ? `Active filters: ${total} | Results: ${filteredResults.length}/${allResults.length}` : ''; } } // Display Table function displayTable(results) { const tbody = document.getElementById('tableBody'); if (!tbody) return; tbody.innerHTML = results.map((item, idx) => ` ${item.ip} ${item.asn} ${escapeHtml(item.owner)} ${item.country} ${item.network} `).join(''); document.getElementById('tableCount').textContent = results.length; } // Toggle All Checkboxes function toggleAll() { const checked = document.getElementById('selectAll').checked; document.querySelectorAll('.ip-checkbox').forEach(cb => cb.checked = checked); } // Get Selected IPs function getSelectedIPs() { const checkboxes = document.querySelectorAll('#tableBody input[type="checkbox"]:checked'); return Array.from(checkboxes).map(cb => cb.closest('tr').querySelector('.ip-cell').textContent ); } // Show Export Output function showExport(title, code) { document.getElementById('exportTitle').textContent = title; document.getElementById('exportCode').textContent = code; const output = document.getElementById('exportOutput'); output.classList.remove('d-none'); output.scrollIntoView({ behavior: 'smooth' }); } // Export Functions async function exportIPSet() { const ips = getSelectedIPs(); if (ips.length === 0) { showError('Please select at least one IP address'); return; } const response = await fetch('/api/export/ipset', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ ips: ips, timeout: 86400 }) }); const code = await response.text(); showExport('IPSet Rules', code); } async function exportIPTables() { const ips = getSelectedIPs(); if (ips.length === 0) return; const response = await fetch('/api/export/iptables', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ ips: ips }) }); const code = await response.text(); showExport('iptables Rules', code); } async function exportNginx() { const ips = getSelectedIPs(); if (ips.length === 0) return; const response = await fetch('/api/export/nginx', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ ips: ips }) }); const code = await response.text(); showExport('Nginx Configuration', code); } async function exportApache() { const ips = getSelectedIPs(); if (ips.length === 0) return; const response = await fetch('/api/export/apache', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ ips: ips }) }); const code = await response.text(); showExport('Apache Configuration', code); } async function exportFirewalld() { const ips = getSelectedIPs(); if (ips.length === 0) return; const response = await fetch('/api/export/firewalld', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ ips: ips }) }); const code = await response.text(); showExport('Firewalld Rules', code); } async function exportMikrotik() { const ips = getSelectedIPs(); if (ips.length === 0) return; const response = await fetch('/api/export/mikrotik', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ ips: ips }) }); const code = await response.text(); showExport('MikroTik Configuration', code); } async function exportCIDR() { const response = await fetch('/api/export/cidr', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ results: filteredResults }) }); const code = await response.text(); showExport('CIDR Network List', code); } async function exportCSV() { const response = await fetch('/api/export/csv', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ results: filteredResults }) }); const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `ip-analysis-${new Date().toISOString().split('T')[0]}.csv`; a.click(); } // Copy to Clipboard function copyToClipboard() { const code = document.getElementById('exportCode').textContent; navigator.clipboard.writeText(code).then(() => { const btn = event.target.closest('button'); const originalHTML = btn.innerHTML; btn.innerHTML = ' Copied!'; btn.classList.add('btn-success'); btn.classList.remove('btn-secondary'); setTimeout(() => { btn.innerHTML = originalHTML; btn.classList.remove('btn-success'); btn.classList.add('btn-secondary'); }, 2000); }).catch(err => { showError('Failed to copy: ' + err); }); } // Utility Functions function showError(message) { const error = document.getElementById('error'); if (error) { error.textContent = message; error.classList.remove('d-none'); setTimeout(() => error.classList.add('d-none'), 5000); } } function escapeHtml(text) { const map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; return String(text).replace(/[&<>"']/g, m => map[m]); } // Keyboard Shortcuts document.addEventListener('keydown', (e) => { if (e.ctrlKey && e.key === 'Enter' && document.getElementById('ipInput')) { analyzeIPs(); } }); // Smooth scroll for anchor links document.addEventListener('DOMContentLoaded', () => { document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function (e) { e.preventDefault(); const target = document.querySelector(this.getAttribute('href')); if (target) { target.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }); }); });