const {ipcRenderer}=require('electron'); if(process.sandboxed!==true||process.contextIsolated!==true){ipcRenderer.send('managed:clipboard-sandbox-failure');window.stop();throw Error('Managed renderer sandbox and isolation are required');} // Native shortcuts and guarded menus are the only supported clipboard transfer paths. // Prevent page handlers/legacy execCommand from replacing approved plaintext with hidden data. // Freeze the legacy command primitive in the page realm. Document.open() removes // DOM listeners, but cannot replace this non-configurable prototype property. try { require('electron').contextBridge.executeInMainWorld({func:()=>{ const prototype=Document.prototype,existing=Object.getOwnPropertyDescriptor(prototype,'execCommand'); if(existing?.value?._managedClipboardGuard===true&&!existing.configurable)return; const original=prototype.execCommand,apply=Reflect.apply,test=RegExp.prototype.test.bind(/^(copy|cut|paste)/i); function managedClipboardCommand(command,...args){ if(typeof command!=='string'||test(command))return false; return apply(original,this,[command,...args]); } Object.defineProperty(managedClipboardCommand,'_managedClipboardGuard',{value:true}); Object.defineProperty(prototype,'execCommand',{value:managedClipboardCommand,writable:false,configurable:false}); // Replacement clears security listeners; these unsupported legacy APIs fail closed. const SecurityException=DOMException; const denyReplacement=()=>{throw new SecurityException('Managed document replacement is disabled','SecurityError');}; for(const name of ['open','write','writeln'])Object.defineProperty(prototype,name,{value:denyReplacement,writable:false,configurable:false}); }}); } catch { require('electron').ipcRenderer.send('managed:clipboard-sandbox-failure'); window.stop(); throw Error('Managed clipboard primitive could not be protected'); } for(const name of ['copy','cut','paste','dragstart','dragover','drop'])window.addEventListener(name,event=>{event.preventDefault();event.stopImmediatePropagation();},true); window.addEventListener('beforeinput',event=>{if(/^(insertFromPaste|insertFromDrop|deleteByCut)/.test(event.inputType||'')){event.preventDefault();event.stopImmediatePropagation();}},true); let visualEnabled=ipcRenderer.sendSync('managed:visual-policy').enabled; const documentToken=typeof crypto.randomUUID==='function'?crypto.randomUUID():Array.from(crypto.getRandomValues(new Uint8Array(16)),value=>value.toString(16).padStart(2,'0')).join('');let visualRevision=0,visualApproved=!visualEnabled,visualScheduled=false; ipcRenderer.on('managed:visual-config',(_event,input)=>{visualEnabled=input.enabled===true;visualApproved=!visualEnabled;visualRevision++;visualChanged();ipcRenderer.send('managed:visual-configured',input.token);}); function visualChanged(){ if(!visualEnabled)return;visualRevision++;visualApproved=false; if(visualScheduled)return;visualScheduled=true; setTimeout(async()=>{visualScheduled=false;const revision=visualRevision,url=location.href; try{const result=await ipcRenderer.invoke('managed:visual-check',{token:documentToken,revision,url});if(revision===visualRevision&&url===location.href)visualApproved=result.decision==='allow';}catch{visualApproved=false;} if(!visualApproved&&revision===visualRevision)setTimeout(visualChanged,1000); },150); } for(const name of ['keydown','beforeinput','paste','submit','pointerdown'])window.addEventListener(name,event=>{ if(!visualEnabled||visualApproved)return; const element=event.target; if(name==='submit'||element?.closest?.('input,textarea,[contenteditable="true"],button[type="submit"]')){event.preventDefault();event.stopImmediatePropagation();visualChanged();} },true); // This isolated-world preload exposes no bridge or automation capability to sites. let scheduled=false,last=''; function inspect(){scheduled=false;const text=(document.body?.innerText||'').slice(0,250000);if(text===last)return;last=text;ipcRenderer.send('managed:page-content',{text});} function schedule(){if(!scheduled){scheduled=true;setTimeout(inspect,350);}} window.addEventListener('DOMContentLoaded',()=>{schedule();visualChanged();new MutationObserver(()=>{schedule();visualChanged();}).observe(document,{childList:true,subtree:true,characterData:true,attributes:true});});