fix: whitelist Google/OAuth domains in adblock, spoof Sec-CH-UA brand

Two-part fix for Google login "Возможно, этот браузер небезопасны" error:

1. The adblocker was eating Google integrity-check resources (gstatic,
   google-analytics, googletagmanager — flagged by EasyPrivacy). Add @@
   whitelist filters for Google, Yandex, Microsoft, Apple, Facebook,
   GitHub, VK, Mail.ru ecosystems. Also switch from non-existent
   addFilters() to updateFromDiff({added}) — previous TMDB whitelist was
   silently failing in a then().catch() and never applied. Adblock cache
   bumped to v3 so the new filters take effect.
2. Sec-CH-UA client-hints branding was leaking Electron app name as the
   browser brand. Override sec-ch-ua, sec-ch-ua-mobile, sec-ch-ua-platform
   headers via webRequest.onBeforeSendHeaders on all 3 sessions so
   embedded-browser detectors see real-Chrome brand list.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-16 20:54:35 +03:00
parent a171f62629
commit 542be8135a
2 changed files with 52 additions and 17 deletions

67
main.js
View File

@@ -7,7 +7,7 @@ const { ElectronBlocker, adsAndTrackingLists } = require('@cliqz/adblocker-elect
const { autoUpdater } = require('electron-updater');
const CONFIG_PATH = path.join(os.homedir(), '.ESH-Media.json');
const BLOCKER_CACHE_PATH = path.join(os.homedir(), '.ESH-Media-adblock-v2.bin');
const BLOCKER_CACHE_PATH = path.join(os.homedir(), '.ESH-Media-adblock-v3.bin');
const DEFAULT_TRUSTED_DOMAINS = [
// Google ecosystem (OAuth)
'google.com', 'accounts.google.com', 'googleapis.com', 'googleusercontent.com',
@@ -72,8 +72,26 @@ function getBlocker() {
'https://easylist-downloads.adblockplus.org/ruadlist+easylist.txt', // RuAdList
];
const b = await ElectronBlocker.fromLists(fetchFn, [...adsAndTrackingLists, ...russianLists]);
// Whitelist TMDB so the movie search API is not blocked
b.addFilters(['@@||api.themoviedb.org^', '@@||image.tmdb.org^', '@@||themoviedb.org^']);
// Whitelist domains that need ALL requests passed through unfiltered.
// Tracking-list false positives on these break critical functionality:
// • Google: OAuth/login integrity checks fail without gstatic + analytics endpoints
// → "Возможно, этот браузер или приложение небезопасны" error
// • Yandex/Mail/Microsoft/Apple: same OAuth-style integrity flows
// • TMDB: movie search API and poster CDN
const whitelist = [
'@@||api.themoviedb.org^', '@@||image.tmdb.org^', '@@||themoviedb.org^',
'@@||google.com^', '@@||googleapis.com^', '@@||googleusercontent.com^',
'@@||gstatic.com^', '@@||youtube.com^', '@@||ytimg.com^', '@@||googlevideo.com^',
'@@||google-analytics.com^', '@@||googletagmanager.com^',
'@@||yandex.ru^', '@@||yandex.com^', '@@||yastatic.net^', '@@||mc.yandex.ru^',
'@@||github.com^', '@@||githubassets.com^', '@@||githubusercontent.com^',
'@@||vk.com^', '@@||vk.ru^', '@@||vkuser.net^',
'@@||mail.ru^', '@@||my.mail.ru^', '@@||imgsmail.ru^',
'@@||microsoft.com^', '@@||microsoftonline.com^', '@@||live.com^', '@@||office.com^',
'@@||apple.com^', '@@||icloud.com^',
'@@||facebook.com^', '@@||fbcdn.net^',
];
b.updateFromDiff({ added: whitelist });
fs.writeFileSync(BLOCKER_CACHE_PATH, Buffer.from(b.serialize()));
console.log('[adblock] filter lists downloaded and cached');
return b;
@@ -1172,20 +1190,37 @@ app.whenReady().then(async () => {
app.userAgentFallback = cleanUserAgent;
session.defaultSession.setUserAgent(cleanUserAgent);
// Add Referer to image requests so hotlink protection doesn't block them
session.defaultSession.webRequest.onBeforeSendHeaders(
{ urls: ['https://*/*', 'http://*/*'] },
(details, callback) => {
const headers = details.requestHeaders;
if (details.resourceType === 'image' && !headers['Referer'] && !headers['referer']) {
try {
const u = new URL(details.url);
headers['Referer'] = `${u.protocol}//${u.hostname}/`;
} catch (_) {}
// Chrome version from the cleaned UA — used for client hints below
const chromeVerMatch = cleanUserAgent.match(/Chrome\/(\d+)/);
const chromeMajor = chromeVerMatch ? chromeVerMatch[1] : '128';
const secChUa = `"Not_A Brand";v="8", "Chromium";v="${chromeMajor}", "Google Chrome";v="${chromeMajor}"`;
const installRequestHooks = (sess) => {
sess.webRequest.onBeforeSendHeaders(
{ urls: ['https://*/*', 'http://*/*'] },
(details, callback) => {
const headers = details.requestHeaders;
// Spoof Sec-CH-UA so embedded-browser detectors (Google login, etc.) see
// a real-Chrome brand list. Electron normally injects the app name as
// the brand which is how Google fingerprints us as "embedded/unsafe".
headers['sec-ch-ua'] = secChUa;
headers['sec-ch-ua-mobile'] = '?0';
headers['sec-ch-ua-platform'] = '"Windows"';
// Add Referer to image requests so hotlink protection doesn't block them
if (details.resourceType === 'image' && !headers['Referer'] && !headers['referer']) {
try {
const u = new URL(details.url);
headers['Referer'] = `${u.protocol}//${u.hostname}/`;
} catch (_) {}
}
callback({ requestHeaders: headers });
}
callback({ requestHeaders: headers });
}
);
);
};
installRequestHooks(session.defaultSession);
installRequestHooks(getProxySession());
installRequestHooks(getDirectSession());
// Apply proxy from config before blocker tries to download filter lists
loadTrustedDomainsFromDisk();

View File

@@ -1,6 +1,6 @@
{
"name": "ESH-Media",
"version": "1.0.3",
"version": "1.0.4",
"private": true,
"main": "main.js",
"scripts": {