fix(theseus): give pages a Chrome-shaped window.chrome
Electron hands every page an empty window.chrome. Real Chrome's carries app, csi, loadTimes and runtime, and bot checks — Google's sign-in botguard among them — look for exactly those to tell Chrome from an embedded Chromium. The per-tab identity script now fills the object with the same shapes and return types; a site learns nothing it would not also learn from stock Chrome.
This commit is contained in:
parent
cee120cb23
commit
5b6b693694
1 changed files with 14 additions and 0 deletions
14
main.js
14
main.js
|
|
@ -807,6 +807,8 @@ async function applyFingerprint(wc) {
|
||||||
if (settings.hideMediaDevices) {
|
if (settings.hideMediaDevices) {
|
||||||
src += `try{const md=navigator.mediaDevices;if(md&&md.enumerateDevices){const o=md.enumerateDevices.bind(md);md.enumerateDevices=async()=>{let l=[];try{l=await o()}catch(e){}const ks=[...new Set(l.map(d=>d.kind))];return ks.map(kind=>({deviceId:'',kind:kind,label:'',groupId:'',toJSON(){return{deviceId:'',kind:kind,label:'',groupId:''}}}))};}}catch(e){}`;
|
src += `try{const md=navigator.mediaDevices;if(md&&md.enumerateDevices){const o=md.enumerateDevices.bind(md);md.enumerateDevices=async()=>{let l=[];try{l=await o()}catch(e){}const ks=[...new Set(l.map(d=>d.kind))];return ks.map(kind=>({deviceId:'',kind:kind,label:'',groupId:'',toJSON(){return{deviceId:'',kind:kind,label:'',groupId:''}}}))};}}catch(e){}`;
|
||||||
}
|
}
|
||||||
|
// Always on: Chrome-shaped window.chrome (see CHROME_SHIM_SRC).
|
||||||
|
src += CHROME_SHIM_SRC;
|
||||||
if (src) {
|
if (src) {
|
||||||
const res = await wc.debugger.sendCommand("Page.addScriptToEvaluateOnNewDocument", { source: src });
|
const res = await wc.debugger.sendCommand("Page.addScriptToEvaluateOnNewDocument", { source: src });
|
||||||
wc._langScript = res.identifier;
|
wc._langScript = res.identifier;
|
||||||
|
|
@ -875,6 +877,18 @@ function stockChromeUA() {
|
||||||
// still said "Chromium" only. DataDome ("AI Threats Detection") blocked on
|
// still said "Chromium" only. DataDome ("AI Threats Detection") blocked on
|
||||||
// exactly that header/JS mismatch (estore.asus.com, 2026-09-20), so the same
|
// exactly that header/JS mismatch (estore.asus.com, 2026-09-20), so the same
|
||||||
// metadata is now also installed in every tab via Emulation.setUserAgentOverride.
|
// metadata is now also installed in every tab via Emulation.setUserAgentOverride.
|
||||||
|
// Electron hands every page an EMPTY window.chrome. Real Chrome's carries
|
||||||
|
// app / csi / loadTimes / runtime, and bot checks — Google sign-in's among
|
||||||
|
// them — look for exactly those to tell Chrome from an embedded Chromium.
|
||||||
|
// Same shapes and return types as Chrome; nothing here is reachable by the
|
||||||
|
// site beyond what a stock Chrome would also give it.
|
||||||
|
const CHROME_SHIM_SRC = `try{(()=>{const c=window.chrome;if(!c||typeof c!=="object"||Object.keys(c).length)return;
|
||||||
|
const t=()=>performance.timing;
|
||||||
|
c.app={isInstalled:false,InstallState:{DISABLED:"disabled",INSTALLED:"installed",NOT_INSTALLED:"not_installed"},RunningState:{CANNOT_RUN:"cannot_run",READY_TO_RUN:"ready_to_run",RUNNING:"running"},getDetails(){return null},getIsInstalled(){return false},runningState(){return "cannot_run"}};
|
||||||
|
c.csi=function(){const p=t();return{startE:p.navigationStart,onloadT:p.domContentLoadedEventEnd,pageT:performance.now(),tran:15}};
|
||||||
|
c.loadTimes=function(){const p=t();return{requestTime:p.navigationStart/1000,startLoadTime:p.navigationStart/1000,commitLoadTime:p.responseStart/1000,finishDocumentLoadTime:p.domContentLoadedEventEnd/1000,finishLoadTime:p.loadEventEnd/1000,firstPaintTime:p.responseEnd/1000,firstPaintAfterLoadTime:0,navigationType:"Other",wasFetchedViaSpdy:true,wasNpnNegotiated:true,npnNegotiatedProtocol:"h2",wasAlternateProtocolAvailable:false,connectionInfo:"h2"}};
|
||||||
|
c.runtime={OnInstalledReason:{CHROME_UPDATE:"chrome_update",INSTALL:"install",SHARED_MODULE_UPDATE:"shared_module_update",UPDATE:"update"},OnRestartRequiredReason:{APP_UPDATE:"app_update",OS_UPDATE:"os_update",PERIODIC:"periodic"},PlatformArch:{ARM:"arm",ARM64:"arm64",MIPS:"mips",MIPS64:"mips64",X86_32:"x86-32",X86_64:"x86-64"},PlatformNaclArch:{ARM:"arm",MIPS:"mips",MIPS64:"mips64",X86_32:"x86-32",X86_64:"x86-64"},PlatformOs:{ANDROID:"android",CROS:"cros",LINUX:"linux",MAC:"mac",OPENBSD:"openbsd",WIN:"win"},RequestUpdateCheckStatus:{NO_UPDATE:"no_update",THROTTLED:"throttled",UPDATE_AVAILABLE:"update_available"},id:undefined,connect(){throw new TypeError("chrome.runtime.connect() called from a webpage must specify an Extension ID (string) for its first argument.")},sendMessage(){throw new TypeError("chrome.runtime.sendMessage() called from a webpage must specify an Extension ID (string) for its first argument.")}};
|
||||||
|
})()}catch(e){}`;
|
||||||
function chromeBrandMetadata() {
|
function chromeBrandMetadata() {
|
||||||
const full = CHROME_VERSION_CLAIMED;
|
const full = CHROME_VERSION_CLAIMED;
|
||||||
const major = parseInt(full.split(".")[0], 10) || 130;
|
const major = parseInt(full.split(".")[0], 10) || 130;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue