Files
safetynet/tests/fixtures/broker-electron-interop.cjs

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'});}
});