'use strict'; // This capability stays in the main process. Neither pages nor agents receive CDP access. const owners=new WeakMap(); function protectClipboardPrimitives(){ 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}); 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}); const deny=event=>{event.preventDefault();event.stopImmediatePropagation();}; for(const name of ['copy','cut','paste','dragstart','dragover','drop'])window.addEventListener(name,deny,true); const transferred=RegExp.prototype.test.bind(/^(insertFromPaste|insertFromDrop|deleteByCut)/); window.addEventListener('beforeinput',event=>{if(transferred(event.inputType||''))deny(event);},true); } const source=`(${protectClipboardPrimitives.toString()})();`; function deadline(operation){let timer;return Promise.race([operation,new Promise((_,reject)=>{timer=setTimeout(()=>reject(Error('Page security initialization timed out')),5000);})]).finally(()=>clearTimeout(timer));} async function attachPageClipboardGuard(contents,onFailure){ const api=contents.debugger; if(!api||api.isAttached()||owners.has(contents))throw Error('Page security initialization unavailable'); const owner={api,healthy:false}; const detached=()=>{owners.delete(contents);owner.healthy=false;if(!contents.isDestroyed())onFailure();}; owner.detached=detached; api.on('detach',detached); try{ api.attach('1.3'); await deadline(api.sendCommand('Page.enable',{})); const registration=await deadline(api.sendCommand('Page.addScriptToEvaluateOnNewDocument',{source})); if(typeof registration?.identifier!=='string'||!registration.identifier||!api.isAttached())throw Error('Page security initialization failed'); owner.healthy=true;owners.set(contents,owner); }catch{ api.removeListener('detach',detached); if(api.isAttached())api.detach(); throw Error('Page security initialization failed'); } } function guardedScreenshot(contents,parameters){ const owner=owners.get(contents); if(!owner)return null; if(!owner.healthy||owner.api!==contents.debugger||!owner.api.isAttached())throw Error('Page security connection unavailable'); // Only the fixed screenshot command is shared. There is no general command dispatcher. return owner.api.sendCommand('Page.captureScreenshot',parameters); } function disposePageClipboardGuard(contents){ const owner=owners.get(contents);if(!owner)return; owners.delete(contents);owner.healthy=false;owner.api.removeListener('detach',owner.detached); if(owner.api.isAttached())owner.api.detach(); } module.exports={attachPageClipboardGuard,guardedScreenshot,disposePageClipboardGuard};