// browser-nav.js - Injected into NOSE apps to get the UI browser working. (function () { const ALLOWED_DOMAINS = ['localhost', '.local', '.nose.space'] function isAllowedOrigin(url) { try { const urlObj = new URL(url, window.location.href) return ALLOWED_DOMAINS.some(domain => urlObj.hostname === domain || urlObj.hostname.endsWith(domain) ) } catch { return false } } // Intercept navigation attempts function interceptNavigation(e) { const target = e.target.closest('a') if (!target || !target.href) return // Allow relative URLs and hash links if (target.getAttribute('href').startsWith('#')) return if (target.getAttribute('href').startsWith('/')) return // Check if external if (!isAllowedOrigin(target.href)) { e.preventDefault() if (window.parent !== window) { window.parent.postMessage({ type: 'NAV_BLOCKED', data: { url: target.href, reason: 'External domain not allowed' } }, '*') } else { alert('Navigation to external sites is not allowed') } } } // Listen for clicks on links document.addEventListener('click', interceptNavigation, true) // Intercept programmatic navigation const originalPushState = history.pushState const originalReplaceState = history.replaceState history.pushState = function (state, title, url) { if (url && !isAllowedOrigin(url)) { if (window.parent !== window) { window.parent.postMessage({ type: 'NAV_BLOCKED', data: { url, reason: 'External domain not allowed' } }, '*') } return } return originalPushState.apply(this, arguments) } history.replaceState = function (state, title, url) { if (url && !isAllowedOrigin(url)) { if (window.parent !== window) { window.parent.postMessage({ type: 'NAV_BLOCKED', data: { url, reason: 'External domain not allowed' } }, '*') } return } return originalReplaceState.apply(this, arguments) } // Listen for navigation commands from parent window.addEventListener('message', (event) => { console.log(event) if (event.data.type === 'NAV_COMMAND') { switch (event.data.action) { case 'back': history.back(); break case 'forward': history.forward(); break case 'reload': window.location.reload(); break case 'stop': window.stop(); break } } }) if (window.parent !== window) { window.parent.postMessage({ type: 'NAV_READY' }, '*') window.addEventListener('popstate', () => { window.parent.postMessage({ type: 'URL_CHANGED', data: { url: location.href } }, '*') }) } })()