Last active
January 20, 2019 15:16
-
-
Save mikesamuel/4f3696975ec47d09de50dc3f4328dfe9 to your computer and use it in GitHub Desktop.
Checking arguments to Function/eval
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class TrustedScript { // Just a stub of github.com/wicg/trusted-types | |
constructor(x) { | |
this.content = String(x); | |
} | |
toString() { | |
return this.content; | |
} | |
static createUnsafely(x) { | |
return new TrustedScript(x); | |
} | |
} | |
function unwrapTrustedScript(x) { | |
if (x instanceof TrustedScript) { | |
return String(x); | |
} | |
throw new TypeError(`Expected TrustedScript got ${ x }: ${ typeof x }`); | |
} | |
function unwrapTrustedScriptAsLastArgument(argumentList) { | |
const n = argumentList.length; | |
if (n) { | |
argumentList[n - 1] = unwrapTrustedScript(argumentList[n - 1]); | |
} | |
} | |
const TrustedScriptCheckingFunctionProxy = new Proxy( | |
Function, | |
{ | |
construct(target, argumentList) { | |
unwrapTrustedScriptAsLastArgument(argumentList); | |
return Reflect.construct(target, argumentList); | |
}, | |
apply(target, thisArg, argumentList) { | |
unwrapTrustedScriptAsLastArgument(argumentList); | |
return Reflect.apply(target, thisArg, argumentList); | |
} | |
}); | |
// Does not distinguish between eval operator and eval function. | |
// eval has to be called via an identifier named eval. | |
const checkingEval = ((eval) => (x) => eval(unwrapTrustedScript(x)))(eval); | |
Function.prototype.constructor = TrustedScriptCheckingFunctionProxy; | |
Function = TrustedScriptCheckingFunctionProxy; | |
eval = checkingEval; | |
let puppyKicked = 0; | |
let puppyPetted = 0; | |
function kickPuppy() { | |
++puppyKicked; | |
// You heartless monster. | |
} | |
function petPuppy() { | |
++puppyPetted; | |
// Awww. | |
} | |
try { | |
eval('kickPuppy()'); | |
} catch (ex) { | |
console.error(ex); | |
} | |
try { | |
new Function('kickPuppy()')(); | |
} catch (ex) { | |
console.error(ex); | |
} | |
try { | |
({}).constructor.constructor('kickPuppy()')(); | |
} catch (ex) { | |
console.error(ex); | |
} | |
try { | |
eval(TrustedScript.createUnsafely('petPuppy()')); | |
} catch (ex) { | |
console.error(ex); | |
} | |
try { | |
new Function(TrustedScript.createUnsafely('petPuppy()'))(); | |
} catch (ex) { | |
console.error(ex); | |
} | |
try { | |
({}).constructor.constructor(TrustedScript.createUnsafely('petPuppy()'))(); | |
} catch (ex) { | |
console.error(ex); | |
} | |
console.log(`puppyKicked=${ puppyKicked }`); // -> 0 | |
console.log(`puppyPetted=${ puppyPetted }`); // -> 3 | |
console.log(`((function () {}) instanceof Function)=${ (function () {}) instanceof Function }`); // -> true | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment