`).join('');
}
function logEntry(ip, count) {
const timestamp = new Date().toLocaleString('en-US');
lookupLog.unshift({ timestamp, ip, count });
if (lookupLog.length > 50) lookupLog.pop(); // Limit log size
saveState();
renderLog();
}
function renderResults() {
ui.summaryIp.textContent = currentResults.ip;
ui.summaryCount.textContent = currentResults.domains.length;
ui.domainList.innerHTML = currentResults.domains.map(d => `
${escapeHTML(d)}
`).join('');
ui.resultsContainer.style.display = 'block';
}
function showMessage(message, isError = true) {
ui.errorMsg.textContent = message;
ui.errorMsg.style.display = 'block';
}
// --- API LOGIC ---
async function fetchReverseIp(ip) {
ui.loader.style.display = 'block';
ui.resultsContainer.style.display = 'none';
ui.errorMsg.style.display = 'none';
currentResults = { ip, domains: [] };
// Basic regex for IP validation
const ipRegex = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/;
if (!ipRegex.test(ip)) {
showMessage('Invalid IP address format. Please use xxx.xxx.xxx.xxx');
ui.loader.style.display = 'none';
return;
}
try {
// Using HackerTarget's free, CORS-enabled API
const response = await fetch(`https://api.hackertarget.com/reverseiplookup/?q=${encodeURIComponent(ip)}`);
if (!response.ok) {
throw new Error(`API request failed with status ${response.status}`);
}
const text = await response.text();
if (text.includes("error check your search parameter") || text.trim() === "") {
throw new Error("Invalid IP address or no domains found.");
}
const domains = text.split('\n').filter(d => d.trim() !== '');
currentResults.domains = domains;
renderResults();
logEntry(ip, domains.length);
} catch (error) {
console.error("Reverse IP Fetch Error:", error);
showMessage(error.message);
logEntry(ip, 'Error');
} finally {
ui.loader.style.display = 'none';
}
}
// --- EVENT HANDLERS & LOGIC ---
ui.form.addEventListener('submit', e => {
e.preventDefault();
const ip = ui.input.value.trim();
if (ip) {
fetchReverseIp(ip);
}
});
// --- PDF LOGIC ---
ui.downloadReportBtn.addEventListener('click', () => {
const { jsPDF } = window.jspdf;
if (!jsPDF || !window.jspdf.autoTable) { alert("PDF library not loaded!"); return; }
if (currentResults.domains.length === 0) {
alert("Please run a successful lookup before downloading.");
return;
}
const doc = new jsPDF();
doc.setFontSize(18);
doc.text(`Reverse IP Report for: ${currentResults.ip}`, 14, 22);
doc.setFontSize(12);
doc.text(`Total Domains Found: ${currentResults.domains.length}`, 14, 30);
doc.autoTable({
startY: 40,
head: [['Domain Name']],
body: currentResults.domains.map(d => [d]),
theme: 'striped',
headStyles: { fillColor: [0, 119, 182] } // var(--primary-color)
});
doc.save(`Reverse_IP_Report_${currentResults.ip}.pdf`);
});
ui.downloadLogBtn.addEventListener('click', () => {
const { jsPDF } = window.jspdf;
if (!jsPDF || !window.jspdf.autoTable) { alert("PDF library not loaded!"); return; }
if (lookupLog.length === 0) {
alert("Log is empty. Please perform a lookup first.");
return;
}
const doc = new jsPDF();
doc.setFontSize(18);
doc.text("Reverse IP Lookup Log", 14, 22);
doc.autoTable({
startY: 30,
head: [['Timestamp', 'IP Searched', 'Domains Found']],
body: lookupLog.map(log => [log.timestamp, log.ip, log.count]),
theme: 'striped',
headStyles: { fillColor: [0, 119, 182] }
});
doc.save("Reverse_IP_Log.pdf");
});
ui.clearLogBtn.addEventListener('click', () => {
lookupLog = [];
saveState();
renderLog();
});
// --- TABBING LOGIC ---
function switchTab(targetTabId) {
ui.tabContents.forEach(c => c.classList.remove('active'));
ui.tabButtons.forEach(b => b.classList.remove('active'));
document.getElementById(`rip-tab-${targetTabId}`).classList.add('active');
document.querySelector(`.rip-tab-button[data-tab="${targetTabId}"]`).classList.add('active');
}
function navigateTabs(dir) {
const tabs = Array.from(ui.tabButtons);
const active = tabs.find(t => t.classList.contains('active'));
let index = tabs.indexOf(active) + dir;
if (index < 0) index = 0; if (index >= tabs.length) index = tabs.length - 1;
switchTab(tabs[index].dataset.tab);
}
ui.tabButtons.forEach(button => button.addEventListener('click', () => switchTab(button.dataset.tab)));
ui.nextTabBtn.addEventListener('click', () => navigateTabs(1));
ui.prevTabBtn.addEventListener('click', () => navigateTabs(-1));
// --- UTILITY ---
function escapeHTML(str) { const p = document.createElement('p'); p.textContent = str; return p.innerHTML; }
// --- INITIALIZATION ---
loadState();
renderLog();
});