Task 26377610: [DynamicProto] Investigate possible security issue with prototype pollution (#81)

This commit is contained in:
Nev 2024-01-11 10:58:39 -08:00 коммит произвёл GitHub
Родитель 09cf322bd0
Коммит 69866bb9c4
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 1626 добавлений и 575 удалений

4
.github/workflows/ci.yml поставляемый
Просмотреть файл

@ -24,6 +24,10 @@ jobs:
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Update rush shrinkwrap dependencies (for different node versions)
run: node common/scripts/install-run-rush.js update --full
- run: npm install rollup -g
- run: npm install grunt-cli
- run: npm install
- run: node common/scripts/install-run-rush.js check && node common/scripts/install-run-rush.js update
- run: npm run build --verbose

1450
common/config/rush/npm-shrinkwrap.json сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -89,6 +89,15 @@ module.exports = function (grunt) {
}
}
}
},
connect: {
server: {
options: {
port: 9005,
base: '.',
debug: true
}
}
}
});
@ -100,6 +109,7 @@ module.exports = function (grunt) {
grunt.loadNpmTasks("@nevware21/grunt-eslint-ts");
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-run');
grunt.registerTask("default", ["ts:rollup", "ts:rolluptest", "ts:dynamicproto", "ts:dynamicprototest", "qunit:rollup", "qunit:dynamicproto"]);
grunt.registerTask("dynamicproto", ["eslint-ts:dynamicproto-fix", "ts:dynamicproto"]);
@ -107,4 +117,5 @@ module.exports = function (grunt) {
grunt.registerTask("rollup", ["ts:rollup", "ts:rolluptest", "qunit:rollup"]);
grunt.registerTask("lint", ["eslint-ts:dynamicproto"]);
grunt.registerTask("lint-fix", ["eslint-ts:dynamicproto-fix"]);
grunt.registerTask("serve", ["connect:server:keepalive"]);
};

Просмотреть файл

@ -39,7 +39,7 @@
"license": "MIT",
"sideEffects": false,
"dependencies": {
"@nevware21/ts-utils": ">= 0.9.4 < 2.x"
"@nevware21/ts-utils": ">= 0.10.4 < 2.x"
},
"devDependencies": {
"@microsoft/applicationinsights-rollup-es3" : "^1.0.1",

Просмотреть файл

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import { getGlobal, objHasOwnProperty, throwTypeError } from "@nevware21/ts-utils";
import { getGlobal, objCreate, objHasOwnProperty, throwTypeError } from "@nevware21/ts-utils";
interface DynamicGlobalSettings {
/**
@ -152,8 +152,7 @@ function _isObjectOrArrayPrototype(target:any) {
* Helper used to check whether the target is an Object prototype, Array prototype or Function prototype
* @ignore
*/
function _isObjectArrayOrFunctionPrototype(target:any)
{
function _isObjectArrayOrFunctionPrototype(target:any) {
return _isObjectOrArrayPrototype(target) || target === Function[Prototype];
}
@ -219,7 +218,7 @@ function _forEachProp(target: any, func: (name: string) => void) {
* @ignore
*/
function _isDynamicCandidate(target:any, funcName:string, skipOwn:boolean) {
return (funcName !== Constructor && typeof target[funcName] === strFunction && (skipOwn || objHasOwnProperty(target, funcName)));
return (funcName !== Constructor && typeof target[funcName] === strFunction && (skipOwn || objHasOwnProperty(target, funcName)) && funcName !== str__Proto && funcName !== Prototype);
}
/**
@ -239,7 +238,7 @@ function _throwTypeError(message:string) {
*/
function _getInstanceFuncs(thisTarget:any): any {
// Get the base proto
var instFuncs = {};
var instFuncs = objCreate(null);
// Save any existing instance functions
_forEachProp(thisTarget, (name) => {
@ -292,7 +291,7 @@ function _getBaseFuncs(classProto:any, thisTarget:any, instFuncs:any, useBaseIns
}
// Start creating a new baseFuncs by creating proxies for the instance functions (as they may get replaced)
var baseFuncs = {};
var baseFuncs = objCreate(null);
_forEachProp(instFuncs, (name) => {
// Create an instance callback for passing the base function to the caller
baseFuncs[name] = _instFuncProxy(thisTarget, instFuncs, name);
@ -333,8 +332,8 @@ function _getInstFunc(target: any, funcName: string, proto: any, currentDynProto
// it will walk the proto chain and return any parent proto classname.
if (target && objHasOwnProperty(proto, DynClassName)) {
let instFuncTable = target[DynInstFuncTable] || {};
instFunc = (instFuncTable[proto[DynClassName]] || {})[funcName];
let instFuncTable = target[DynInstFuncTable] || objCreate(null);
instFunc = (instFuncTable[proto[DynClassName]] || objCreate(null))[funcName];
if (!instFunc) {
// Avoid stack overflow from recursive calling the same function
@ -426,27 +425,31 @@ function _populatePrototype(proto:any, className:string, target:any, baseInstFun
}
if (!_isObjectOrArrayPrototype(proto)) {
let instFuncTable = target[DynInstFuncTable] = target[DynInstFuncTable] || {};
let instFuncs = instFuncTable[className] = (instFuncTable[className] || {}); // fetch and assign if as it may not exist yet
let instFuncTable = target[DynInstFuncTable] = target[DynInstFuncTable] || objCreate(null);
if (!_isObjectOrArrayPrototype(instFuncTable)) {
let instFuncs = instFuncTable[className] = (instFuncTable[className] || objCreate(null)); // fetch and assign if as it may not exist yet
// Set whether we are allow to lookup instances, if someone has set to false then do not re-enable
if (instFuncTable[DynAllowInstChkTag] !== false) {
instFuncTable[DynAllowInstChkTag] = !!setInstanceFunc;
}
_forEachProp(target, (name) => {
// Only add overridden functions
if (_isDynamicCandidate(target, name, false) && target[name] !== baseInstFuncs[name] ) {
// Save the instance Function to the lookup table and remove it from the instance as it's not a dynamic proto function
instFuncs[name] = target[name];
delete target[name];
// Add a dynamic proto if one doesn't exist or if a prototype function exists and it's not a dynamic one
if (!objHasOwnProperty(proto, name) || (proto[name] && !proto[name][DynProxyTag])) {
proto[name] = _createDynamicPrototype(proto, name);
}
// Set whether we are allow to lookup instances, if someone has set to false then do not re-enable
if (instFuncTable[DynAllowInstChkTag] !== false) {
instFuncTable[DynAllowInstChkTag] = !!setInstanceFunc;
}
});
if (!_isObjectOrArrayPrototype(instFuncs)) {
_forEachProp(target, (name) => {
// Only add overridden functions
if (_isDynamicCandidate(target, name, false) && target[name] !== baseInstFuncs[name] ) {
// Save the instance Function to the lookup table and remove it from the instance as it's not a dynamic proto function
instFuncs[name] = target[name];
delete target[name];
// Add a dynamic proto if one doesn't exist or if a prototype function exists and it's not a dynamic one
if (!objHasOwnProperty(proto, name) || (proto[name] && !proto[name][DynProxyTag])) {
proto[name] = _createDynamicPrototype(proto, name);
}
}
});
}
}
}
}

Просмотреть файл

@ -0,0 +1,667 @@
/// <reference path="./TestFramework/Common.ts" />
import { objGetPrototypeOf } from "@nevware21/ts-utils";
import dynamicProto from "../src/DynamicProto";
class HackClass {
public hello: string;
constructor() {
this.hello = "world";
}
}
class BadInstClass {
public _dynInstFuncs: any = {};
constructor() {
this._dynInstFuncs = Object.prototype;
}
}
class BadProxyInstClass {
public _dynInstFuncs: any = {};
constructor() {
this._dynInstFuncs = new Proxy(this, {
get: (target, prop) => {
if (typeof prop === "string" && prop.startsWith("_dynCls")) {
return Object.prototype;
}
return target[prop];
}
});
}
}
export class SecurityCheckTests extends TestClass {
public testInitialize() {
}
public registerTests() {
this.testCase({
name: "Try to update Object.prototype directly",
test: () => {
let a: any = {};
try {
dynamicProto(Object, a, (_self, base) => {
_self._testFunction = () => {
QUnit.assert.fail("Should not be able to update Object.prototype");
}
_self.__proto__ = {
testHack: true
};
_self.prototype = {
testHack2: true
};
});
QUnit.assert.fail("Should not be able to update Object.prototype");
} catch (e) {
QUnit.assert.ok(true, "Expected an exception to be thrown");
}
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack2"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("_testFunction"), "Should not have polluted Object.prototype");
}
});
this.testCase({
name: "Try to update Object.prototype directly",
test: () => {
let a: any = {};
try {
dynamicProto(Object.prototype, a, (_self, base) => {
_self._testFunction = () => {
QUnit.assert.fail("Should not be able to update Object.prototype");
}
_self.__proto__ = {
testHack: true
};
_self.prototype = {
testHack2: true
};
});
QUnit.assert.fail("Should not be able to update Object.prototype");
} catch (e) {
QUnit.assert.ok(true, "Expected an exception to be thrown");
}
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack2"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("_testFunction"), "Should not have polluted Object.prototype");
}
});
this.testCase({
name: "Try to update Object.prototype directly",
test: () => {
let a: any = {};
try {
dynamicProto(Object, a, (_self, base) => {
_self._testFunction = () => {
QUnit.assert.fail("Should not be able to update Object.prototype");
}
_self.__proto__ = {
testHack: true
};
_self.prototype = {
testHack2: true
};
});
QUnit.assert.fail("Should not be able to update Object.prototype");
} catch (e) {
QUnit.assert.ok(true, "Expected an exception to be thrown");
}
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack2"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("_testFunction"), "Should not have polluted Object.prototype");
}
});
this.testCase({
name: "Try to update Object.prototype directly with a HackClass instance and __proto__ property",
test: () => {
let a = new HackClass();
dynamicProto(HackClass, a, (_self, base) => {
let self = <any>_self;
self.__proto__ = {
testHack: true
};
self.prototype = {
testHack2: true
};
self._testFunction = () => {
QUnit.assert.fail("Should not be able to update Object.prototype");
}
});
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack2"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("_testFunction"), "Should not have polluted Object.prototype");
}
});
this.testCase({
name: "Try to update Object.prototype directly with a HackClass instance and __proto__ function",
test: () => {
let a = new HackClass();
dynamicProto(HackClass, a, (_self, base) => {
let self = <any>_self;
self.__proto__ = () => {
testHack: true
};
self.prototype = {
testHack2: true
};
self._testFunction = () => {
QUnit.assert.fail("Should not be able to update Object.prototype");
}
});
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack2"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("_testFunction"), "Should not have polluted Object.prototype");
}
});
this.testCase({
name: "Try to update Object.prototype directly using defineProperty with a HackClass instance and __proto__ property",
test: () => {
let a = new HackClass();
dynamicProto(HackClass, a, (_self, base) => {
let self = <any>_self;
Object.defineProperty(self, "__proto__", {
value: {
testHack: true
},
configurable: true,
enumerable: true
});
self.prototype = {
testHack2: true
};
self._testFunction = () => {
QUnit.assert.fail("Should not be able to update Object.prototype");
}
});
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack2"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("_testFunction"), "Should not have polluted Object.prototype");
}
});
this.testCase({
name: "Try to update Object.prototype directly using defineProperty with a HackClass instance and __proto__ function",
test: () => {
let a = new HackClass();
dynamicProto(HackClass, a, (_self, base) => {
let self = <any>_self;
Object.defineProperty(self, "__proto__", {
value: () => {
testHack: true
},
configurable: true,
enumerable: true
});
self.prototype = {
testHack2: true
};
self._testFunction = () => {
QUnit.assert.fail("Should not be able to update Object.prototype");
}
});
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack2"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("_testFunction"), "Should not have polluted Object.prototype");
}
});
this.testCase({
name: "Try to update Object.prototype using HackClass instance with a __proto__ function",
test: () => {
let a = new HackClass();
dynamicProto(HackClass, a, (_self, base) => {
let self = <any>_self;
self.__proto__ = () => {
QUnit.assert.fail("Should not be able to update Object.prototype");
};
self.prototype = {
testHack2: true
};
self._testFunction = () => {
QUnit.assert.fail("Should not be able to update Object.prototype");
}
});
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack2"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("_testFunction"), "Should not have polluted Object.prototype");
}
});
this.testCase({
name: "Try to update Object.prototype directly with HackClass and an object instance",
test: () => {
let a = {};
try {
dynamicProto(HackClass, a, (_self, base) => {
let self = <any>_self;
self._testFunction = () => {
QUnit.assert.fail("Should not be able to update Object.prototype");
}
self.__proto__ = {
testHack: true
};
self.prototype = {
testHack2: true
};
});
QUnit.assert.fail("Should not be able to update Object.prototype");
} catch (e) {
QUnit.assert.ok(true, "Expected an exception to be thrown");
QUnit.assert.ok(e.message.indexOf("not in hierarchy") > -1, "Expected an exception to be thrown");
}
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack2"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("_testFunction"), "Should not have polluted Object.prototype");
}
});
this.testCase({
name: "Try to update Object.prototype indirectly using defineProperty with HackClass and an object instance",
test: () => {
let a = {};
try {
dynamicProto(HackClass, a, (_self, base) => {
let self = <any>_self;
self._testFunction = () => {
QUnit.assert.fail("Should not be able to update Object.prototype");
}
Object.defineProperty(self, "__proto__", {
value: {
testHack: true
},
configurable: true,
enumerable: true
});
self.prototype = {
testHack2: true
};
});
} catch (e) {
QUnit.assert.ok(true, "Expected an exception to be thrown");
QUnit.assert.ok(e.message.indexOf("not in hierarchy") > -1, "Expected an exception to be thrown");
}
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack2"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("_testFunction"), "Should not have polluted Object.prototype");
}
});
this.testCase({
name: "Try to update Object.prototype directly with evil __proto__ with HackClass and an object instance",
test: () => {
let a = new HackClass();
dynamicProto(HackClass, a, (_self, base) => {
let self = <any>_self;
self._testFunction = () => {
QUnit.assert.fail("Should not be able to update Object.prototype");
}
self["__proto__['hacked']"] = {
testHack: true
};
self.prototype = {
testHack2: true
};
});
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack2"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("_testFunction"), "Should not have polluted Object.prototype");
}
});
this.testCase({
name: "Try to update Object.prototype indirectly using defineProperty with evil __proto__ with HackClass and an object instance",
test: () => {
let a = new HackClass();
dynamicProto(HackClass, a, (_self, base) => {
let self = <any>_self;
self._testFunction = () => {
QUnit.assert.fail("Should not be able to update Object.prototype");
}
Object.defineProperty(self, "__proto__['hacked']", {
value: {
testHack: true
},
configurable: true,
enumerable: true
});
self.prototype = {
testHack2: true
};
});
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack2"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("_testFunction"), "Should not have polluted Object.prototype");
}
});
this.testCase({
name: "Try to update Object.prototype directly with a HackClass instance",
test: () => {
let a = new HackClass()
dynamicProto(HackClass, a, (_self, base) => {
let self = <any>_self;
self._testFunction = () => {
QUnit.assert.fail("Should not be able to update Object.prototype");
}
self.__proto__ = {
testHack: true
};
self.prototype = {
testHack2: true
};
});
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack2"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("_testFunction"), "Should not have polluted Object.prototype");
}
});
this.testCase({
name: "Try to update Object.prototype indirectly using defineProperty with a HackClass instance",
test: () => {
let a = new HackClass();
dynamicProto(HackClass, a, (_self, base) => {
let self = <any>_self;
self._testFunction = () => {
QUnit.assert.fail("Should not be able to update Object.prototype");
}
Object.defineProperty(self, "__proto__", {
value: {
testHack: true
},
configurable: true,
enumerable: true
});
self.prototype = {
testHack2: true
};
});
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack2"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("_testFunction"), "Should not have polluted Object.prototype");
}
});
this.testCase({
name: "Try to update Object.prototype indirectly with a null prototype instance",
test: () => {
let a: any = {};
let theInstance = Object.create(a);
try {
dynamicProto(theInstance, a, (_self, base) => {
_self.__proto__ = {
testHack: true
};
_self.prototype = {
testHack2: true
};
_self._testFunction = () => {
QUnit.assert.fail("Should not be able to update Object.prototype");
}
});
QUnit.assert.fail("Should not be able to update Object.prototype");
} catch (e) {
QUnit.assert.ok(true, "Expected an exception to be thrown");
}
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack2"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("_testFunction"), "Should not have polluted Object.prototype");
}
});
this.testCase({
name: "Try to update Object.prototype indirectly with an a prototype instance",
test: () => {
let a: any = {};
let theInstance = Object.create(a);
try {
dynamicProto(Object.getPrototypeOf(theInstance), a, (_self, base) => {
_self._testFunction = () => {
QUnit.assert.fail("Should not be able to update Object.prototype");
}
});
QUnit.assert.fail("Should not be able to update Object.prototype");
} catch (e) {
QUnit.assert.ok(true, "Expected an exception to be thrown");
}
QUnit.assert.ok(!Object.prototype.hasOwnProperty("_testFunction"), "Should not have polluted Object.prototype");
}
});
this.testCase({
name: "Try to update Object.prototype indirectly by using a proxy to return the Object.prototype as the instance functions",
test: () => {
let a = new HackClass();
dynamicProto(HackClass, a, (_self, base) => {
_self["_dynInstFuncs"] = new Proxy(_self["_dynInstFuncs"] || {}, {
get: (target, prop) => {
if (typeof prop === "string" && prop.startsWith("_dynCls")) {
return Object.prototype;
}
return target[prop];
}
});
(_self as any)._testFunction = () => {
QUnit.assert.fail("Should not be able to update Object.prototype");
}
});
QUnit.assert.ok(!Object.prototype.hasOwnProperty("_testFunction"), "Should not have polluted Object.prototype");
}
});
this.testCase({
name: "Try to update Object.prototype indirectly by using a proxy to return the Object.prototype as the instance functions",
test: () => {
let a = new HackClass();
dynamicProto(HackClass, a, (_self, base) => {
let className = _self["_dynClass"];
let classProto = _self["_dynInstFuncs"] = (_self["_dynInstFuncs"] || {});
// Change the return class prototype to be Object.prototype
classProto["_dynCls" + className] = Object.prototype;
(_self as any)._testFunction = () => {
QUnit.assert.fail("Should not be able to update Object.prototype");
}
});
QUnit.assert.ok(!Object.prototype.hasOwnProperty("_testFunction"), "Should not have polluted Object.prototype");
}
});
this.testCase({
name: "Try to update Object.prototype indirectly by using a HackClass and updating the base class prototype",
test: () => {
let a = new HackClass();
dynamicProto(HackClass, a, (_self, base) => {
try {
objGetPrototypeOf(base).testHack = true;
QUnit.assert.fail("Should not be able to update Object.prototype");
} catch (e) {
QUnit.assert.ok(true, "Expected an exception to be thrown");
}
(_self as any)._testFunction = () => {
QUnit.assert.fail("Should not be able to update Object.prototype");
}
});
QUnit.assert.ok(!Object.prototype.hasOwnProperty("_testFunction"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("testHack"), "Should not have polluted Object.prototype");
}
});
this.testCase({
name: "Try to update Array.prototype indirectly by using a proxy to return the Array.prototype as the instance functions",
test: () => {
let a = new HackClass();
dynamicProto(HackClass, a, (_self, base) => {
_self["_dynInstFuncs"] = new Proxy(_self["_dynInstFuncs"] || {}, {
get: (target, prop) => {
if (typeof prop === "string" && prop.startsWith("_dynCls")) {
return Array.prototype;
}
return target[prop];
}
});
(_self as any)._testFunction = () => {
QUnit.assert.fail("Should not be able to update Array.prototype");
}
});
QUnit.assert.ok(!Array.prototype.hasOwnProperty("_testFunction"), "Should not have polluted Array.prototype");
}
});
this.testCase({
name: "Try to update Array.prototype indirectly by using a proxy to return the Object.prototype as the instance functions",
test: () => {
let a = new HackClass();
dynamicProto(HackClass, a, (_self, base) => {
let className = _self["_dynClass"];
let classProto = _self["_dynInstFuncs"] = (_self["_dynInstFuncs"] || {});
// Change the return class prototype to be Object.prototype
classProto["_dynCls" + className] = Array.prototype;
(_self as any)._testFunction = () => {
QUnit.assert.fail("Should not be able to update Array.prototype");
}
});
QUnit.assert.ok(!Array.prototype.hasOwnProperty("_testFunction"), "Should not have polluted Array.prototype");
}
});
this.testCase({
name: "Try to update Object.prototype with a BadInstClass instance",
test: () => {
let a = new BadInstClass();
dynamicProto(BadInstClass, a, (_self, base) => {
(_self as any)._testFunction = () => {
QUnit.assert.fail("Should not be able to update Object.prototype");
}
});
QUnit.assert.ok(!Object.prototype.hasOwnProperty("_testFunction"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("_dynInstFuncs"), "Should not have polluted Object.prototype");
}
});
this.testCase({
name: "Try to update Object.prototype with a BadProxyInstClass instance",
test: () => {
let a = new BadProxyInstClass();
dynamicProto(BadProxyInstClass, a, (_self, base) => {
(_self as any)._testFunction = () => {
QUnit.assert.fail("Should not be able to update Object.prototype");
}
});
QUnit.assert.ok(!Object.prototype.hasOwnProperty("_testFunction"), "Should not have polluted Object.prototype");
QUnit.assert.ok(!Object.prototype.hasOwnProperty("_dynInstFuncs"), "Should not have polluted Object.prototype");
}
});
}
}

Просмотреть файл

@ -2,10 +2,12 @@ import { DynamicProtoDefaultTests } from '../DynamicProto.Tests';
import { DynamicProtoMultipleCallTests } from '../DynamicProtoMultipleCall.Tests';
import { DynamicProtoNoInstTests } from '../DynamicProtoNoInst.Tests';
import { DynamicProtoMultipleNoInstTests } from '../DynamicProtoMultipleNoInst.Tests';
import { SecurityCheckTests } from '../SecurityCheck.Tests';
export function runTests() {
new DynamicProtoDefaultTests("Default").registerTests();
new DynamicProtoMultipleCallTests("Multiple").registerTests();
new DynamicProtoNoInstTests("SetInst").registerTests();
new DynamicProtoMultipleNoInstTests("Multiple SetInst").registerTests();
new SecurityCheckTests("Security Checks").registerTests();
}

Просмотреть файл

@ -27,7 +27,8 @@
"fullClean": "git clean -xdf && npm install && rush update --recheck --purge --full",
"fullCleanBuild": "npm run fullClean && npm run build",
"npm_pack": "copyfiles README.md LICENSE lib && cd lib && npm pack",
"npm_publish": "cd lib && node ../tools/release-tools/npm_publish.js ."
"npm_publish": "cd lib && node ../tools/release-tools/npm_publish.js .",
"serve": "grunt serve"
},
"repository": {
"type": "git",
@ -41,7 +42,7 @@
},
"homepage": "https://github.com/microsoft/DynamicProto-JS#readme",
"dependencies": {
"@nevware21/ts-utils": ">= 0.9.4 < 2.x"
"@nevware21/ts-utils": ">= 0.10.4 < 2.x"
},
"devDependencies": {
"@microsoft/rush": "5.82.1",
@ -57,6 +58,7 @@
"eslint-plugin-security": "^1.4.0",
"grunt": "^1.5.3",
"grunt-cli": "^1.4.3",
"grunt-contrib-connect": "^3.0.0",
"grunt-contrib-qunit": "^4.0.0",
"grunt-contrib-uglify": "^5.0.1",
"grunt-run": "^0.8.1",

Просмотреть файл

@ -34,7 +34,7 @@
},
"homepage": "https://github.com/microsoft/DynamicProto-JS#readme",
"dependencies": {
"@nevware21/ts-utils": ">= 0.9.4 < 2.x"
"@nevware21/ts-utils": ">= 0.10.4 < 2.x"
},
"devDependencies": {
"grunt": "^1.5.3",