diff --git a/src/main/browser/profile-manager.ts b/src/main/browser/profile-manager.ts index 92634f1f..5638a766 100644 --- a/src/main/browser/profile-manager.ts +++ b/src/main/browser/profile-manager.ts @@ -1,10 +1,9 @@ -import { app, BrowserWindow, dialog, Session } from "electron"; +import { BrowserWindow, dialog, Session } from "electron"; import { getSession } from "@/browser/sessions"; import { TypedEventEmitter } from "@/modules/typed-event-emitter"; import { getProfile, getProfilePath, ProfileData } from "@/sessions/profiles"; import { BrowserEvents } from "@/browser/events"; import { Browser } from "@/browser/browser"; -import { FLAGS } from "@/modules/flags"; import { ElectronChromeExtensions } from "electron-chrome-extensions"; import { NEW_TAB_URL } from "@/browser/tabs/tab-manager"; import { ExtensionInstallStatus, installChromeWebStore } from "electron-chrome-web-store"; @@ -13,6 +12,7 @@ import { setWindowSpace } from "@/ipc/session/spaces"; import { registerWindow, WindowType } from "@/modules/windows"; import { getSettingValueById } from "@/saving/settings"; import { ExtensionManager } from "@/modules/extensions/management"; +import { transformUserAgentHeader } from "@/browser/utility/user-agent"; /** * Represents a loaded browser profile @@ -120,12 +120,11 @@ export class ProfileManager { const profilePath = getProfilePath(profileId); // Remove Electron and App details to closer emulate Chrome's UA - if (FLAGS.SCRUBBED_USER_AGENT) { - const userAgent = profileSession - .getUserAgent() - .replace(/\sElectron\/\S+/, "") - .replace(new RegExp(`\\s${app.getName()}/\\S+`, "i"), ""); - profileSession.setUserAgent(userAgent); + const oldUserAgent = profileSession.getUserAgent(); + const newUserAgent = transformUserAgentHeader(oldUserAgent, null); + + if (oldUserAgent !== newUserAgent) { + profileSession.setUserAgent(newUserAgent); } // Setup Extensions diff --git a/src/main/browser/utility/intercept-rules.ts b/src/main/browser/utility/intercept-rules.ts index c71613cc..4aa5c0df 100644 --- a/src/main/browser/utility/intercept-rules.ts +++ b/src/main/browser/utility/intercept-rules.ts @@ -4,8 +4,37 @@ import { generateID } from "@/modules/utils"; import { getSettingValueById } from "@/saving/settings"; import { Session } from "electron"; import { URL } from "url"; +import { transformUserAgentHeader } from "@/browser/utility/user-agent"; + +function setupUserAgentTransformer(session: Session) { + const webRequest = createBetterWebRequest(session.webRequest, "user-agent-transformer"); + + webRequest.onBeforeSendHeaders((details, callback) => { + let updated = false; + + const url = URL.parse(details.url); + + const requestHeaders = details.requestHeaders; + const newHeaders = { ...requestHeaders }; + for (const header of Object.keys(requestHeaders)) { + if (header.toLowerCase() == "user-agent") { + const oldValue = requestHeaders[header]; + const newValue = transformUserAgentHeader(oldValue, url); + if (oldValue !== newValue) { + newHeaders[header] = newValue; + updated = true; + } + } + } + + if (updated) { + callback({ requestHeaders: newHeaders }); + } else { + callback({}); + } + }); +} -// Bypass CORS for flow and flow-internal protocols function setupCorsBypassForFlowProtocols(session: Session) { const webRequest = createBetterWebRequest(session.webRequest, "bypass-cors"); @@ -36,7 +65,6 @@ function setupCorsBypassForFlowProtocols(session: Session) { }); } -// Setup redirects required for the better PDF viewer function setupBetterPdfViewer(session: Session) { const webRequest = createBetterWebRequest(session.webRequest, "better-pdf-viewer"); @@ -86,22 +114,13 @@ function setupBetterPdfViewer(session: Session) { callback({}); } ); - - // Update Origin header to requests - webRequest.onBeforeSendHeaders((details, callback) => { - const url = details.url; - const urlObject = URL.parse(url); - if (!urlObject) { - return callback({}); - } - - const newHeaders = { ...details.requestHeaders, Origin: urlObject.origin }; - callback({ requestHeaders: newHeaders }); - }); } // Setup intercept rules for the session export function setupInterceptRules(session: Session) { + // Transform the User-Agent header + setupUserAgentTransformer(session); + // Bypass CORS for flow and flow-internal protocols setupCorsBypassForFlowProtocols(session); diff --git a/src/main/browser/utility/user-agent.ts b/src/main/browser/utility/user-agent.ts new file mode 100644 index 00000000..2d8482db --- /dev/null +++ b/src/main/browser/utility/user-agent.ts @@ -0,0 +1,44 @@ +import { FLAGS } from "@/modules/flags"; +import { app } from "electron"; + +const EDGE_USER_AGENT = "Edg/136.0.3240.76"; + +export function transformUserAgentHeader(userAgent: string, url: URL | null) { + if (!FLAGS.SCRUBBED_USER_AGENT) { + return userAgent; + } + + // Edge User Agent: + // - Causes a few issues with Google Auth + const addEdgeUserAgent = false; + + // Remove Electron User Agent: + // - Causes issues with Spotify + const removeElectronUserAgent = true; + + // Remove App User Agent: + // - Flow will be less identifiable + const removeAppUserAgent = false; + + if (url) { + // const hostname = url.hostname.toLowerCase(); + // if (hostname === "accounts.google.com") { + // } + } + + if (removeElectronUserAgent) { + userAgent = userAgent.replace(/\sElectron\/\S+/, ""); + } + + if (removeAppUserAgent) { + const appName = app.getName(); + userAgent = userAgent.replace(new RegExp(`\\s${appName}/\\S+`, "i"), ""); + } + + const hasEdgeUserAgent = userAgent.includes(EDGE_USER_AGENT); + if (addEdgeUserAgent && !hasEdgeUserAgent) { + userAgent = `${userAgent} ${EDGE_USER_AGENT}`; + } + + return userAgent; +} diff --git a/src/main/modules/flags.ts b/src/main/modules/flags.ts index 20f3f1a0..4d161717 100644 --- a/src/main/modules/flags.ts +++ b/src/main/modules/flags.ts @@ -14,9 +14,8 @@ type Flags = { }; export const FLAGS: Flags = { - // Disabled, because it causes cloudflare turnstile to flag us. - // It also causes Google to flag us as a bot, which stops us from logging in to Google. - SCRUBBED_USER_AGENT: false, + // Transform the user agent + SCRUBBED_USER_AGENT: true, // Replace - Use window.location.replace to load the error page. // Load - Add the page to the history stack by loading it normally.