UNPKG

shadow-function

Version:

ioing lib - shadow Function, worker Function

148 lines (124 loc) 4.13 kB
'use strict' import windowOwnPropertyNames from './windowOwnPropertyNames.config' class Sandbox { public sandbox: HTMLIFrameElement public shadowWindow!: ShadowWindow public window!: Window public document!: Document public content!: Document public windowOwnPropertyNames: Array<string> = windowOwnPropertyNames private white: boolean constructor (white = false, properties: string[] = ['*'], setting = 'allow-scripts allow-same-origin') { const 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 } static getWindowOwnPropertyNames () { return windowOwnPropertyNames } static debugger (isee: string, model = { 'safe-context': 'safe' }) { let 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}'`) } } private shadow () { const contentWindow = this.sandbox.contentWindow as ShadowWindow const contentDocument = this.sandbox.contentDocument as Document this.window = contentWindow this.content = this.document = contentDocument if (this.white) return this const globalProperty = this.getProtoProperty(this.window) const ShadowObject = this.window.Object as ObjectConstructor const allowAllProperty = ~this.windowOwnPropertyNames.indexOf('*') this.shadowWindow = new contentWindow.Object() as ShadowWindow for (let k of globalProperty) { if (this.window[k] + '' !== '[object Window]' && (allowAllProperty || ~this.windowOwnPropertyNames.indexOf(k))) { this.shadowWindow[k] = this.window[k] } else { try { ShadowObject.defineProperty(this.shadowWindow, k, { configurable: true, enumerable: true, writable: true, get () { console.error(`Sandbox Error: Unauthorized use of window['${k}'].`) return null } }) this.delProtoProperty(this.window, k) } catch (e) { // } } } this.shadowWindow.shadowWindow = this.shadowWindow this.shadowWindow.window = this.shadowWindow return this } public getProtoProperty (object: object) { let propertyNames = Object.getOwnPropertyNames(object) if (object['__proto__']) return propertyNames.concat(this.getProtoProperty(object['__proto__'] as object)) return propertyNames } public delProtoProperty (object: object, name: string) { 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] } } public set (allow: string) { this.sandbox.setAttribute('sandbox', allow) } public reset (allow: string) { this.exit() this.set(allow) this.enter() this.shadow() return this } public open () { this.content.open() return this } public write (context = '<head><meta charset="utf-8"></head>') { this.content.write(context) return this } public close () { this.content.close() return this } public enter () { const documentElement = document.documentElement as HTMLHtmlElement documentElement.appendChild(this.sandbox) } public exit () { if (this['open debugger']) return const parentNode = this.sandbox.parentNode as HTMLHtmlElement parentNode && parentNode.removeChild(this.sandbox) } } export { Sandbox }