43 lines
2.7 KiB
JavaScript
43 lines
2.7 KiB
JavaScript
'use strict';
|
|
// Test-only stock Electron client. No production browser APIs or policy edits.
|
|
const {app,BrowserWindow,session}=require('electron');
|
|
const {X509Certificate}=require('node:crypto');
|
|
app.disableHardwareAcceleration();
|
|
let window,config,loginCount=0,initialized=false;
|
|
const send=value=>{if(process.connected)process.send(value);};
|
|
process.on('disconnect',()=>app.exit(0));
|
|
app.on('login',(event,contents,_details,info,callback)=>{
|
|
event.preventDefault();
|
|
if(config&&contents===window?.webContents&&info.isProxy&&info.host==='127.0.0.1'&&info.port===config.proxyPort&&info.scheme.toLowerCase()==='basic'&&info.realm==='SafetyNet private broker'){
|
|
loginCount++;callback(config.credentials.username,config.credentials.password);
|
|
}else callback();
|
|
});
|
|
process.on('message',async message=>{
|
|
try {
|
|
if(message?.type==='initialize'&&!initialized){
|
|
initialized=true;config=message.config;
|
|
app.setPath('userData',config.userData);
|
|
await app.whenReady();
|
|
const partition=session.fromPartition('broker-interop',{cache:false});
|
|
partition.setCertificateVerifyProc((request,callback)=>{
|
|
try {
|
|
const certificate=new X509Certificate(request.certificate.data);
|
|
const now=Date.now();
|
|
if(request.hostname==='localhost'&&certificate.checkHost('localhost')==='localhost'&&certificate.fingerprint256===config.fingerprint&&Date.parse(certificate.validFrom)<=now&&now<Date.parse(certificate.validTo))return callback(0);
|
|
}catch{}
|
|
callback(-3);
|
|
});
|
|
await partition.setProxy({mode:'fixed_servers',proxyRules:`http=127.0.0.1:${config.proxyPort};https=127.0.0.1:${config.proxyPort}`,proxyBypassRules:'<-loopback>'});
|
|
window=new BrowserWindow({show:false,webPreferences:{session:partition,nodeIntegration:false,contextIsolation:true,sandbox:true,webSecurity:true}});
|
|
window.webContents.on('render-process-gone',()=>send({type:'error',code:'renderer-gone'}));
|
|
await window.loadURL(config.origin+'/');
|
|
send({type:'ready',loginCount,electron:process.versions.electron,chromium:process.versions.chrome});return;
|
|
}
|
|
if(message?.type==='stop'){window?.destroy();app.exit(0);return;}
|
|
const bodies={public:'public browser content',secret:'PROJECT SECRET',revoked:'public revoked content'};
|
|
if(!window||!Object.hasOwn(bodies,message?.type))throw Error('invalid-message');
|
|
const result=await window.webContents.executeJavaScript(`(async()=>{try{const response=await fetch('/submit',{method:'POST',body:${JSON.stringify(bodies[message.type])}});return {status:response.status,body:await response.text()};}catch{return {blocked:true};}})()`);
|
|
send({type:'result',operation:message.type,result,loginCount});
|
|
} catch {send({type:'error',code:'interop-failed'});}
|
|
});
|