shadow-function
Version:
ioing lib - shadow Function, worker Function
1,250 lines (1,237 loc) • 55.1 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var windowOwnPropertyNames = [
'Object',
'Function',
'Array',
'Number',
'parseFloat',
'parseInt',
'Infinity',
'NaN',
'undefined',
'Boolean',
'String',
'Symbol',
'Date',
'Promise',
'RegExp',
'Error',
'EvalError',
'RangeError',
'ReferenceError',
'SyntaxError',
'TypeError',
'URIError',
'JSON',
'Math',
'console',
'Intl',
'ArrayBuffer',
'Uint8Array',
'Int8Array',
'Uint16Array',
'Int16Array',
'Uint32Array',
'Int32Array',
'Float32Array',
'Float64Array',
'Uint8ClampedArray',
'BigUint64Array',
'BigInt64Array',
'DataView',
'Map',
'BigInt',
'Set',
'WeakMap',
'WeakSet',
'Proxy',
'Reflect',
'decodeURI',
'decodeURIComponent',
'encodeURI',
'encodeURIComponent',
'escape',
'unescape',
'eval',
'isFinite',
'isNaN',
'TreeWalker',
'SVGAElement',
'Range',
'NodeList',
'NodeIterator',
'NodeFilter',
'Node',
'Element',
'HTMLElement',
'document',
'innerheight',
'innerwidth',
'outerheight',
'outerwidth',
'pageXOffset',
'pageYOffset',
'addEventListener',
'removeEventListener',
'dispatchEvent',
'Screen',
'alert',
'clearInterval',
'clearTimeout',
'valueOf',
'confirm',
'scrollTo',
'setInterval',
'setTimeout',
'toString',
'Float32Array',
'Proxy',
'EventTarget',
'hasOwnProperty',
'isPrototypeOf',
'toLocaleString',
'propertyIsEnumerable',
'__proto__',
'__defineGetter__',
'__lookupGetter__',
'__defineSetter__',
'__lookupSetter__'
];
var Sandbox = /** @class */ (function () {
function Sandbox(white, properties, setting) {
if (white === void 0) { white = false; }
if (properties === void 0) { properties = ['*']; }
if (setting === void 0) { setting = 'allow-scripts allow-same-origin'; }
this.windowOwnPropertyNames = windowOwnPropertyNames;
var sandbox = this.sandbox = document.createElement('iframe');
sandbox.src = 'about:blank';
sandbox.style.display = 'none';
this.windowOwnPropertyNames = this.windowOwnPropertyNames.concat(properties);
this.white = white;
this.set(setting);
this.enter();
this.shadow();
if (!white)
this.exit();
return this;
}
Sandbox.getWindowOwnPropertyNames = function () {
return windowOwnPropertyNames;
};
Sandbox.debugger = function (isee, model) {
if (model === void 0) { model = { 'safe-context': 'safe' }; }
var msg = 'I know the danger!';
if (isee === msg) {
this.prototype['open debugger'] = true;
if (model['safe-context'] === 'unsafe') {
this.prototype['unsafe-context'] = true;
}
else {
console.warn("%c Sandbox: Opening the 'debugger' will result in a risk of losing security!", 'font-size: 32px; color: red');
}
}
else {
console.log("Sandbox: Opening 'debugger' input '" + msg + "'");
}
};
Sandbox.prototype.shadow = function () {
var contentWindow = this.sandbox.contentWindow;
var contentDocument = this.sandbox.contentDocument;
this.window = contentWindow;
this.content = this.document = contentDocument;
if (this.white)
return this;
var globalProperty = this.getProtoProperty(this.window);
var ShadowObject = this.window.Object;
var allowAllProperty = ~this.windowOwnPropertyNames.indexOf('*');
this.shadowWindow = new contentWindow.Object();
var _loop_1 = function (k) {
if (this_1.window[k] + '' !== '[object Window]' && (allowAllProperty || ~this_1.windowOwnPropertyNames.indexOf(k))) {
this_1.shadowWindow[k] = this_1.window[k];
}
else {
try {
ShadowObject.defineProperty(this_1.shadowWindow, k, {
configurable: true,
enumerable: true,
writable: true,
get: function () {
console.error("Sandbox Error: Unauthorized use of window['" + k + "'].");
return null;
}
});
this_1.delProtoProperty(this_1.window, k);
}
catch (e) {
//
}
}
};
var this_1 = this;
for (var _i = 0, globalProperty_1 = globalProperty; _i < globalProperty_1.length; _i++) {
var k = globalProperty_1[_i];
_loop_1(k);
}
this.shadowWindow.shadowWindow = this.shadowWindow;
this.shadowWindow.window = this.shadowWindow;
return this;
};
Sandbox.prototype.getProtoProperty = function (object) {
var propertyNames = Object.getOwnPropertyNames(object);
if (object['__proto__'])
return propertyNames.concat(this.getProtoProperty(object['__proto__']));
return propertyNames;
};
Sandbox.prototype.delProtoProperty = function (object, name) {
if (!object)
return false;
if (object['__proto__']) {
if (object['__proto__'].hasOwnProperty(name)) {
return delete object['__proto__'][name];
}
else {
return this.delProtoProperty(object['__proto__'], name);
}
}
else {
return delete object[name];
}
};
Sandbox.prototype.set = function (allow) {
this.sandbox.setAttribute('sandbox', allow);
};
Sandbox.prototype.reset = function (allow) {
this.exit();
this.set(allow);
this.enter();
this.shadow();
return this;
};
Sandbox.prototype.open = function () {
this.content.open();
return this;
};
Sandbox.prototype.write = function (context) {
if (context === void 0) { context = '<head><meta charset="utf-8"></head>'; }
this.content.write(context);
return this;
};
Sandbox.prototype.close = function () {
this.content.close();
return this;
};
Sandbox.prototype.enter = function () {
var documentElement = document.documentElement;
documentElement.appendChild(this.sandbox);
};
Sandbox.prototype.exit = function () {
if (this['open debugger'])
return;
var parentNode = this.sandbox.parentNode;
parentNode && parentNode.removeChild(this.sandbox);
};
return Sandbox;
}());
var getObjectType = function (object) {
var objectStr = Object.prototype.toString.call(object);
var objectType = (/\s*\[(\w+) (\w+)\]\s*/.exec(objectStr) || []);
switch (objectType[1]) {
case 'object':
return objectType[2];
case 'native':
return 'native';
}
return 'unknow';
};
var allowProtoProperties = {
Node: [
'nodeName',
'nodeType',
'textContent'
],
Element: [
'style',
'onblur',
'onfocus',
'onscroll',
'offsetWidth',
'offsetHeight',
'clientWidth',
'clientHeight',
'innerText',
'setAttribute',
'removeAttribute',
'createTextNode',
'addEventListener',
'getElementsByTagName'
],
HTMLElement: [],
HTMLBodyElement: [],
HTMLDivElement: [],
HTMLUListElement: [],
HTMLLIElement: [],
HTMLVideoElement: [],
HTMLAudioElement: [],
HTMLSelectElement: [],
HTMLOptionElement: [],
HTMLInputElement: [],
HTMLSpanElement: [],
HTMLDListElement: [],
HTMLFontElement: [],
HTMLHeadingElement: [],
HTMLParagraphElement: [],
HTMLDocument: [
'documentElement',
'body'
],
Navigator: [
'appCodeName',
'appName',
'appVersion',
'language',
'languages',
'maxTouchPoints',
'onLine',
'platform',
'product',
'productSub',
'userAgent',
'vendor',
'vendorSub'
],
UserActivation: [
'hasBeenActive',
'isActive'
],
Promise: [
'then',
'catch',
'resolve'
],
Touch: [
'clientX',
'clientY',
'force',
'identifier',
'pageX',
'pageY',
'radiusX',
'radiusY',
'rotationAngle',
'screenX',
'screenY',
'target'
],
TouchEvent: [
'altKey',
'bubbles',
'cancelBubble',
'cancelable',
'changedTouches',
'composed',
'ctrlKey',
'currentTarget',
'defaultPrevented',
'detail',
'eventPhase',
'metaKey',
'returnValue',
'shiftKey',
'sourceCapabilities',
'targetTouches',
'timeStamp',
'touches',
'type',
'which'
],
MouseEvent: [
'altKey',
'bubbles',
'button',
'buttons',
'cancelBubble',
'cancelable',
'clientX',
'clientY',
'composed',
'ctrlKey',
'defaultPrevented',
'detail',
'eventPhase',
'fromElement',
'getModifierState',
'initMouseEvent',
'layerX',
'layerY',
'metaKey',
'movementX',
'movementY',
'offsetX',
'offsetY',
'pageX',
'pageY',
'relatedTarget',
'returnValue',
'screenX',
'screenY',
'shiftKey',
'sourceCapabilities',
'timeStamp',
'type',
'which',
'x',
'y'
]
};
// ShadowFunction
var ShadowFunction = /** @class */ (function () {
function ShadowFunction() {
var _this = this;
this.sandbox = new Sandbox(false, this['allow properties'] || ['*']);
this.shadowWindow = this.sandbox.shadowWindow;
this.ShadowFunction = this.shadowWindow.Function;
this.shadowHasOwnProperty = this.shadowWindow.Object.hasOwnProperty;
this.ShadowObject = this.shadowWindow.Object;
this.ShadowProxy = this.shadowWindow.Proxy;
this.allowProtoProperties = allowProtoProperties;
this.run = function () { return null; };
this.tracker = function (e) {
if (typeof (e.name) === 'symbol' || !isNaN(Number(e.name)))
return 'no';
switch (e.name) {
case 'length':
case '__proto__':
break;
default:
return _this.log(e);
}
return 'no';
};
this.freezeShadowProto(this.shadowWindow);
}
ShadowFunction.prototype.log = function (e) {
return console.log('Event Log:', e);
};
ShadowFunction.debugger = function (isee, model) {
if (model === void 0) { model = { 'no-Proxy': false }; }
var msg = 'I know the danger!';
if (isee === msg) {
this.prototype['open debugger'] = true;
if (model['no-Proxy']) {
this.prototype['open debugger: no-Proxy'] = true;
}
if (Sandbox.prototype['unsafe-context'] !== true) {
console.warn("%c ShadowFunction: Opening the 'debugger' will result in a risk of losing security!", 'font-size: 32px; color: red');
}
}
else {
console.log("ShadowFunction: Opening 'debugger' input '" + msg + "'");
}
};
ShadowFunction.assignContextProperties = function (names) {
if (names === void 0) { names = ['*']; }
this.prototype['allow properties'] = names;
};
ShadowFunction.prototype.setAllowProtoProperties = function (allowProperties) {
Object.assign(this.allowProtoProperties, allowProperties);
return this.preShadowFunction.bind(this);
};
ShadowFunction.prototype.freezeShadowProto = function (object) {
var Object = this.ShadowObject;
var propNames = Object.getOwnPropertyNames(object);
// Freeze properties before freezing self
for (var _i = 0, propNames_1 = propNames; _i < propNames_1.length; _i++) {
var name_1 = propNames_1[_i];
var value = object[name_1];
if (!value)
break;
if (!(Object.getOwnPropertyDescriptor(object, name_1) || {}).writable)
break;
typeof value === 'object' && this.freezeShadowProto(value);
}
if (!Object.isFrozen(object['prototype']))
Object.freeze(object['prototype']);
};
ShadowFunction.prototype.getAllowProperties = function (object) {
return this.getAllowProtoProperties(object).concat(Object.getOwnPropertyNames(object));
};
ShadowFunction.prototype.getAllowProtoProperties = function (object) {
var propertyNames = this.allowProtoProperties[getObjectType(object)] || [];
if (object['__proto__'])
return propertyNames.concat(this.getAllowProtoProperties(object['__proto__']));
return propertyNames;
};
ShadowFunction.prototype.isElementObject = function (value) {
if (/HTML(\w+)?Element/.exec(getObjectType(value)))
return true;
return false;
};
ShadowFunction.prototype.isFixedObject = function (value) {
if (this.isElementObject(value))
return false;
return typeof value === 'object';
};
ShadowFunction.prototype.safeGetter = function (origin, target, name) {
if (this['open debugger'] && name === '...') {
console.warn("ShadowFunction: Unsafe return in debug mode\uFF01");
return origin;
}
if (this.getAllowProperties(origin).indexOf(name) === -1) {
this.tracker({
origin: origin,
name: name,
action: 'read'
});
return target[name];
}
if (origin[name] && !this.isFixedObject(origin[name]) && origin[name].hasOwnProperty === this.shadowHasOwnProperty) {
return origin[name];
}
return this.proxy(origin[name], origin);
};
ShadowFunction.prototype.safeSetter = function (origin, target, name, value) {
target[name] = this.proxy(value, target);
if (this.tracker({
origin: origin,
name: name,
action: 'write',
value: value
}) === "allow set " + name)
origin[name] = target[name];
return true;
};
ShadowFunction.prototype.puppet = function (origin) {
var _this = this;
var Proxy = this.ShadowProxy;
var propNames = Object.getOwnPropertyNames(origin);
var puppet = new this.ShadowObject();
propNames.map(function (name) {
if ((Object.getOwnPropertyDescriptor(puppet, name) || { writable: true }).writable)
puppet[name] = '...';
});
return new Proxy(puppet, {
get: function (target, name) {
return _this.safeGetter(origin, target, name);
},
set: function (target, name, value) {
return _this.safeSetter(origin, target, name, value);
}
});
};
ShadowFunction.prototype.proxy = function (target, self) {
if (self === void 0) { self = null; }
if (this['open debugger: no-Proxy'] || !target)
return target;
switch (typeof (target)) {
case 'string':
case 'number':
case 'boolean':
case 'undefined':
return target;
case 'function':
return this.safeReturnFunction(target, self);
case 'object':
return this.puppet(target);
}
return;
};
ShadowFunction.prototype.safeReturnFunction = function (fn, origin) {
var shadowFunction = new this.ShadowFunction('fn', 'origin', 'proxy', "\n return (function () {\n return function () {\n return proxy(fn.apply(origin, proxy(arguments)))\n }\n })()\n ")(fn, origin, this.proxy.bind(this));
var propNames = Object.getOwnPropertyNames(fn);
for (var _i = 0, propNames_2 = propNames; _i < propNames_2.length; _i++) {
var name_2 = propNames_2[_i];
if ((Object.getOwnPropertyDescriptor(fn, name_2) || { writable: true }).writable) {
if (name_2 === 'prototype')
continue;
shadowFunction[name_2] = this.proxy({ 0: fn[name_2] })[0];
}
}
return shadowFunction;
};
ShadowFunction.prototype.preShadowFunction = function (scriptStr) {
this.shadowFunction = new this.ShadowFunction("\n (function () {\n with (arguments[0].window || {}) {\n with (arguments[0].context || {}) {\n (function () {"
+ scriptStr +
"}).bind(Object.assign(arguments[0].window || {}, arguments[0].context || {}))()\n }\n }\n })(this)");
return this.runShadowFunction.bind(this);
};
ShadowFunction.prototype.runShadowFunction = function (origin) {
var target = this.proxy(origin);
var shadowFunction = this.shadowFunction;
shadowFunction.apply(this.ShadowObject.assign(new this.ShadowObject(), { window: this.shadowWindow, context: target }));
return {
run: this.preShadowFunction.bind(this),
proxy: this.proxy.bind(this),
sandbox: this.sandbox
};
};
return ShadowFunction;
}());
var shadowFunction = function (code, setting, log) {
var sfnc = new ShadowFunction();
if (log)
sfnc.log = log;
if (setting) {
sfnc.run = sfnc.setAllowProtoProperties(setting)(code);
}
else {
switch (typeof (code)) {
case 'object':
sfnc.run = sfnc.setAllowProtoProperties(code);
break;
case 'string':
sfnc.run = sfnc.preShadowFunction(code);
break;
default:
throw new Error('ShadowFunction: Uncaught SyntaxError: Unexpected identifier.');
}
}
return sfnc.run;
};
shadowFunction.debugger = ShadowFunction.debugger.bind(ShadowFunction);
var DOCUMENT = document;
var constructorId = 0;
// ShadowDocument
var ShadowDocument = /** @class */ (function () {
function ShadowDocument(root, template, setting, log) {
if (setting === void 0) { setting = [{}, {}]; }
var _this = this;
this.run = function () { return null; };
this.constructorId = 0;
this.o = 0;
this.allowTagName = {
'DIV': true,
'B': true,
'P': true,
'H1': true,
'H2': true,
'H3': true,
'H4': true,
'H5': true,
'DL': true,
'DT': true,
'DD': true,
'EM': true,
'HR': true,
'UL': true,
'LI': true,
'OL': true,
'TD': true,
'TH': true,
'TR': true,
'TT': true,
'NAV': true,
'SUP': true,
'SUB': true,
'SPAN': true,
'FONT': true,
'BR': true,
'STYLE': true,
'SMALL': true,
'LABEL': true,
'TABLE': true,
'TBODY': true,
'THEAD': true,
'TFOOT': true,
'BUTTON': true,
'FOOTER': true,
'HEADER': true,
'STRONG': true
};
this.tracker = function (e) {
if (typeof (_this.log) === 'function') {
_this.log(e);
}
else {
console.log('Event Log:', e);
}
};
this.getRealElement = function (element) {
return _this.TREE[element['uuid']] || new Error("ShadowFunction: Cannot synchronously read compiled style. Async read after the rendering ends / or use '<HTMLElement>.oncomputed = () => { element.offsetTop }'\uFF01");
};
this.TREE = {
0: root.attachShadow ? root.attachShadow({ mode: 'open' }) : root
};
this.SHADOWTREE = {};
Object.assign(this.allowTagName, setting[0] || setting);
this.log = log;
this.constructorId = constructorId++;
this.shadowFunction = new shadowFunction(setting[1] || {}, undefined, log);
this.shadowFunction = this.shadowFunction(this.injection())(this.empowerment());
this.sandbox = this.shadowFunction.sandbox;
this.shadowWindow = this.sandbox.shadowWindow;
this.shadowDocumentBody = this.shadowWindow.document.body;
this.ShadowObject = this.shadowWindow.Object;
this.ShadowNode = this.shadowWindow.Node;
this.ShadowElement = this.shadowWindow.Element;
this.shadowGetAttribute = this.ShadowElement['prototype'].getAttribute;
this.setShadowObserver();
this.write(template);
this.run = this.shadowFunction.run.bind(this);
}
ShadowDocument.prototype.empowerment = function () {
var _this = this;
return {
getShadowElement: function (element) {
return _this.getRealElement(element);
},
getShadowElementProps: function (element, propsName) {
return _this.getRealElement(element)[propsName];
},
getComputedStyle: function (element, pseudoElt) {
if (pseudoElt === void 0) { pseudoElt = null; }
return getComputedStyle(_this.getRealElement(element), pseudoElt);
},
setShadowEventListener: function (listener, type, callback, opt) {
var target = null;
var eventName = 'on-shadow-' + type + '-' + _this.constructorId;
switch (listener) {
case '[object Window]':
target = window;
break;
case '[object HTMLDocument]':
target = document;
break;
case '[object HTMLBodyElement]':
target = document.body;
break;
case '[object HTMLHtmlElement]':
target = document.documentElement;
break;
}
if (!target)
return;
if (!callback)
return target.removeEventListener(type, target[eventName]);
Object.defineProperty(target, eventName, {
enumerable: false,
configurable: true,
writable: false,
value: function (e) {
callback.apply(callback, [_this.createShadowEventObject(e)]);
}
});
target.addEventListener(type, target[eventName], opt);
}
};
};
ShadowDocument.prototype.isElementObject = function (value) {
if (/HTML(\w+)?Element/.exec(getObjectType(value)))
return true;
return false;
};
ShadowDocument.prototype.createShadowEventObject = function (originEvent) {
var target = {};
for (var key in originEvent) {
var value = originEvent[key];
switch (typeof value) {
case 'string':
case 'number':
case 'boolean':
case 'undefined':
target[key] = value;
break;
case 'function':
target[key] = value.bind(originEvent);
break;
case 'object':
switch (key) {
case 'changedTouches':
case 'sourceCapabilities':
case 'targetTouches':
case 'touches':
target[key] = this.createShadowEventObject(value);
break;
case 'srcElement':
case 'target':
case 'toElement':
if (this.isElementObject(value))
target[key] = this.SHADOWTREE[value.uuid];
break;
default:
if (!isNaN(Number(key))) {
target[key] = this.createShadowEventObject(value);
}
else {
target[key] = value;
}
break;
}
break;
}
}
return target;
};
ShadowDocument.prototype.injection = function () {
return "\n window.addEventListener = EventTarget.prototype.addEventListener = function (type, callback, options) {\n var target = this\n var targetTypeName = Object.prototype.toString.call(target)\n if (!target['onShadowEventNames']) {\n Object.defineProperty(target, 'onShadowEventNames', {\n enumerable: false,\n configurable: true,\n writable: true,\n value: [type]\n })\n } else {\n target['onShadowEventNames'].push(type)\n }\n if (!target['onshadow' + type]) {\n Object.defineProperty(target, 'onshadow' + type, {\n enumerable: false,\n configurable: true,\n writable: true,\n value: {\n type: type,\n options: options,\n callback: [callback]\n }\n })\n setShadowEventListener(targetTypeName, type, function () {\n var args = arguments\n target['onshadow' + type].callback.map(function (fn) {\n fn.apply(target, args)\n })\n }, options)\n } else {\n target['onshadow' + type].callback.push(callback)\n }\n }\n window.removeEventListener = EventTarget.prototype.removeEventListener = function (type, callback, options) {\n var target = this\n var targetTypeName = Object.prototype.toString.call(target)\n var callbackIndex = this['onshadow' + type].callback.indexOf(callback)\n var eventNameIndex = this['onShadowEventNames'].indexOf(type)\n if (eventNameIndex !== -1) {\n this['onShadowEventNames'].splice(eventNameIndex, 1)\n }\n if (callbackIndex !== -1) {\n this['onshadow' + type].callback.splice(callbackIndex, 1)\n }\n if (this['onshadow' + type].callback.length === 0) {\n setShadowEventListener(targetTypeName, type)\n }\n }\n shadowWindow.Object.defineProperties(shadowWindow.HTMLElement.prototype, {\n 'offsetHeight': {\n get () {\n return getShadowElementProps(this, 'offsetHeight')\n }\n },\n 'offsetWidth': {\n get () {\n return getShadowElementProps(this, 'offsetWidth')\n }\n },\n 'offsetTop': {\n get () {\n return getShadowElementProps(this, 'offsetTop')\n }\n },\n 'offsetLeft': {\n get () {\n return getShadowElementProps(this, 'offsetLeft')\n }\n },\n 'offsetParent': {\n get () {\n return getShadowElementProps(this, 'offsetParent')\n }\n },\n 'ref': {\n get () {\n return getShadowElement(this)\n }\n }\n })\n ";
};
ShadowDocument.prototype.setShadowObserver = function () {
var _this = this;
new MutationObserver(function (records) {
var _loop_1 = function (record) {
var target = record.target;
switch (record.type) {
case 'attributes':
_this.setAttribute(record.attributeName, target);
break;
case 'characterData':
_this.setCharacterData(target);
break;
case 'childList':
Array.prototype.forEach.call(record.removedNodes, function (node) {
_this.walker(_this.iterator(node), target, true);
});
Array.prototype.forEach.call(record.addedNodes, function (node) {
_this.walker(_this.iterator(node), target);
});
break;
}
};
for (var _i = 0, records_1 = records; _i < records_1.length; _i++) {
var record = records_1[_i];
_loop_1(record);
}
}).observe(this.shadowDocumentBody, {
subtree: true,
attributes: true,
childList: true,
characterData: true,
attributeOldValue: true,
characterDataOldValue: true
});
};
ShadowDocument.prototype.write = function (template) {
this.shadowDocumentBody.innerHTML = "<div>" + template + "</div>";
};
ShadowDocument.prototype.uuid = function (node, uuid) {
uuid = parseInt(node.parentNode ? node.parentNode.uuid || 0 : 0, 10);
uuid++;
this.o++;
uuid = uuid + '.' + this.o;
if (!node.uuid) {
this.ShadowObject.defineProperty(node, 'uuid', {
configurable: false,
enumerable: false,
value: uuid
});
this.SHADOWTREE[uuid] = node;
}
return uuid;
};
ShadowDocument.prototype.iterator = function (nodes) {
if (nodes.nextNode)
return nodes;
return DOCUMENT.createNodeIterator(nodes, NodeFilter.SHOW_ALL, null);
};
ShadowDocument.prototype.walker = function (nodes, target, del) {
if (del === void 0) { del = false; }
var node = nodes.nextNode();
while (node) {
this.uuid(node);
switch (node.nodeType) {
case Node.ELEMENT_NODE:
if (del) {
this.removeElement(node, target);
}
else {
this.createElement(node, target);
}
break;
case Node.TEXT_NODE:
if (del) {
this.removeTextNode(node, target);
}
else {
this.createTextNode(node, target);
}
break;
}
node = nodes.nextNode();
if (!node)
break;
}
};
ShadowDocument.prototype.getParentId = function (node, target) {
return (node.parentNode ? node.parentNode['uuid'] : target['uuid']) || 0;
};
ShadowDocument.prototype.createElement = function (node, target) {
var uuid = node['uuid'];
var name = this.ShadowNode['prototype'].cloneNode.call(node).nodeName;
var puuid = this.getParentId(node, target);
if (this.TREE[uuid])
return;
switch (name) {
case this.allowTagName[name] ? name : null:
this.TREE[uuid] = DOCUMENT.createElement(name);
this.TREE[uuid].uuid = uuid;
break;
default:
this.tracker({
tagName: name,
action: 'createElement'
});
throw new Error("ShadowFunction: The tag name provided ('" + name + "') is not a valid name of whitelist.");
}
for (var i = 0; i < node.attributes.length; i++) {
this.setAttribute(node.attributes[i].name, node);
}
node['completedState'] = 'complete';
this.TREE[puuid].appendChild(this.TREE[uuid]);
this.createEvent(node);
this.shadowFunction.run("\n typeof computed === 'function' && computed(el)\n ")({
el: this.TREE[uuid],
computed: node['oncomputed']
});
};
ShadowDocument.prototype.removeElement = function (node, target) {
var uuid = node['uuid'];
var puuid = this.getParentId(node, target);
if (this.TREE[puuid] && this.TREE[uuid]) {
this.TREE[puuid].removeChild(this.TREE[uuid]);
}
delete this.TREE[uuid];
};
ShadowDocument.prototype.createTextNode = function (node, target) {
var uuid = node['uuid'];
var puuid = this.getParentId(node, target);
var text = node.textContent || '';
if (this.TREE[uuid])
return;
this.TREE[uuid] = DOCUMENT.createTextNode(text);
this.TREE[uuid].uuid = uuid;
if (this.TREE[puuid]) {
this.TREE[puuid].appendChild(this.TREE[uuid]);
}
};
ShadowDocument.prototype.removeTextNode = function (node, target) {
var uuid = node['uuid'];
var puuid = this.getParentId(node, target);
if (this.TREE[puuid] && this.TREE[uuid]) {
this.TREE[puuid].removeChild(this.TREE[uuid]);
}
delete this.TREE[uuid];
};
ShadowDocument.prototype.createEvent = function (node) {
var _this = this;
var onEvent = node['onShadowEventNames'];
if (!onEvent)
return;
onEvent.map(function (type) {
var shadowEvent = node['onshadow' + type];
if (shadowEvent) {
_this.TREE[node['uuid']].addEventListener(shadowEvent.type, function (event) {
event = _this.createShadowEventObject(event);
_this.shadowFunction.run("\n for (let i = 0; i < events.length; i++) {\n typeof(events[i]) === 'function' && events[i].apply(node, args)\n }\n ")({ events: shadowEvent.callback.map(function (fn) { return fn.bind(node); }), node: node, args: [event] });
}, shadowEvent.options);
}
});
};
ShadowDocument.prototype.setAttribute = function (name, node) {
var whiteNode = this.TREE[node['uuid']];
var shadowNode = this.ShadowNode['prototype'].cloneNode.call(node);
var tagName = shadowNode.tagName;
var allow = this.allowTagName[tagName];
var value = this.shadowGetAttribute.call(shadowNode, name);
var safeAttr = false;
if (!whiteNode)
return;
switch (name) {
case 'id':
case 'name':
case 'style':
case 'class':
case 'width':
case 'height':
safeAttr = true;
break;
default:
if (typeof (allow) === 'function' && allow(name, value)) {
safeAttr = true;
}
else {
this.tracker({
tagName: tagName,
attributeName: name,
action: 'setAttribute',
value: value
});
throw new Error("ShadowFunction: The attribute name provided ('" + name + " in <" + tagName.toLocaleLowerCase() + " />') is not a valid name of whitelist.");
}
break;
}
if (whiteNode && safeAttr)
whiteNode.setAttribute(name, value);
};
ShadowDocument.prototype.setCharacterData = function (node) {
var char = this.TREE[node.uuid];
if (char)
char.textContent = node.textContent;
};
return ShadowDocument;
}());
var shadowDocument = function (root, template, setting, log) {
if (setting === void 0) { setting = [{}, {}]; }
return new ShadowDocument(root, template, setting, log).run;
};
var BlackDocument = /** @class */ (function () {
function BlackDocument(template, root, csp, type) {
if (root === void 0) { root = document.body; }
if (csp === void 0) { csp = "default-src 'self';"; }
this.root = root;
this.create(template, csp, type);
// @ts-ignore
return this.run.bind(this);
}
BlackDocument.prototype.hashSource = function () {
return (new Array(8 + Math.round(Math.random() * 8))).join(',').split(',').map(function () {
return String.fromCharCode(97 + Math.round(Math.random() * 25));
}).join('');
};
BlackDocument.prototype.injectRequestParentAction = function (csp) {
var _this = this;
var hash = this.hashSource();
window.addEventListener('message', function (data) {
var result = data.data || {};
var method = result.method;
var params = result.params;
var postToSandbox = function (data) {
if (_this.sandbox.contentWindow) {
_this.sandbox.contentWindow.postMessage({
data: data,
key: method + ':' + JSON.stringify(params)
}, '*');
}
};
if (result.hash === hash) {
var func = _this.methods[method];
var promise = void 0;
if (typeof func === 'function') {
promise = func(params);
}
else {
promise = func;
}
if (promise instanceof Promise) {
promise.then(postToSandbox);
}
else {
postToSandbox(promise);
}
}
}, false);
return "\n <meta http-equiv=\"Content-Security-Policy\" content=\"" + csp + "\">\n <script>\n window.requestParentAction = function (method, params) {\n parent.postMessage({ method: method, params: params, hash: '" + hash + "' }, '" + location.origin + "')\n return new Promise(function (reslove, reject) {\n function callback (data) {\n if (data && data.data && data.data.data) {\n if (method + ':' + JSON.stringify(params) === data.data.key) {\n window.removeEventListener('message', callback)\n reslove(data.data.data)\n }\n } else {\n reject()\n }\n }\n window.addEventListener('message', callback)\n })\n }\n </script>\n ";
};
BlackDocument.prototype.create = function (template, csp, type) {
if (type === void 0) { type = 'fullscreen'; }
var iframe = document.createElement('iframe');
iframe.csp = csp;
iframe.src = URL.createObjectURL(new Blob([this.injectRequestParentAction(csp) + " ;\n " + template], { type: 'text/html' }));
iframe.setAttribute('sandbox', 'allow-scripts');
if (type === 'fullscreen')
iframe.setAttribute('style', "position: fixed; top: 0; right: 0; bottom: 0; left: 0; width: 100%; height: 100%");
this.sandbox = iframe;
};
BlackDocument.prototype.run = function (methods) {
this.methods = methods;
this.root.appendChild(this.sandbox);
};
return BlackDocument;
}());
function freeze(object, deep, exclude) {
if (deep === void 0) { deep = false; }
if (exclude === void 0) { exclude = {}; }
if (!object)
return;
exclude = getObjectType(exclude) === 'Object' ? exclude : {};
if (deep) {
var propNames = Object.getOwnPropertyNames(object);
// Freeze properties before freezing self
for (var _i = 0, propNames_1 = propNames; _i < propNames_1.length; _i++) {
var name_1 = propNames_1[_i];
var value = object[name_1];
var ignore = exclude[name_1];
if (!value)
break;
if (isFrozen(value))
break;
if (ignore)
break;
freeze(value.prototype, true, exclude);
freeze(value.__proto__, true, exclude);
var descriptor = Object.getOwnPropertyDescriptor(object, name_1) || {};
if (!descriptor.writable)
break;
object[name_1] = value && typeof value === 'object' ?
freeze(value, true) : value;
}
}
return Object.freeze(object);
}
function isFrozen(obj) {
return Object.isFrozen(obj);
}
var sandbox = new Sandbox();
var randPassword = function () {
var shadowString = sandbox.shadowWindow.String;
var shadowMath = sandbox.shadowWindow.Math;
var shadowArray = sandbox.shadowWindow.Array;
return (new shadowArray(8 + shadowMath.round(shadowMath.random() * 8))).join(',').split(',').map(function () {
return shadowString['fromCharCode'](33 + shadowMath.round(shadowMath.random() * 89));
}).join('');
};
var Strongbox = /** @class */ (function () {
function Strongbox(insurance, log) {
var _this = this;
this.password = randPassword();
this.tracker = function (e) {
if (typeof (_this.log) === 'function') {
_this.log(e);
}
else {
console.log('Event Log:', e);
}
};
var that = this;
var secretKey = this.password;
// tracker log
this.log = log;
var _loop_1 = function (insured) {
var object = insured[0];
var props = insured[1];
var value = object[props];
Object.defineProperty(object, props, {
get: function () {
that.password = secretKey = randPassword();
return function (password, setValue) {
if (password === secretKey) {
if (setValue) {
value = setValue;
}
else {
return value;
}
}
else {
var log_1 = {
object: object,
name: props,
action: 'read'
};
if (setValue) {
log_1.value = setValue;
log_1.action = 'write';
}
that.tracker(log_1);
return;
}
};
},
set: function () { return; },
enumerable: true,
configurable: false
});
freeze(object, true);
};
for (var _i = 0, insurance_1 = insurance; _i < insurance_1.length; _i++) {
var insured = insurance_1[_i];
_loop_1(insured);
}
return this;
}
Strongbox.prototype.lock = function () {
windowOwnPropertyNames.forEach(function (key) {
var type = typeof (window[key]);
if (type === 'object' || type === 'function') {
try {
switch (key) {
case 'window':
break;
default:
freeze(window[key], true);
break;
}
}
catch (_e) {
//
}
}
});
};
return Strongbox;
}());
var WorkerFunction = /** @class */ (function () {
function WorkerFunction(code) {
code = typeof (code) === 'string' ? code : typeof (code) === 'function' ? Object.toString.call(code) : '';
// code = `self.addEventListener('message', function (event) { ` + code + ` }, false)`
return new Worker(URL.createObjectURL(new Blob([code], { type: 'text/javascript' })));
}
return WorkerFunction;
}());
var TryAgain = /** @class */ (function () {
function TryAgain(task, options) {
this.task = task;
this.polls = options.polls || 2;
this.timeout = options.timeout || 3000;
this.timeoutId = null;
}
TryAgain.prototype.try = function () {
var _this = this;
if (this.polls <= 0)
return false;
this.timeoutId = setTimeout(function () {
if (_this.polls-- > 0)
_this.task() && _this.try();
}, this.timeout);
};
TryAgain.prototype.stop = function () {
clearTimeout(this.timeoutId);
};
TryAgain.prototype.wait = function (time) {
this.timeout = time;
};
TryAgain.prototype.over = function () {
this.stop();
this.polls = 0;
};
return TryAgain;
}());
var documentElement = document.documentElement;
var clearUnsafe = "\n function clearUnsafe (proto) {\n var props = Object.getOwnPropertyNames(proto)\n props.map(function (key) {\n try {\n proto[key] = null\n delete proto[key]\n } catch (e) {}\n })\n }\n clearUnsafe(Document.prototype)\n clearUnsafe(Function.prototype)\n clearUnsafe(Object.prototype)\n clearUnsafe(HTMLElement.prototype)\n clearUnsafe(Element.prototype)\n clearUnsafe(Node.prototype)\n clearUnsafe(String.prototype)\n clearUnsafe(window)\n";
var getShadowModule = function (url, options) {
if (options === void 0) { options = { receiver: '', timeout: 30000, dataType: 'module' }; }
return new Promise(function (resolve, reject) {
var dataType = options.dataType, receiver = options.receiver, timeout = options.timeout;
var iframe;
var tryObj;
var timeoutId;
timeout = timeout || 30000;
// 异常尝试
tryObj = new TryAgain(send, { timeout: 3000, polls: 2 });
// abort
function abort() {
clearTimeout(timeoutId);
window.removeEventListener('online', send, false);
iframe.parentElement && documentElement.removeChild(iframe);
}
// over
function over(type) {
abort();
tryObj.try();
if (tryObj.polls === 0) {
reject(type);
}
}
function hashSource() {
return (new Array(8 + Math.round(Math.random() * 8))).join(',').split(',').map(function () {
return String.fromCharCode(97 + Math.round(Math.random() * 25));
}).join('');
}
function send() {
var hash = hashSource();
var script = document.createElement('script');
script.src = url;
url = script.src;
iframe = document.createElement('iframe');
iframe.style.display = 'none';
iframe.csp = "script-src 'unsafe-inline' " + url.split(/\?|\#/)[0] + " 'nonce-" + hash + "'; " + (options.reportUrl ? 'report-uri ' + options.reportUrl : '');
iframe.src = URL.createObjectURL(new Blob(["\n <html>\n <head>\n <meta http-equiv=\"Content-Security-Policy\" content=\"" + iframe.csp + "\">\n <script id=" + hash + " nonce=" + hash + " src=\"" + url + "\" async></script>\n <script nonce=" + hash + ">\n (function () {\n var parent = window.parent\n var script = document.getElementById('" + hash + "')\n window['" + receiver + "'] = window['moduleExportsReceiver'] = function (data) {\n window['moduleExportsReceiver'] = function () {}\n parent['on" + hash + "'] ? parent['on" + hash + "']({ data: { response: data, src: '" + url + "', hash: '" + hash + "' } }) : parent.postMessage({ response: JSON.parse(JSON.stringify(data)), src: '" + url + "', hash: '" + hash + "' }, '" + location.origin + "')\n }\n script.o