shadow-function
Version:
ioing lib - shadow Function, worker Function
148 lines (124 loc) • 4.13 kB
text/typescript
'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
}