diff --git a/main.js b/main.js index b5de314..3102000 100644 --- a/main.js +++ b/main.js @@ -82,29 +82,33 @@ function createWindow(startUrl) { const win = new BrowserWindow(windowOptions); - // Handle window.open() calls – load URL in this window + // Allow window.open() popups (e.g. OAuth / SSO / school portals) so that + // POST form submissions and opener relationships are preserved. + // We still restrict to http/https for safety; everything else is denied. win.webContents.setWindowOpenHandler(({ url }) => { - win.loadURL(url); + if (url.startsWith('http://') || url.startsWith('https://')) { + return { action: 'allow' }; + } return { action: 'deny' }; }); - // Intercept direct navigations (e.g., user clicks a link) – load URL in this window - win.webContents.on('will-navigate', (event, url) => { - event.preventDefault(); // Prevent navigation in the current window - win.loadURL(url); - }); + // IMPORTANT: Do NOT intercept 'will-navigate' with preventDefault() because + // that strips POST bodies (turning logins into GET requests). Let Chromium + // perform the navigation normally. If you need to observe navigations, add + // a listener without calling preventDefault(). + // (Previous code here was causing login forms to fail.) - // Intercept legacy new-window events – load URL in this window - win.webContents.on('new-window', (event, url) => { - event.preventDefault(); // Prevent new Electron window - win.loadURL(url); - }); + // Remove deprecated 'new-window' handler that forcibly loaded targets in the + // same window; this also broke some auth popup flows. setWindowOpenHandler + // above now governs popup behavior. // ensure all embedded tags behave predictably without heavy injections win.webContents.on('did-attach-webview', (event, webContents) => { - // Let the renderer/webview handle navigation; avoid extra JS injection that can stall + // Allow popups inside as well (required for some login flows) webContents.setWindowOpenHandler(({ url }) => { - webContents.loadURL(url); + if (url.startsWith('http://') || url.startsWith('https://')) { + return { action: 'allow' }; + } return { action: 'deny' }; }); }); @@ -162,8 +166,17 @@ app.whenReady().then(async () => { } }); - // Configure user agent for better compatibility - ses.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Nebula/1.0.0'); + // Configure user agent for better compatibility: + // Previously this forced Chrome/120 which is stale and can cause anti-bot / Cloudflare challenges + // to fail due to UA / feature mismatch fingerprinting. Use the real Chromium UA then append branding. + try { + const realUA = ses.getUserAgent(); + if (realUA && !realUA.includes('Nebula/')) { + ses.setUserAgent(realUA + ' Nebula/1.0.0'); + } + } catch (e) { + console.warn('Failed to read real user agent, keeping default:', e); + } // Configure cookies for OAuth compatibility ses.cookies.on('changed', (event, cookie, cause, removed) => { @@ -175,11 +188,17 @@ app.whenReady().then(async () => { // Optional: add headers only for OAuth flows; avoid forcing cache headers globally ses.webRequest.onBeforeSendHeaders((details, callback) => { + const headers = details.requestHeaders; + // Add richer headers for sensitive flows (OAuth / login) to look like a real browser if (details.url.includes('accounts.google.com') || details.url.includes('oauth')) { - details.requestHeaders['Referrer-Policy'] = 'strict-origin-when-cross-origin'; - details.requestHeaders['Accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'; + headers['Referrer-Policy'] = 'strict-origin-when-cross-origin'; + headers['Accept'] = headers['Accept'] || 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'; } - callback({ requestHeaders: details.requestHeaders }); + // Ensure Accept-Language is present (Cloudflare & some WAFs use this in heuristics) + if (!headers['Accept-Language'] && !headers['accept-language']) { + headers['Accept-Language'] = 'en-US,en;q=0.9'; + } + callback({ requestHeaders: headers }); }); } console.log('Session configured successfully for OAuth compatibility'); diff --git a/renderer/script.js b/renderer/script.js index 92fbe76..7c4dec6 100644 --- a/renderer/script.js +++ b/renderer/script.js @@ -170,7 +170,12 @@ function createTab(inputUrl) { webview.setAttribute('preload', '../preload.js'); // Add attributes needed for Google OAuth and sign-in flows webview.setAttribute('webpreferences', 'allowRunningInsecureContent=false,javascript=true,webSecurity=true'); - webview.setAttribute('useragent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Nebula/1.0.0'); + try { + const baseUA = navigator.userAgent.includes('Nebula/') ? navigator.userAgent : navigator.userAgent + ' Nebula/1.0.0'; + webview.setAttribute('useragent', baseUA); + } catch { + // fallback: let Electron supply default UA + } webview.addEventListener('page-favicon-updated', e => { if (e.favicons.length > 0) updateTabMetadata(id, 'favicon', e.favicons[0]); @@ -194,6 +199,9 @@ function createTab(inputUrl) { webview.addEventListener('did-navigate', e => { handleNavigation(id, e.url); if (e.url.startsWith('http')) debug('[DEBUG] Recording navigation to:', e.url); + if (/\/cdn-cgi\//.test(e.url) || /challenge/i.test(e.url)) { + console.log('[Nebula] Cloudflare challenge detected at', e.url); + } }); webview.addEventListener('did-navigate-in-page', e => { @@ -208,8 +216,18 @@ function createTab(inputUrl) { // catch any target="_blank" or window.open() calls and open them as new tabs webview.addEventListener('new-window', e => { - e.preventDefault(); - createTab(e.url); + // Allow auth / SSO popup windows (don't preventDefault) when target is http(s) + // so form POST + redirect chains stay intact. For simple links attempting to + // open a new tab, we create an in-app tab instead. Heuristic: if disposition + // is 'foreground-tab' or 'background-tab', treat as tab; otherwise allow popup. + if (e.url && (e.url.startsWith('http://') || e.url.startsWith('https://'))) { + if (e.disposition && e.disposition.includes('tab')) { + e.preventDefault(); + createTab(e.url); + } // else let Electron create a real popup window + } else { + e.preventDefault(); + } }); // After creating dynamic webview: @@ -332,7 +350,10 @@ function convertHomeTabToWebview(tabId, inputUrl, resolvedUrl) { webview.setAttribute('preload', '../preload.js'); // Add attributes needed for Google OAuth and sign-in flows webview.setAttribute('webpreferences', 'allowRunningInsecureContent=false,javascript=true,webSecurity=true'); - webview.setAttribute('useragent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Nebula/1.0.0'); + try { + const baseUA2 = navigator.userAgent.includes('Nebula/') ? navigator.userAgent : navigator.userAgent + ' Nebula/1.0.0'; + webview.setAttribute('useragent', baseUA2); + } catch {} // Add event listeners webview.addEventListener('did-fail-load', handleLoadFail(tabId)); @@ -343,6 +364,9 @@ function convertHomeTabToWebview(tabId, inputUrl, resolvedUrl) { webview.addEventListener('did-navigate', e => { handleNavigation(tabId, e.url); + if (/\/cdn-cgi\//.test(e.url) || /challenge/i.test(e.url)) { + console.log('[Nebula] Cloudflare challenge detected at', e.url); + } }); webview.addEventListener('did-navigate-in-page', e => { handleNavigation(tabId, e.url); @@ -352,7 +376,15 @@ function convertHomeTabToWebview(tabId, inputUrl, resolvedUrl) { }); webview.addEventListener('new-window', e => { - createTab(e.url); + if (e.url && (e.url.startsWith('http://') || e.url.startsWith('https://'))) { + if (e.disposition && e.disposition.includes('tab')) { + e.preventDefault(); + createTab(e.url); + } + // otherwise allow popup for auth + } else { + e.preventDefault(); + } }); // After creating dynamic webview: diff --git a/site-history.json b/site-history.json index 46ab1e1..c44dc44 100644 --- a/site-history.json +++ b/site-history.json @@ -1,8 +1,3 @@ [ - "https://nebula.zambazosmedia.group/roadmap.html", - "https://nebula.zambazosmedia.group/index.html", - "https://nebula.zambazosmedia.group/wiki/index.html", - "https://nebula.zambazosmedia.group/", - "https://github.com/Bobbybear007/NebulaBrowser", - "https://www.youtube.com/" + ] \ No newline at end of file