// Tab switching functionality
document.addEventListener('DOMContentLoaded', function() {
const tabButtons = document.querySelectorAll('.tab-button');
const tabContents = document.querySelectorAll('.tab-content');
tabButtons.forEach(button => {
button.addEventListener('click', () => {
const targetTab = button.getAttribute('data-tab');
// Remove active class from all buttons and contents
tabButtons.forEach(btn => btn.classList.remove('active'));
tabContents.forEach(content => content.classList.remove('active'));
// Add active class to clicked button and corresponding content
button.classList.add('active');
document.getElementById(`${targetTab}-tab`).classList.add('active');
// Load analytics data when analytics tab is clicked
if (targetTab === 'analytics') {
loadAnalyticsData();
}
});
});
// Analytics functionality
function loadAnalyticsData() {
const loading = document.getElementById('analytics-loading');
const chartCanvas = document.getElementById('analytics-chart');
if (!loading || !chartCanvas) {
console.error('Analytics elements not found');
return;
}
// Show loading
loading.classList.remove('hidden');
// Fetch analytics data from backend
fetch('/api/analytics-data')
.then(response => response.json())
.then(data => {
loading.classList.add('hidden');
if (data.error) {
console.error('Error loading analytics data:', data.error);
return;
}
// Create Chart.js chart
const ctx = chartCanvas.getContext('2d');
new Chart(ctx, {
type: 'line',
data: {
labels: data.labels,
datasets: [
{
label: 'Anonymity Score (%)',
data: data.anonymityScores,
borderColor: 'rgba(75, 192, 192, 1)',
backgroundColor: 'rgba(75, 192, 192, 0.2)',
yAxisID: 'y',
tension: 0.1
},
{
label: 'Threat Level (%)',
data: data.threatLevels,
borderColor: 'rgba(255, 99, 132, 1)',
backgroundColor: 'rgba(255, 99, 132, 0.2)',
yAxisID: 'y1',
tension: 0.1
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
type: 'linear',
display: true,
position: 'left',
title: {
display: true,
text: 'Anonymity Score (%)'
},
min: 0,
max: 100
},
y1: {
type: 'linear',
display: true,
position: 'right',
title: {
display: true,
text: 'Threat Level (%)'
},
min: 0,
max: 100,
grid: {
drawOnChartArea: false,
},
}
},
plugins: {
title: {
display: true,
text: 'IP Analysis Trends Over Time'
},
legend: {
display: true,
position: 'top'
}
}
}
});
})
.catch(error => {
loading.classList.add('hidden');
console.error('Error fetching analytics data:', error);
});
}
// IP check functionality
const ipInput = document.getElementById('ip-input');
const checkBtn = document.getElementById('check-btn');
const loading = document.getElementById('loading');
const results = document.getElementById('results');
// IP Purity Scanner functionality
const purityIpInput = document.getElementById('purity-ip-input');
const purityCheckBtn = document.getElementById('purity-check-btn');
const purityLoading = document.getElementById('purity-loading');
const purityResults = document.getElementById('purity-results');
// Only allow numbers and dots in IP input
ipInput.addEventListener('input', (e) => {
// Remove any characters that are not numbers or dots
e.target.value = e.target.value.replace(/[^0-9.]/g, '');
});
// Only allow numbers and dots in purity IP input
purityIpInput.addEventListener('input', (e) => {
// Remove any characters that are not numbers or dots
e.target.value = e.target.value.replace(/[^0-9.]/g, '');
});
// Prevent non-numeric and non-dot characters on keypress
ipInput.addEventListener('keydown', (e) => {
// Allow: backspace, delete, tab, escape, enter
if (['Backspace', 'Delete', 'Tab', 'Escape', 'Enter'].includes(e.key)) {
return;
}
// Allow: Ctrl+A, Ctrl+C, Ctrl+V, Ctrl+X
if ((e.ctrlKey || e.metaKey) && ['a', 'c', 'v', 'x'].includes(e.key.toLowerCase())) {
return;
}
// Allow: Arrow keys, Home, End
if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End'].includes(e.key)) {
return;
}
// Allow only numbers (0-9) and dot (.)
if (!/^[0-9.]$/.test(e.key)) {
e.preventDefault();
}
});
// Allow Enter key to trigger check
ipInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
checkIP();
}
});
checkBtn.addEventListener('click', checkIP);
// Allow Enter key to trigger purity check
purityIpInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
checkPurity();
}
});
purityCheckBtn.addEventListener('click', checkPurity);
function checkIP() {
const ip = ipInput.value.trim();
if (!ip) {
showError('Please enter an IP address');
return;
}
// Basic IP validation
const ipRegex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
if (!ipRegex.test(ip)) {
showError('Please enter a valid IP address');
return;
}
// Show loading, hide results
loading.classList.remove('hidden');
results.classList.add('hidden');
results.innerHTML = '';
// Call backend API
fetch('/api/check-ip', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ ip: ip })
})
.then(response => response.json())
.then(data => {
loading.classList.add('hidden');
if (data.error) {
showError(data.error);
} else {
displayResults(data);
}
})
.catch(error => {
loading.classList.add('hidden');
showError('Error connecting to server. Please try again.');
console.error('Error:', error);
});
}
function showError(message) {
results.classList.remove('hidden');
results.innerHTML = `
${message}
`;
}
function displayResults(data) {
// Ensure abuseConfidencePercentage is a number
let abuseConfidence = data.abuseConfidencePercentage !== undefined && data.abuseConfidencePercentage !== null
? Number(data.abuseConfidencePercentage)
: 0;
// Handle NaN or invalid numbers
if (isNaN(abuseConfidence) || abuseConfidence < 0) {
abuseConfidence = 0;
}
let statusClass = 'status-safe';
let statusText = 'Safe';
if (abuseConfidence >= 75) {
statusClass = 'status-danger';
statusText = 'High Risk';
} else if (abuseConfidence >= 25) {
statusClass = 'status-warning';
statusText = 'Medium Risk';
}
const usageTypes = data.usageType || 'Unknown';
const isp = data.isp || 'Unknown';
const domain = data.domain || 'Unknown';
const country = data.countryName || 'Unknown';
// Ensure totalReports is a number
let reports = data.totalReports !== undefined && data.totalReports !== null
? Number(data.totalReports)
: 0;
// Handle NaN or invalid numbers
if (isNaN(reports) || reports < 0) {
reports = 0;
}
const lastReported = data.lastReportedAt || 'Never';
results.classList.remove('hidden');
results.innerHTML = `
Threat Level
${abuseConfidence.toFixed(0)}%
Last Reported
${formatDate(lastReported)}
`;
}
function formatDate(dateString) {
if (!dateString || dateString === 'Never') {
return 'Never';
}
try {
const date = new Date(dateString);
return date.toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
} catch (e) {
return dateString;
}
}
// Load last reported IPs
function loadLastReports(showLoading = true) {
const loading = document.getElementById('last-report-loading');
const results = document.getElementById('last-report-results');
// Check if elements exist before trying to use them
if (!loading || !results) {
return;
}
if (showLoading) {
loading.classList.remove('hidden');
results.innerHTML = '';
}
fetch('/api/last-reports')
.then(response => response.json())
.then(data => {
if (showLoading) {
loading.classList.add('hidden');
}
if (data.error) {
results.innerHTML = `
${data.error}
`;
} else if (data.ips && data.ips.length > 0) {
displayLastReports(data.ips);
} else {
results.innerHTML = `
No reported IPs found.
`;
}
})
.catch(error => {
if (showLoading) {
loading.classList.add('hidden');
}
results.innerHTML = `
Error loading reported IPs. Please try again.
`;
console.error('Error:', error);
});
}
function displayLastReports(ips) {
const results = document.getElementById('last-report-results');
if (!results) return;
const ipsHTML = ips.map((ipData, index) => {
const abuseConfidence = ipData.abuseConfidencePercentage || 0;
let statusClass = 'status-safe';
let statusText = 'Safe';
if (abuseConfidence >= 75) {
statusClass = 'status-danger';
statusText = 'High Risk';
} else if (abuseConfidence >= 25) {
statusClass = 'status-warning';
statusText = 'Medium Risk';
}
return `
Threat Level
${abuseConfidence.toFixed(0)}%
Total Reports
${ipData.totalReports || 0}
Country
${ipData.countryName || 'Unknown'}
ISP
${ipData.isp || 'Unknown'}
Usage Type
${ipData.usageType || 'Unknown'}
Domain
${ipData.domain || 'Unknown'}
Distinct Users
${ipData.numDistinctUsers || 0}
Last Reported
${formatDate(ipData.lastReportedAt)}
`;
}).join('');
results.innerHTML = ipsHTML;
}
// Report IP functionality
const reportIpInput = document.getElementById('report-ip-input');
const reportCategory = document.getElementById('report-category');
const reportComment = document.getElementById('report-comment');
const submitReportBtn = document.getElementById('submit-report-btn');
const reportLoading = document.getElementById('report-loading');
const reportMessage = document.getElementById('report-message');
// Only add event listeners if elements exist
if (reportIpInput) {
reportIpInput.addEventListener('input', (e) => {
e.target.value = e.target.value.replace(/[^0-9.]/g, '');
});
reportIpInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter' && reportCategory.value) {
submitReport();
}
});
}
if (submitReportBtn) {
submitReportBtn.addEventListener('click', submitReport);
}
function submitReport() {
if (!reportIpInput || !reportCategory || !reportComment || !reportLoading || !reportMessage) {
console.error('Report elements not found');
return;
}
const ip = reportIpInput.value.trim();
const category = reportCategory.value;
const comment = reportComment.value.trim();
if (!ip) {
showReportMessage('Please enter an IP address', 'error');
return;
}
// Basic IP validation
const ipRegex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
if (!ipRegex.test(ip)) {
showReportMessage('Please enter a valid IP address', 'error');
return;
}
if (!category) {
showReportMessage('Please select a category', 'error');
return;
}
// Show loading
reportLoading.classList.remove('hidden');
reportMessage.classList.add('hidden');
// Call backend API
fetch('/api/report-ip', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
ip: ip,
category: category,
comment: comment
})
})
.then(response => response.json())
.then(data => {
reportLoading.classList.add('hidden');
if (data.error) {
showReportMessage(data.error, 'error');
} else {
showReportMessage('Report submitted successfully! Thank you for your contribution.', 'success');
// Clear form
reportIpInput.value = '';
reportCategory.value = '';
reportComment.value = '';
}
})
.catch(error => {
reportLoading.classList.add('hidden');
showReportMessage('Error submitting report. Please try again.', 'error');
console.error('Error:', error);
});
}
function showReportMessage(message, type) {
if (!reportMessage) return;
reportMessage.classList.remove('hidden');
reportMessage.className = 'report-message hidden';
reportMessage.classList.add(type === 'success' ? 'success' : 'error');
reportMessage.classList.remove('hidden');
reportMessage.innerHTML = message;
}
// IP Purity Scanner functions
function checkPurity() {
const ip = purityIpInput.value.trim();
if (!ip) {
showPurityError('Please enter an IP address');
return;
}
// Basic IP validation
const ipRegex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
if (!ipRegex.test(ip)) {
showPurityError('Please enter a valid IP address');
return;
}
// Show loading, hide results
purityLoading.classList.remove('hidden');
purityResults.classList.add('hidden');
purityResults.innerHTML = '';
// Call backend API
fetch('/api/purity-check', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ ip: ip })
})
.then(response => response.json())
.then(data => {
purityLoading.classList.add('hidden');
if (data.error) {
showPurityError(data.error);
} else {
displayPurityResults(data);
}
})
.catch(error => {
purityLoading.classList.add('hidden');
showPurityError('Error connecting to server. Please try again.');
console.error('Error:', error);
});
}
function showPurityError(message) {
purityResults.classList.remove('hidden');
purityResults.innerHTML = `
${message}
`;
}
function displayPurityResults(data) {
// Ensure anonymityScore is a number
let anonymityScore = data.anonymityScore !== undefined && data.anonymityScore !== null
? Number(data.anonymityScore)
: 0;
// Handle NaN or invalid numbers
if (isNaN(anonymityScore) || anonymityScore < 0) {
anonymityScore = 0;
}
if (anonymityScore > 100) {
anonymityScore = 100;
}
// Ensure abuseConfidencePercentage is a number
let abuseConfidence = data.abuseConfidencePercentage !== undefined && data.abuseConfidencePercentage !== null
? Number(data.abuseConfidencePercentage)
: 0;
// Handle NaN or invalid numbers
if (isNaN(abuseConfidence) || abuseConfidence < 0) {
abuseConfidence = 0;
}
let statusClass = 'status-safe';
let statusText = 'Safe';
if (abuseConfidence >= 75) {
statusClass = 'status-danger';
statusText = 'High Risk';
} else if (abuseConfidence >= 25) {
statusClass = 'status-warning';
statusText = 'Medium Risk';
}
const proxy = data.proxy || 'No';
const vpn = data.vpn || 'No';
const tor = data.tor || 'No';
const country = data.countryName || 'Unknown';
const isp = data.isp || 'Unknown';
purityResults.classList.remove('hidden');
purityResults.innerHTML = `
Anonymity Score
${anonymityScore.toFixed(0)}%
Threat Level
${abuseConfidence.toFixed(0)}%
`;
}
});