first commit
This commit is contained in:
commit
ff482ebe23
251 files changed
+19126
No files matched your search
@@ -0,0 +1,55 @@
|
||||
'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};
|
||||
Reference in new issue
Block a user