冻结运行环境内置的对象

This commit is contained in:
lyswhut 2023-11-05 14:36:57 +08:00
parent 44a3a37e0d
commit 1c99f40248

View File

@ -1,3 +1,4 @@
'use strict'
globalThis.lx_setup = (key, id, name, description, rawScript) => { globalThis.lx_setup = (key, id, name, description, rawScript) => {
delete globalThis.setup delete globalThis.setup
@ -37,7 +38,7 @@ globalThis.lx_setup = (key, id, name, description, rawScript) => {
const callbacks = new Map() const callbacks = new Map()
let timeoutId = 0 let timeoutId = 0
const setTimeout = (callback, timeout = 0, ...params) => { const _setTimeout = (callback, timeout = 0, ...params) => {
if (typeof timeout !== 'number' || timeout < 0) throw new Error('timeout required number') if (typeof timeout !== 'number' || timeout < 0) throw new Error('timeout required number')
if (timeoutId > 90000000000) throw new Error('max timeout') if (timeoutId > 90000000000) throw new Error('max timeout')
const id = timeoutId++ const id = timeoutId++
@ -48,7 +49,7 @@ globalThis.lx_setup = (key, id, name, description, rawScript) => {
set_timeout(id, parseInt(timeout)) set_timeout(id, parseInt(timeout))
return id return id
} }
const clearTimeout = (id) => { const _clearTimeout = (id) => {
const tagret = callbacks.get(id) const tagret = callbacks.get(id)
if (!tagret) return if (!tagret) return
callbacks.delete(id) callbacks.delete(id)
@ -113,11 +114,11 @@ globalThis.lx_setup = (key, id, name, description, rawScript) => {
// 'utils.zlib.inflate': 'utils.zlib.inflate', // 'utils.zlib.inflate': 'utils.zlib.inflate',
// 'utils.zlib.deflate': 'utils.zlib.deflate', // 'utils.zlib.deflate': 'utils.zlib.deflate',
} }
const EVENT_NAMES = Object.freeze({ const EVENT_NAMES = {
request: 'request', request: 'request',
inited: 'inited', inited: 'inited',
updateAlert: 'updateAlert', updateAlert: 'updateAlert',
}) }
const eventNames = Object.values(EVENT_NAMES) const eventNames = Object.values(EVENT_NAMES)
const events = { const events = {
request: null, request: null,
@ -299,7 +300,7 @@ globalThis.lx_setup = (key, id, name, description, rawScript) => {
else if (Array.isArray(data) || ArrayBuffer.isView(data)) return utils.buffer.bufToString(data, 'base64') else if (Array.isArray(data) || ArrayBuffer.isView(data)) return utils.buffer.bufToString(data, 'base64')
throw new Error('data type error: ' + typeof data + ' raw data: ' + data) throw new Error('data type error: ' + typeof data + ' raw data: ' + data)
} }
const utils = Object.freeze({ const utils = {
crypto: { crypto: {
aesEncrypt(buffer, mode, key, iv) { aesEncrypt(buffer, mode, key, iv) {
// console.log('aesEncrypt', buffer, mode, key, iv) // console.log('aesEncrypt', buffer, mode, key, iv)
@ -391,117 +392,130 @@ globalThis.lx_setup = (key, id, name, description, rawScript) => {
// }) // })
// }) // })
// }, // },
// }, // }),
}) }
Object.defineProperty(globalThis, 'lx', {
configurable: false,
writable: false,
value: Object.freeze({
EVENT_NAMES,
request(url, { method = 'get', timeout, headers, body, form, formData, binary }, callback) {
let options = { headers, binary: binary === true }
// let data
// if (body) {
// data = body
// } else if (form) {
// data = form
// // data.content_type = 'application/x-www-form-urlencoded'
// options.json = false
// } else if (formData) {
// data = formData
// // data.content_type = 'multipart/form-data'
// options.json = false
// }
if (timeout && typeof timeout == 'number') options.timeout = Math.min(options.timeout, 60_000)
let request = sendNativeRequest(url, { method, body, form, formData, ...options }, (err, resp) => { globalThis.lx = {
callback(err, { EVENT_NAMES,
statusCode: resp.statusCode, request(url, { method = 'get', timeout, headers, body, form, formData, binary }, callback) {
statusMessage: resp.statusMessage, let options = { headers, binary: binary === true }
headers: resp.headers, // let data
// bytes: resp.bytes, // if (body) {
// raw: resp.raw, // data = body
body: resp.body, // } else if (form) {
}, resp.body) // data = form
}) // // data.content_type = 'application/x-www-form-urlencoded'
// options.json = false
// } else if (formData) {
// data = formData
// // data.content_type = 'multipart/form-data'
// options.json = false
// }
if (timeout && typeof timeout == 'number') options.timeout = Math.min(options.timeout, 60_000)
return () => { let request = sendNativeRequest(url, { method, body, form, formData, ...options }, (err, resp) => {
if (!request.aborted) request.abort() callback(err, {
request = null statusCode: resp.statusCode,
} statusMessage: resp.statusMessage,
}, headers: resp.headers,
send(eventName, data) { // bytes: resp.bytes,
return new Promise((resolve, reject) => { // raw: resp.raw,
if (!eventNames.includes(eventName)) return reject(new Error('The event is not supported: ' + eventName)) body: resp.body,
switch (eventName) { }, resp.body)
case EVENT_NAMES.inited: })
if (isInitedApi) return reject(new Error('Script is inited'))
isInitedApi = true return () => {
handleInit(data) if (!request.aborted) request.abort()
resolve() request = null
break }
case EVENT_NAMES.updateAlert: },
if (isShowedUpdateAlert) return reject(new Error('The update alert can only be called once.')) send(eventName, data) {
isShowedUpdateAlert = true return new Promise((resolve, reject) => {
handleShowUpdateAlert(data, resolve, reject) if (!eventNames.includes(eventName)) return reject(new Error('The event is not supported: ' + eventName))
break
default:
reject(new Error('Unknown event name: ' + eventName))
}
})
},
on(eventName, handler) {
if (!eventNames.includes(eventName)) return Promise.reject(new Error('The event is not supported: ' + eventName))
switch (eventName) { switch (eventName) {
case EVENT_NAMES.request: case EVENT_NAMES.inited:
events.request = handler if (isInitedApi) return reject(new Error('Script is inited'))
isInitedApi = true
handleInit(data)
resolve()
break break
default: return Promise.reject(new Error('The event is not supported: ' + eventName)) case EVENT_NAMES.updateAlert:
if (isShowedUpdateAlert) return reject(new Error('The update alert can only be called once.'))
isShowedUpdateAlert = true
handleShowUpdateAlert(data, resolve, reject)
break
default:
reject(new Error('Unknown event name: ' + eventName))
} }
return Promise.resolve() })
}, },
utils, on(eventName, handler) {
currentScriptInfo: Object.freeze({ if (!eventNames.includes(eventName)) return Promise.reject(new Error('The event is not supported: ' + eventName))
name, switch (eventName) {
description, case EVENT_NAMES.request:
}), events.request = handler
version: '1.0.0', break
env: 'mobile', default: return Promise.reject(new Error('The event is not supported: ' + eventName))
}), }
}) return Promise.resolve()
},
utils,
currentScriptInfo: {
name,
description,
},
version: '1.0.0',
env: 'mobile',
}
globalThis.setTimeout = _setTimeout
globalThis.clearTimeout = _clearTimeout
globalThis.window = globalThis
globalThis.document = {
getElementsByTagName(name) {
if (name == 'script') {
return [
Object.freeze({
innerText: rawScript,
}),
]
}
return null
},
}
Object.defineProperty(globalThis, 'setTimeout', { const _toString = Function.prototype.toString
configurable: false, // eslint-disable-next-line no-extend-native
writable: false, Function.prototype.toString = function() {
value: setTimeout, return Object.getOwnPropertyDescriptors(this).name.configurable
}) ? _toString.apply(this)
Object.defineProperty(globalThis, 'clearTimeout', { : `function ${this.name}() { [native code] }`
configurable: false, }
writable: false,
value: clearTimeout, const excludes = [
}) Function.prototype.toString,
Object.defineProperty(globalThis, 'window', { Function.prototype.toLocaleString,
configurable: false, Object.prototype.toString,
writable: false, ]
value: globalThis, const freezeObject = (obj, freezedObj = new Set()) => {
}) if (obj == null) return
Object.defineProperty(globalThis, 'document', { switch (typeof obj) {
configurable: false, case 'object':
writable: false, case 'function':
value: Object.freeze({ if (freezedObj.has(obj)) return
getElementsByTagName(name) { // Object.freeze(obj)
if (name == 'script') { freezedObj.add(obj)
return [ for (const [name, { ...config }] of Object.entries(Object.getOwnPropertyDescriptors(obj))) {
Object.freeze({ if (!excludes.includes(config.value)) {
innerText: rawScript, if (config.writable) config.writable = false
}), if (config.configurable) config.configurable = false
] Object.defineProperty(obj, name, config)
}
freezeObject(config.value, freezedObj)
} }
return null }
}, }
}), freezeObject(globalThis)
})
console.log('Preload finished.') console.log('Preload finished.')
} }