If so, please let me know what those security risks are, and, for bonus points, whether those security risks can be avoided by using the safest known function-cloning solutions that use eval(), new Function(), .bind, .call, or .apply... in the context of unknown user input... considering the below function.
Here's a simplified, shallow, dirty cloning function (preceded by an example function-to-clone and an example class-to-clone) to demonstrate what I mean by dirty cloning:
function doStuff(x, y){
console.log("did stuff with x: " + x + " and y: " + y);
}
let clonedFunc = dirtyClone(doStuff); // shallow-clone; for brevity
clonedFunc( 5, "because" );
class Animal{
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
let clonedClass = dirtyClone(Animal); // shallow-clone; for brevity
let anInstance = new clonedClass("Cloned-Class Instance");
anInstance.speak();
function dirtyClone(class_or_function){ // shallow-clone; for brevity
if(typeof class_or_function !== "function"){
console.log("wrong input type");
return false;
}
let stringVersion = class_or_function.toString();
let preCurl = stringVersion.match(/[^{]*/)[0];
let funcType;
if(preCurl.indexOf("function") !== -1) funcType = "function";
else if(preCurl.indexOf("class") !== -1) funcType = "class";
else {
console.log("wrong input type");
return false;
}
// uuid adapted from: https://stackoverflow.com/a/21963136
let lut = []; for (let i=0; i<256; i++) { lut[i] = (i<16?'0':'')+(i).toString(16); }
let d0 = Math.random()*0xffffffff|0;
let d1 = Math.random()*0xffffffff|0;
let d2 = Math.random()*0xffffffff|0;
let d3 = Math.random()*0xffffffff|0;
let aUUID = "a_" + lut[d0&0xff]+lut[d0>>8&0xff]+lut[d0>>16&0xff]+lut[d0>>24&0xff]+'_'+
lut[d1&0xff]+lut[d1>>8&0xff]+'_'+lut[d1>>16&0x0f|0x40]+lut[d1>>24&0xff]+'_'+
lut[d2&0x3f|0x80]+lut[d2>>8&0xff]+'_'+lut[d2>>16&0xff]+lut[d2>>24&0xff]+
lut[d3&0xff]+lut[d3>>8&0xff]+lut[d3>>16&0xff]+lut[d3>>24&0xff];
let bUUID = "b_" + lut[d0&0xff]+lut[d0>>8&0xff]+lut[d0>>16&0xff]+lut[d0>>24&0xff]+'_'+
lut[d1&0xff]+lut[d1>>8&0xff]+'_'+lut[d1>>16&0x0f|0x40]+lut[d1>>24&0xff]+'_'+
lut[d2&0x3f|0x80]+lut[d2>>8&0xff]+'_'+lut[d2>>16&0xff]+lut[d2>>24&0xff]+
lut[d3&0xff]+lut[d3>>8&0xff]+lut[d3>>16&0xff]+lut[d3>>24&0xff];
switch(funcType){
case "function":
let functionName = stringVersion.match(/[^(]*/);
let functionBod = stringVersion.replace(functionName,"");
let newFunction = "function " + aUUID + " " + functionBod;
let funScript = document.createElement("SCRIPT");
funScript.text = newFunction;
document.body.append(funScript);
break;
case "class":
let classNameDec = stringVersion.match(/[^{]*/);
let classBod = stringVersion.replace(classNameDec,"");
let newClass = "class " + bUUID + " " + classBod;
let classScript = document.createElement("SCRIPT");
classScript.text = aUUID + " = " + newClass;
document.body.append(classScript);
break;
case "child_class":
// excluded; for brevity
break;
default:
console.log("wrong input type");
return false;
}
return window[aUUID];
}