mip-sandbox
Advanced tools
Comparing version 1.1.0-alpha to 1.1.0-alpha-1
@@ -5,443 +5,4 @@ /** | ||
*/ | ||
var keys = require('./utils/keys') | ||
var flatten = require('./utils/flatten') | ||
var constant = require('./utils/constant') | ||
var safeThis = require('./utils/safe-this') | ||
var ORIGINAL = [ | ||
{ | ||
type: constant.TYPE.PROPS, | ||
mode: constant.MODE.NORMAL, | ||
access: constant.ACCESS.READONLY, | ||
props: [ | ||
'Array', | ||
'ArrayBuffer', | ||
'Blob', | ||
'Boolean', | ||
'DOMError', | ||
'DOMException', | ||
// https://github.com/mipengine/mip2/issues/336 | ||
'DataView', | ||
'Date', | ||
'Error', | ||
'Float32Array', | ||
'Float64Array', | ||
'FormData', | ||
'Headers', | ||
'Infinity', | ||
'Int16Array', | ||
'Int32Array', | ||
'Int8Array', | ||
'JSON', | ||
'Map', | ||
'Math', | ||
'NaN', | ||
'Number', | ||
'Object', | ||
'Promise', | ||
'Proxy', | ||
'ReadableStream', | ||
'ReferenceError', | ||
'Reflect', | ||
'RegExp', | ||
'Request', | ||
'Response', | ||
'Set', | ||
'String', | ||
'Symbol', | ||
'SyntaxError', | ||
// https://github.com/mipengine/mip2/issues/347 | ||
'TextDecoder', | ||
'TextEncoder', | ||
'TypeError', | ||
'URIError', | ||
'URL', | ||
'URLSearchParams', | ||
'Uint16Array', | ||
'Uint32Array', | ||
'Uint8Array', | ||
'Uint8ClampedArray', | ||
// 1.0.17 新增 WebSocket | ||
'WebSocket', | ||
'WritableStream', | ||
// issue https://github.com/mipengine/mip2/issues/62 | ||
'crypto', | ||
'console', | ||
'decodeURI', | ||
'decodeURIComponent', | ||
'localStorage', | ||
'navigator', | ||
'sessionStorage', | ||
'screen', | ||
'undefined' | ||
] | ||
}, | ||
{ | ||
type: constant.TYPE.PROPS, | ||
mode: constant.MODE.RUNTIME, | ||
access: constant.ACCESS.READONLY, | ||
props: [ | ||
'devicePixelRatio', | ||
'innerHeight', | ||
'innerWidth', | ||
'isSecureContext', | ||
'length', | ||
'outerHeight', | ||
'outerWidth', | ||
'screenLeft', | ||
'screenTop', | ||
'screenX', | ||
'screenY', | ||
'scrollX', | ||
'scrollY', | ||
// mip-data ready status | ||
'mipDataPromises' | ||
] | ||
}, | ||
{ | ||
type: constant.TYPE.FUNCTION, | ||
mode: constant.MODE.NORMAL, | ||
access: constant.ACCESS.READONLY, | ||
props: [ | ||
// https://github.com/mipengine/mip2/issues/347 | ||
'atob', | ||
'clearInterval', | ||
'clearTimeout', | ||
'encodeURI', | ||
'encodeURIComponent', | ||
'escape', | ||
'fetch', | ||
'getComputedStyle', | ||
'isFinite', | ||
'isNaN', | ||
'matchMedia', | ||
'parseFloat', | ||
'parseInt', | ||
'setInterval', | ||
'setTimeout', | ||
'unescape', | ||
// mip1 polyfill | ||
'fetchJsonp' | ||
] | ||
} | ||
] | ||
var RESERVED = [ | ||
'arguments', | ||
'require', | ||
'module', | ||
'exports', | ||
'define', | ||
'import', | ||
// process.env.NODE_ENV | ||
'process' | ||
] | ||
var SANDBOX_STRICT = { | ||
name: 'strict', | ||
access: constant.ACCESS.READONLY, | ||
origin: function () { | ||
return window | ||
}, | ||
properties: ORIGINAL.concat([ | ||
{ | ||
type: constant.TYPE.PROPS, | ||
mode: constant.MODE.NORMAL, | ||
access: constant.ACCESS.READONLY, | ||
props: [ | ||
{ | ||
name: 'document', | ||
origin: function () { | ||
return document | ||
}, | ||
properties: [ | ||
{ | ||
type: constant.TYPE.PROPS, | ||
mode: constant.MODE.RUNTIME, | ||
access: constant.ACCESS.READWRITE, | ||
props: [ | ||
'cookie', | ||
// https://github.com/mipengine/mip2/issues/95 | ||
'domain' | ||
] | ||
} | ||
] | ||
}, | ||
{ | ||
name: 'location', | ||
// host: 'location', | ||
origin: function () { | ||
return location | ||
}, | ||
properties: [ | ||
{ | ||
type: constant.TYPE.PROPS, | ||
mode: constant.MODE.RUNTIME, | ||
access: constant.ACCESS.READONLY, | ||
props: [ | ||
'href', | ||
'protocol', | ||
'host', | ||
'hostname', | ||
'port', | ||
'pathname', | ||
'search', | ||
'hash', | ||
'origin' | ||
] | ||
} | ||
] | ||
}, | ||
{ | ||
name: 'MIP', | ||
// host: 'MIP', | ||
origin: function () { | ||
return MIP | ||
}, | ||
properties: [ | ||
{ | ||
type: constant.TYPE.PROPS, | ||
mode: constant.MODE.NORMAL, | ||
access: constant.ACCESS.READONLY, | ||
props: [ | ||
'viewport', | ||
'util', | ||
'sandbox', | ||
{ | ||
name: 'viewer', | ||
origin: function () { | ||
return MIP.viewer | ||
}, | ||
properties: [ | ||
{ | ||
type: constant.TYPE.PROPS, | ||
mode: constant.MODE.NORMAL, | ||
access: constant.ACCESS.READONLY, | ||
props: [ | ||
'isIframed' | ||
] | ||
}, | ||
{ | ||
type: constant.TYPE.FUNCTION, | ||
mode: constant.MODE.NORMAL, | ||
access: constant.ACCESS.READONLY, | ||
props: [ | ||
'sendMessage', | ||
'open' | ||
] | ||
} | ||
] | ||
} | ||
] | ||
}, | ||
{ | ||
type: constant.TYPE.PROPS, | ||
mode: constant.MODE.RUNTIME, | ||
access: constant.ACCESS.READONLY, | ||
props: [ | ||
'MIP_ROOT_PAGE' | ||
] | ||
}, | ||
{ | ||
type: constant.TYPE.FUNCTION, | ||
mode: constant.MODE.NORMAL, | ||
access: constant.ACCESS.READONLY, | ||
props: [ | ||
'watch', | ||
'setData', | ||
'getData' | ||
] | ||
} | ||
] | ||
}, | ||
{ | ||
name: 'window', | ||
getter: function () { | ||
return MIP.sandbox.strict | ||
} | ||
} | ||
] | ||
}, | ||
{ | ||
type: constant.TYPE.FUNCTION, | ||
mode: constant.MODE.NORMAL, | ||
access: constant.ACCESS.READONLY, | ||
props: [ | ||
{ | ||
name: 'this', | ||
getter: function () { | ||
return safeThis(MIP.sandbox.strict) | ||
} | ||
} | ||
] | ||
} | ||
]) | ||
} | ||
var SANDBOX = { | ||
name: 'sandbox', | ||
access: constant.ACCESS.READONLY, | ||
origin: function () { | ||
return window | ||
}, | ||
properties: ORIGINAL.concat([ | ||
{ | ||
type: constant.TYPE.PROPS, | ||
mode: constant.MODE.NORMAL, | ||
access: constant.ACCESS.READONLY, | ||
props: [ | ||
// https://github.com/mipengine/mip2/issues/143 | ||
'CustomEvent', | ||
'File', | ||
'FileList', | ||
'FileReader', | ||
'Image', | ||
'ImageBitmap', | ||
'MutationObserver', | ||
'Notification', | ||
// 待定 | ||
'history', | ||
// 待定 | ||
'location', | ||
'scrollbars', | ||
{ | ||
name: 'document', | ||
origin: function () { | ||
return document | ||
}, | ||
properties: [ | ||
{ | ||
type: constant.TYPE.PROPS, | ||
mode: constant.MODE.RUNTIME, | ||
access: constant.ACCESS.READWRITE, | ||
props: [ | ||
// https://github.com/mipengine/mip2/issues/95 | ||
'domain', | ||
'head', | ||
'body', | ||
'title', | ||
'cookie', | ||
'referrer', | ||
'readyState', | ||
'documentElement' | ||
] | ||
}, | ||
{ | ||
type: constant.TYPE.FUNCTION, | ||
mode: constant.MODE.NORMAL, | ||
access: constant.ACCESS.READONLY, | ||
props: [ | ||
'createElement', | ||
'createDocumentFragment', | ||
'getElementById', | ||
'getElementsByClassName', | ||
'getElementsByTagName', | ||
'querySelector', | ||
'querySelectorAll' | ||
] | ||
} | ||
] | ||
}, | ||
{ | ||
name: 'window', | ||
getter: function () { | ||
return MIP.sandbox | ||
} | ||
}, | ||
{ | ||
name: 'MIP', | ||
getter: function () { | ||
return MIP | ||
} | ||
}, | ||
SANDBOX_STRICT | ||
] | ||
}, | ||
{ | ||
type: constant.TYPE.FUNCTION, | ||
mode: constant.MODE.NORMAL, | ||
access: constant.ACCESS.READONLY, | ||
props: [ | ||
'addEventListener', | ||
'cancelAnimationFrame', | ||
'createImageBitmap', | ||
'removeEventListener', | ||
'requestAnimationFrame', | ||
'scrollBy', | ||
'scrollTo', | ||
'scroll', | ||
'webkitCancelAnimationFrame', | ||
'webkitRequestAnimationFrame', | ||
{ | ||
name: 'this', | ||
getter: function () { | ||
return safeThis(MIP.sandbox) | ||
} | ||
} | ||
] | ||
} | ||
]) | ||
} | ||
function flattenProperties (properties) { | ||
return flatten(properties.map(function (prop) { | ||
return prop.props | ||
})) | ||
} | ||
var sandboxProperties = flattenProperties(SANDBOX.properties) | ||
var sandboxStrictProperties = flattenProperties(SANDBOX_STRICT.properties) | ||
var WHITELIST = keys(sandboxProperties).concat(RESERVED) | ||
var WHITELIST_STRICT = keys(sandboxStrictProperties).concat(RESERVED) | ||
var WHITELIST_RESERVED = keys(sandboxProperties, true).concat(RESERVED) | ||
var WHITELIST_STRICT_RESERVED = keys(sandboxStrictProperties, true).concat(RESERVED) | ||
// 防止用户篡改数组,因此每次返回的都是数组浅拷贝 | ||
var whiteListProperties = { | ||
type: constant.TYPE.PROPS, | ||
mode: constant.MODE.NORMAL, | ||
access: constant.ACCESS.READONLY, | ||
props: [ | ||
{ | ||
name: 'WHITELIST', | ||
getter: function () { | ||
return WHITELIST.slice() | ||
} | ||
}, | ||
{ | ||
name: 'WHITELIST_STRICT', | ||
getter: function () { | ||
return WHITELIST_STRICT.slice() | ||
} | ||
}, | ||
{ | ||
name: 'WHITELIST_RESERVED', | ||
getter: function () { | ||
return WHITELIST_RESERVED.slice() | ||
} | ||
}, | ||
{ | ||
name: 'WHITELIST_STRICT_RESERVED', | ||
getter: function () { | ||
return WHITELIST_STRICT_RESERVED.slice() | ||
} | ||
} | ||
] | ||
} | ||
SANDBOX.properties = SANDBOX.properties.concat(whiteListProperties) | ||
SANDBOX_STRICT.properties = SANDBOX_STRICT.properties.concat(whiteListProperties) | ||
module.exports = { | ||
ORIGINAL: ORIGINAL, | ||
RESERVED: RESERVED, | ||
SANDBOX: SANDBOX, | ||
SANDBOX_STRICT: SANDBOX_STRICT, | ||
WHITELIST: WHITELIST, | ||
WHITELIST_STRICT: WHITELIST_STRICT, | ||
WHITELIST_RESERVED: WHITELIST_RESERVED, | ||
WHITELIST_STRICT_RESERVED: WHITELIST_STRICT_RESERVED | ||
} | ||
var gen = require('./keywords-generate') | ||
module.exports = gen() |
@@ -8,7 +8,8 @@ /** | ||
var keywords = require('./keywords') | ||
var gen = require('./keywords-generate') | ||
var def = require('./utils/def') | ||
module.exports = function (mip) { | ||
var sandboxDescriptor = def(mip, keywords.SANDBOX.name, keywords.SANDBOX) | ||
var keywords = gen() | ||
var descriptor = def(mip, keywords.SANDBOX.name, keywords.SANDBOX) | ||
@@ -19,4 +20,4 @@ if (mip) { | ||
var sandbox = sandboxDescriptor.get() | ||
var sandbox = descriptor.get() | ||
return sandbox | ||
} |
@@ -9,4 +9,3 @@ /** | ||
var sandboxGenerate = require('./sandbox-generate') | ||
module.exports = sandboxGenerate() | ||
var gen = require('./sandbox-generate') | ||
module.exports = gen() |
@@ -11,6 +11,6 @@ /** | ||
}, | ||
MODE: { | ||
NORMAL: false, | ||
RUNTIME: true | ||
}, | ||
// MODE: { | ||
// NORMAL: false, | ||
// RUNTIME: true | ||
// }, | ||
ACCESS: { | ||
@@ -17,0 +17,0 @@ READONLY: false, |
@@ -8,3 +8,5 @@ /** | ||
var globals = window | ||
var TYPE_PROPS = constant.TYPE.PROPS | ||
var TYPE_FUNCTION = constant.TYPE.FUNCTION | ||
var ACCESS_READONLY = constant.ACCESS.READONLY | ||
@@ -14,3 +16,3 @@ function noop () {} | ||
function getGlobals () { | ||
return globals | ||
return window | ||
} | ||
@@ -20,20 +22,46 @@ | ||
return function () { | ||
var parent = origin() | ||
return parent[name] | ||
return origin()[name] | ||
} | ||
} | ||
function bindedPropFactory (name, origin) { | ||
function funcFactory (name, origin) { | ||
return function () { | ||
var parent = origin() | ||
var fn = parent[name] | ||
if (typeof fn === 'function') { | ||
return fn.bind(parent) | ||
} | ||
return fn && fn.bind(parent) | ||
} | ||
} | ||
function mockFactory () { | ||
function propGetter (name, type, origin) { | ||
return type === TYPE_FUNCTION | ||
? funcFactory(name, origin) | ||
: propFactory(name, origin) | ||
} | ||
function mockGetter (name, desc, origin) { | ||
var mock = {} | ||
var isDefined = false | ||
var properties = desc.properties | ||
var childOrigin = desc.origin || propFactory(name, origin) | ||
return function () { | ||
if (isDefined) { | ||
return mock | ||
} | ||
for (var i = 0; i < properties.length; i++) { | ||
var group = properties[i] | ||
var childType = group.type | ||
var childAccess = group.access | ||
var props = group.props | ||
for (var j = 0; j < props.length; j++) { | ||
var prop = props[j] | ||
def(mock, prop.name || prop, prop, childType, childAccess, childOrigin) | ||
} | ||
} | ||
isDefined = true | ||
return mock | ||
@@ -43,10 +71,14 @@ } | ||
function propProxy (name, type, access, origin) { | ||
function proxyFactory (name, desc, type, access, origin) { | ||
return { | ||
get: type === constant.TYPE.FUNCTION | ||
? bindedPropFactory(name, origin) | ||
: propFactory(name, origin), | ||
set: access === constant.ACCESS.READONLY | ||
? noop | ||
: function (val) { | ||
get: typeof desc.getter === 'function' | ||
? desc.getter | ||
: desc.properties | ||
? mockGetter(name, desc, origin) | ||
: propGetter(name, type, origin), | ||
set: typeof desc.setter === 'function' | ||
? desc.setter | ||
: access === ACCESS_READONLY | ||
? noop | ||
: function (val) { | ||
var parent = origin() | ||
@@ -58,36 +90,3 @@ parent[name] = val | ||
function mockProxy (access) { | ||
var mock = {} | ||
return { | ||
get: function () { | ||
return mock | ||
}, | ||
set: access === constant.ACCESS.READONLY | ||
? noop | ||
: function (value) { | ||
mock = value | ||
} | ||
} | ||
} | ||
function setterGetterProxy (getter, setter) { | ||
return { | ||
get: getter, | ||
set: setter || noop | ||
} | ||
} | ||
function proxyFactory (name, desc, type, access, origin) { | ||
if (typeof desc.getter === 'function') { | ||
return setterGetterProxy(desc.getter, desc.setter) | ||
} | ||
if (desc.properties) { | ||
return mockProxy(access) | ||
} | ||
return propProxy(name, type, access, origin) | ||
} | ||
function getDescriptor (name, desc, type, mode, access, origin) { | ||
function getDescriptor (name, desc, type, access, origin) { | ||
if (desc.descriptor) { | ||
@@ -108,52 +107,11 @@ return desc.descriptor | ||
type = desc.type || type || constant.TYPE.PROPS | ||
mode = desc.mode || mode || constant.MODE.NORMAL | ||
access = desc.access || access || constant.ACCESS.READONLY | ||
origin = origin || getGlobals | ||
var proxy = proxyFactory( | ||
name, | ||
desc, | ||
desc.type || type || TYPE_PROPS, | ||
desc.access || access || ACCESS_READONLY, | ||
origin || getGlobals | ||
) | ||
var proxy = proxyFactory(name, desc, type, access, origin) | ||
var getter | ||
if (desc.properties) { | ||
var properties = desc.properties | ||
var childOrigin = desc.origin || propFactory(name, origin) | ||
getter = function () { | ||
var mock = proxy.get() | ||
for (var i = 0; i < properties.length; i++) { | ||
var group = properties[i] | ||
var childType = group.type | ||
var childMode = group.mode | ||
var childAccess = group.access | ||
var props = group.props | ||
for (var j = 0; j < props.length; j++) { | ||
var prop = props[j] | ||
def(mock, prop.name || prop, prop, childType, childMode, childAccess, childOrigin) | ||
} | ||
} | ||
return mock | ||
} | ||
} else { | ||
getter = proxy.get | ||
} | ||
// 普通的节点可以进行缓存 | ||
if (mode === constant.MODE.NORMAL) { | ||
var cache | ||
var runtimeGetter = getter | ||
getter = function () { | ||
if (cache) { | ||
return cache | ||
} | ||
cache = runtimeGetter() | ||
return cache | ||
} | ||
} | ||
descriptor.get = getter | ||
descriptor.get = proxy.get | ||
descriptor.set = proxy.set | ||
@@ -164,4 +122,4 @@ | ||
function def (obj, name, desc, type, mode, access, origin) { | ||
var descriptor = getDescriptor(name, desc, type, mode, access, origin) | ||
function def (obj, name, desc, type, access, origin) { | ||
var descriptor = getDescriptor(name, desc, type, access, origin) | ||
@@ -168,0 +126,0 @@ if (obj) { |
{ | ||
"name": "mip-sandbox", | ||
"version": "1.1.0-alpha", | ||
"version": "1.1.0-alpha-1", | ||
"description": "sandbox tools for MIP project", | ||
@@ -5,0 +5,0 @@ "main": "lib/sandbox.js", |
22
230921
5535