/** * OSINT Suite - Shared Navigation Bar * Reads from apps.json for single source of truth * Include with: */ (function() { const APPS_JSON = 'https://assets.tools.ejfox.com/apps.json'; const currentHost = window.location.hostname; const currentApp = currentHost.split('.')[0]; // Inject favicon if not present if (!document.querySelector('link[rel="icon"]')) { const link = document.createElement('link'); link.rel = 'icon'; link.type = 'image/svg+xml'; link.href = 'https://assets.tools.ejfox.com/favicon.svg'; document.head.appendChild(link); } // Zulu time helpers const zulu = () => new Date().toISOString().slice(11, 16).replace(':', '') + 'Z'; const zuluFull = () => new Date().toISOString().slice(11, 19).replace(/:/g, '') + 'Z'; // Session ID (persistent per tab) const sessionId = sessionStorage.getItem('osint-session') || (() => { const id = Date.now().toString(16).slice(-6).toUpperCase() + '-' + Math.random().toString(16).slice(2, 6).toUpperCase(); sessionStorage.setItem('osint-session', id); return id; })(); fetch(APPS_JSON) .then(r => r.json()) .then(data => { const domain = data.domain; const navCategories = data.categories.filter(c => c.nav); const nav = document.createElement('nav'); nav.id = 'osint-nav'; nav.innerHTML = ` OSINT ${navCategories.map(cat => ` `).join('')} `; // Insert at top of body if (document.body.firstChild) { document.body.insertBefore(nav, document.body.firstChild); } else { document.body.appendChild(nav); } // Update Zulu time every 10 seconds setInterval(() => { const el = document.getElementById('nav-zulu'); if (el) el.textContent = zulu(); }, 10000); }) .catch(e => console.warn('nav.js: failed to load apps.json', e)); })();