diff --git a/bundle.js b/bundle.js index ee63f67..366c7fe 100644 --- a/bundle.js +++ b/bundle.js @@ -3,7 +3,7 @@ import path from "path"; const __dirname = path.resolve(path.dirname(decodeURI(new URL(import.meta.url).pathname))).slice(3); -console.log(__dirname); +console.log(path.resolve(path.dirname(decodeURI(new URL(import.meta.url).pathname))), __dirname); webpack({ mode: 'none', diff --git a/client/index.js b/client/index.js index b84f493..4b41a74 100644 --- a/client/index.js +++ b/client/index.js @@ -15,6 +15,7 @@ import NavigatorApi from "./navigator.js"; import Workers from "./worker.js"; import URLApi from "./url.js"; import EventEmitter from "./events.js"; +import StorageApi from "./storage.js"; class UVClient extends EventEmitter { constructor(window = self, worker = !window.window) { @@ -25,9 +26,14 @@ class UVClient extends EventEmitter { defineProperty: this.window.Object.defineProperty, getOwnPropertyDescriptor: this.window.Object.getOwnPropertyDescriptor, getOwnPropertyDescriptors: this.window.Object.getOwnPropertyDescriptors, + getOwnPropertyNames: this.window.Object.getOwnPropertyNames, + keys: this.window.Object.keys, + getOwnPropertySymbols: this.window.Object.getOwnPropertySymbols, isArray: this.window.Array.isArray, setPrototypeOf: this.window.Object.setPrototypeOf, isExtensible: this.window.Object.isExtensible, + Map: this.window.Map, + Proxy: this.window.Proxy, }; this.worker = worker; this.fetch = new Fetch(this); @@ -46,6 +52,7 @@ class UVClient extends EventEmitter { this.url = new URLApi(this); this.workers = new Workers(this); this.location = new LocationApi(this); + this.storage = new StorageApi(this); }; initLocation(rewriteUrl, sourceUrl) { this.location = new LocationApi(this, sourceUrl, rewriteUrl, this.worker); diff --git a/client/location.js b/client/location.js index 3ec0f40..e665179 100644 --- a/client/location.js +++ b/client/location.js @@ -95,6 +95,18 @@ class LocationApi { }); }; + if ('ancestorOrigins' in this.location) { + this.ctx.nativeMethods.defineProperty(emulation, 'ancestorOrigins', { + get() { + const arr = []; + if (that.window.DOMStringList) that.ctx.nativeMethods.setPrototypeOf(arr, that.window.DOMStringList.prototype); + return arr; + }, + set: undefined, + enumerable: true, + }); + }; + this.ctx.nativeMethods.defineProperty(emulation, 'toString', { value: this.ctx.wrap(this.location, 'toString', () => { diff --git a/client/storage.js b/client/storage.js new file mode 100644 index 0000000..1d1d4db --- /dev/null +++ b/client/storage.js @@ -0,0 +1,155 @@ +import EventEmitter from "./events.js"; +import HookEvent from "./hook.js"; + +class StorageApi extends EventEmitter { + constructor(ctx) { + super(); + this.ctx = ctx; + this.window = ctx.window; + this.localStorage = this.window.localStorage || null; + this.sessionStorage = this.window.sessionStorage || null; + this.Storage = this.window.Storage || {}; + this.storeProto = this.Storage.prototype || {}; + this.getItem = this.storeProto.getItem || null; + this.setItem = this.storeProto.setItem || null; + this.removeItem = this.storeProto.removeItem || null; + this.clear = this.storeProto.clear || null; + this.key = this.storeProto.key || null; + this.methods = ['key', 'getItem', 'setItem', 'removeItem', 'clear']; + this.wrappers = new ctx.nativeMethods.Map(); + }; + overrideMethods() { + this.ctx.override(this.storeProto, 'getItem', (target, that, args) => { + if (!args.length) return target.apply((this.wrappers.get(that) || that), args); + let [ name ] = args; + + const event = new HookEvent({ name }, target, (this.wrappers.get(that) || that)); + this.emit('getItem', event); + + if (event.intercepted) return event.returnValue; + return event.target.call(event.that, event.data.name); + }); + this.ctx.override(this.storeProto, 'setItem', (target, that, args) => { + if (2 > args.length) return target.apply((this.wrappers.get(that) || that), args); + let [ name, value ] = args; + + const event = new HookEvent({ name, value }, target, (this.wrappers.get(that) || that)); + this.emit('setItem', event); + + if (event.intercepted) return event.returnValue; + return event.target.call(event.that, event.data.name, event.data.value); + }); + this.ctx.override(this.storeProto, 'removeItem', (target, that, args) => { + if (!args.length) return target.apply((this.wrappers.get(that) || that), args); + let [ name ] = args; + + const event = new HookEvent({ name }, target, (this.wrappers.get(that) || that)); + this.emit('removeItem', event); + + if (event.intercepted) return event.returnValue; + return event.target.call(event.that, event.data.name); + }); + this.ctx.override(this.storeProto, 'clear', (target, that) => { + const event = new HookEvent(null, target, (this.wrappers.get(that) || that)); + this.emit('clear', event); + + if (event.intercepted) return event.returnValue; + return event.target.call(event.that); + }); + this.ctx.override(this.storeProto, 'key', (target, that, args) => { + if (!args.length) return target.apply((this.wrappers.get(that) || that), args); + let [ index ] = args; + + const event = new HookEvent({ index }, target, (this.wrappers.get(that) || that)); + this.emit('key', event); + + if (event.intercepted) return event.returnValue; + return event.target.call(event.that, event.data.index); + }); + }; + overrideLength() { + this.ctx.overrideDescriptor(this.storeProto, 'length', { + get: (target, that) => { + const event = new HookEvent({ length: target.call((this.wrappers.get(that) || that)) }, target, (this.wrappers.get(that) || that)); + this.emit('length', event); + + if (event.intercepted) return event.returnValue; + return event.data.length; + }, + }); + }; + emulate(storage, obj = {}) { + this.ctx.nativeMethods.setPrototypeOf(obj, this.storeProto); + + const proxy = new this.ctx.window.Proxy(obj, { + get: (target, prop) => { + if (prop in this.storeProto || typeof prop === 'symbol') return storage[prop]; + + const event = new HookEvent({ name: prop }, null, storage); + this.emit('get', event); + + if (event.intercepted) return event.returnValue; + return storage[event.data.name]; + }, + set: (target, prop, value) => { + if (prop in this.storeProto || typeof prop === 'symbol') return storage[prop] = value; + + const event = new HookEvent({ name: prop, value }, null, storage); + this.emit('set', event); + + if (event.intercepted) return event.returnValue; + + return storage[event.data.name] = event.data.value; + }, + deleteProperty: (target, prop) => { + if (typeof prop === 'symbol') return delete storage[prop]; + + const event = new HookEvent({ name: prop }, null, storage); + this.emit('delete', event); + + if (event.intercepted) return event.returnValue; + + return delete storage[event.data.name]; + }, + }); + + this.wrappers.set(proxy, storage); + this.ctx.nativeMethods.setPrototypeOf(proxy, this.storeProto); + + return proxy; + }; + +}; + +export default StorageApi; + + +class StorageWrapper { + constructor(api, storage, wrap, unwrap, origin) { + this.api = api; + this.ctx = api.ctx; + this.storage = storage; + this.wrap = wrap; + this.unwrap = unwrap; + this.origin = origin; + this.emulation = {}; + }; + clear() { + for (const key in this.storage) { + const data = this.unwrap(key); + if (!data || data.origin !== this.origin) continue; + this.api.removeItem.call(this.storage, key); + }; + this.emulation = {}; + this.ctx.nativeMethods.setPrototypeOf(this.emulation, this.api.storeProto); + }; + __init() { + for (const key in this.storage) { + const data = this.unwrap(key); + if (!data || data.origin !== this.origin) continue; + + this.emulation[data.name] = this.api.getItem.call(this.storage, key); + }; + this.ctx.nativeMethods.setPrototypeOf(this.emulation, this.api.storeProto); + }; +}; \ No newline at end of file diff --git a/example/config.json b/example/config.json index 4a9bd5a..defc3c6 100644 --- a/example/config.json +++ b/example/config.json @@ -1,4 +1,4 @@ { - "prefix": "/service/", + "prefix": "/sw/", "bare": "/bare/" } \ No newline at end of file diff --git a/example/load.html b/example/load.html index f6ad2bd..10e363f 100644 --- a/example/load.html +++ b/example/load.html @@ -5,7 +5,7 @@ -__uv$get(frame, 'postMessage', __uv) \ No newline at end of file + \ No newline at end of file diff --git a/index.js b/index.js index 994066c..1f30e27 100644 --- a/index.js +++ b/index.js @@ -18,7 +18,7 @@ console.log( */ console.log( - uv.rewriteJS('window.eval(saasdsd)') + uv.rewriteJS('top') ) /* diff --git a/lib/uv.bundle.js b/lib/uv.bundle.js index c5dcf0b..335eb1a 100644 --- a/lib/uv.bundle.js +++ b/lib/uv.bundle.js @@ -8899,7 +8899,6 @@ class CSS extends _events_js__WEBPACK_IMPORTED_MODULE_1__["default"] { }); return this.generate(ast); } catch(e) { - console.log(e) return str; }; }; @@ -23465,8 +23464,7 @@ __webpack_require__.r(__webpack_exports__); "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__), -/* harmony export */ "NodeEvent": () => (/* binding */ NodeEvent) +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var meriyah__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(140); /* harmony import */ var esotope_hammerhead__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(141); @@ -23563,37 +23561,8 @@ class JS extends _events_js__WEBPACK_IMPORTED_MODULE_2__["default"] { }; }; -class NodeEvent extends _events_js__WEBPACK_IMPORTED_MODULE_2__["default"] { - constructor(node, parent = null) { - super(); - this._node = node; - for (let key in node) { - Object.defineProperty(this, key, { - get: () => node[key], - sel: val => node[key] = val, - }); - }; - this.parent = parent; - }; - iterate(handler) { - for (const key in this._node) { - if (key === 'parent') continue; - if (Array.isArray(this._node[key])) { - this._node[key].forEach(entry => { - const child = new this.constructor(entry, this._node); - handler(child); - }); - } else { - const child = new this.constructor(entry, this._node); - walk(this._node[key], this._node, handler); - }; - }; - }; -}; - /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (JS); - /***/ }), /* 140 */ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { @@ -35538,7 +35507,23 @@ async function db(openDB) { function serialize(cookies = [], meta, js) { let str = ''; + const now = new Date(); for (const cookie of cookies) { + + let expired = false; + + if (cookie.set) { + if (cookie.maxAge) { + expired = cookie.set.getTime() + (cookie.maxAge * 1e3) < now; + } else if (cookie.expires) { + expired = cookie.expires > now; + }; + }; + + if (expired) { + + continue; + }; if (!validateCookie(cookie, meta, js)) continue; if (str.length) str += '; '; str += cookie.name; @@ -35549,15 +35534,34 @@ function serialize(cookies = [], meta, js) { }; async function getCookies(db) { - return await db.getAll('cookies'); + const now = new Date(); + return (await db.getAll('cookies')).filter(cookie => { + + let expired = false; + if (cookie.set) { + if (cookie.maxAge) { + expired = (cookie.set.getTime() + (cookie.maxAge * 1e3)) < now; + } else if (cookie.expires) { + expired = new Date(cookie.expires.toLocaleString()) < now; + }; + }; + + if (expired) { + db.delete('cookies', cookie.id); + return false; + }; + + return true; + }); }; function setCookies(data, db, meta) { if (!db) return false; + const cookies = set_cookie_parser__WEBPACK_IMPORTED_MODULE_0__(data, { decodeValues: false, }) - + for (const cookie of cookies) { if (!cookie.domain) cookie.domain = '.' + meta.url.hostname; if (!cookie.path) cookie.path = '/'; @@ -35569,6 +35573,7 @@ function setCookies(data, db, meta) { db.put('cookies', { ...cookie, id: `${cookie.domain}@${cookie.path}@${cookie.name}`, + set: new Date(Date.now()), }); }; return true; @@ -35584,16 +35589,18 @@ function setCookies(data, db, meta) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "attributes": () => (/* binding */ attributes), +/* harmony export */ "createInjection": () => (/* binding */ createInjection), /* harmony export */ "text": () => (/* binding */ text), /* harmony export */ "isUrl": () => (/* binding */ isUrl), /* harmony export */ "isEvent": () => (/* binding */ isEvent), /* harmony export */ "isForbidden": () => (/* binding */ isForbidden), /* harmony export */ "isHtml": () => (/* binding */ isHtml), /* harmony export */ "isStyle": () => (/* binding */ isStyle), -/* harmony export */ "isSrcset": () => (/* binding */ isSrcset) +/* harmony export */ "isSrcset": () => (/* binding */ isSrcset), +/* harmony export */ "injectHead": () => (/* binding */ injectHead) /* harmony export */ }); function attributes(ctx, meta = ctx.meta) { - const { html, js, css, attributePrefix } = ctx; + const { html, js, css, attributePrefix, handlerScript, bundleScript } = ctx; const origPrefix = attributePrefix + '-attr-'; html.on('attr', (attr, type) => { @@ -35614,7 +35621,11 @@ function attributes(ctx, meta = ctx.meta) { if (type === 'rewrite' && isHtml(attr.name)) { attr.node.setAttribute(origPrefix + attr.name, attr.value); - attr.value = html.rewrite(attr.value, { ...meta, document: true }); + attr.value = html.rewrite(attr.value, { + ...meta, + document: true, + injectHead: attr.options.injectHead || [], + }); }; @@ -35748,6 +35759,53 @@ function isEvent(name) { ].indexOf(name) > -1; }; +function injectHead(ctx) { + const { html, js, css, attributePrefix } = ctx; + const origPrefix = attributePrefix + '-attr-'; + html.on('element', (element, type) => { + if (type !== 'rewrite') return false; + if (element.tagName !== 'head') return false; + if (!('injectHead' in element.options)) return false; + + element.childNodes.unshift( + ...element.options.injectHead + ); + }); +}; + +function createInjection(handler = '/uv.handler.js', bundle = '/uv.bundle.js', cookies = '', referrer = '') { + return [ + { + tagName: 'script', + nodeName: 'script', + childNodes: [ + { + nodeName: '#text', + value: `window.__uv$cookies = atob("${btoa(cookies)}");\nwindow.__uv$referrer = atob("${btoa(referrer)}");` + }, + ], + attrs: [], + skip: true, + }, + { + tagName: 'script', + nodeName: 'script', + childNodes: [], + attrs: [ + { name: 'src', value: bundle, skip: true } + ], + }, + { + tagName: 'script', + nodeName: 'script', + childNodes: [], + attrs: [ + { name: 'src', value: handler, skip: true } + ], + }, + ]; +}; + function isForbidden(name) { return ['http-equiv', 'integrity', 'sandbox', 'nonce', 'crossorigin'].indexOf(name) > -1; }; @@ -35844,8 +35902,21 @@ function property(ctx) { }); }; - if (node.object.type === esotope_hammerhead__WEBPACK_IMPORTED_MODULE_0__.Syntax.Identifier && node.object.name === 'eval') { - + + if (!node.computed && node.property.name === 'top' && type === 'rewrite' || node.property.name === '__uv$top' && type === 'source') { + data.changes.push({ + start: node.property.start, + end: node.property.end, + node: type === 'rewrite' ? '__uv$setSource(__uv).__uv$top' : 'top' + }); + }; + + if (!node.computed && node.property.name === 'parent' && type === 'rewrite' || node.property.name === '__uv$parent' && type === 'source') { + data.changes.push({ + start: node.property.start, + end: node.property.end, + node: type === 'rewrite' ? '__uv$setSource(__uv).__uv$parent' : 'parent' + }); }; @@ -35888,7 +35959,7 @@ function identifier(ctx) { js.on('Identifier', (node, data, type) => { if (type !== 'rewrite') return false; const { parent } = node; - if (!['location', 'eval'].includes(node.name)) return false; + if (!['location', 'eval', 'parent', 'top'].includes(node.name)) return false; if (parent.type === esotope_hammerhead__WEBPACK_IMPORTED_MODULE_0__.Syntax.VariableDeclarator && parent.id === node) return false; if ((parent.type === esotope_hammerhead__WEBPACK_IMPORTED_MODULE_0__.Syntax.AssignmentExpression || parent.type === esotope_hammerhead__WEBPACK_IMPORTED_MODULE_0__.Syntax.AssignmentPattern) && parent.left === node) return false; if ((parent.type === esotope_hammerhead__WEBPACK_IMPORTED_MODULE_0__.Syntax.FunctionExpression || parent.type === esotope_hammerhead__WEBPACK_IMPORTED_MODULE_0__.Syntax.FunctionDeclaration) && parent.id === node) return false; @@ -36037,7 +36108,7 @@ function isWrapped(node) { function computedProperty(parent) { if (!parent.computed) return false; const { property: node } = parent; - if (node.type === 'Literal' && node.value !== 'location') return false; + if (node.type === 'Literal' && !['location', 'top', 'parent']) {} return true; }; @@ -36373,6 +36444,8 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _worker_js__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(170); /* harmony import */ var _url_js__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(171); /* harmony import */ var _events_js__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(155); +/* harmony import */ var _storage_js__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(172); + @@ -36400,9 +36473,14 @@ class UVClient extends _events_js__WEBPACK_IMPORTED_MODULE_16__["default"] { defineProperty: this.window.Object.defineProperty, getOwnPropertyDescriptor: this.window.Object.getOwnPropertyDescriptor, getOwnPropertyDescriptors: this.window.Object.getOwnPropertyDescriptors, + getOwnPropertyNames: this.window.Object.getOwnPropertyNames, + keys: this.window.Object.keys, + getOwnPropertySymbols: this.window.Object.getOwnPropertySymbols, isArray: this.window.Array.isArray, setPrototypeOf: this.window.Object.setPrototypeOf, isExtensible: this.window.Object.isExtensible, + Map: this.window.Map, + Proxy: this.window.Proxy, }; this.worker = worker; this.fetch = new _requests_fetch_js__WEBPACK_IMPORTED_MODULE_6__["default"](this); @@ -36421,6 +36499,7 @@ class UVClient extends _events_js__WEBPACK_IMPORTED_MODULE_16__["default"] { this.url = new _url_js__WEBPACK_IMPORTED_MODULE_15__["default"](this); this.workers = new _worker_js__WEBPACK_IMPORTED_MODULE_14__["default"](this); this.location = new _location_js__WEBPACK_IMPORTED_MODULE_11__["default"](this); + this.storage = new _storage_js__WEBPACK_IMPORTED_MODULE_17__["default"](this); }; initLocation(rewriteUrl, sourceUrl) { this.location = new _location_js__WEBPACK_IMPORTED_MODULE_11__["default"](this, sourceUrl, rewriteUrl, this.worker); @@ -38291,6 +38370,18 @@ class LocationApi { }); }; + if ('ancestorOrigins' in this.location) { + this.ctx.nativeMethods.defineProperty(emulation, 'ancestorOrigins', { + get() { + const arr = []; + if (that.window.DOMStringList) that.ctx.nativeMethods.setPrototypeOf(arr, that.window.DOMStringList.prototype); + return arr; + }, + set: undefined, + enumerable: true, + }); + }; + this.ctx.nativeMethods.defineProperty(emulation, 'toString', { value: this.ctx.wrap(this.location, 'toString', () => { @@ -38577,6 +38668,179 @@ class URLApi extends _events_js__WEBPACK_IMPORTED_MODULE_0__["default"] { /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (URLApi); +/***/ }), +/* 172 */ +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _events_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(155); +/* harmony import */ var _hook_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(156); + + + +class StorageApi extends _events_js__WEBPACK_IMPORTED_MODULE_0__["default"] { + constructor(ctx) { + super(); + this.ctx = ctx; + this.window = ctx.window; + this.localStorage = this.window.localStorage || null; + this.sessionStorage = this.window.sessionStorage || null; + this.Storage = this.window.Storage || {}; + this.storeProto = this.Storage.prototype || {}; + this.getItem = this.storeProto.getItem || null; + this.setItem = this.storeProto.setItem || null; + this.removeItem = this.storeProto.removeItem || null; + this.clear = this.storeProto.clear || null; + this.key = this.storeProto.key || null; + this.methods = ['key', 'getItem', 'setItem', 'removeItem', 'clear']; + this.wrappers = new ctx.nativeMethods.Map(); + }; + overrideMethods() { + this.ctx.override(this.storeProto, 'getItem', (target, that, args) => { + if (!args.length) return target.apply((this.wrappers.get(that) || that), args); + let [ name ] = args; + + const event = new _hook_js__WEBPACK_IMPORTED_MODULE_1__["default"]({ name }, target, (this.wrappers.get(that) || that)); + this.emit('getItem', event); + + if (event.intercepted) return event.returnValue; + return event.target.call(event.that, event.data.name); + }); + this.ctx.override(this.storeProto, 'setItem', (target, that, args) => { + if (2 > args.length) return target.apply((this.wrappers.get(that) || that), args); + let [ name, value ] = args; + + const event = new _hook_js__WEBPACK_IMPORTED_MODULE_1__["default"]({ name, value }, target, (this.wrappers.get(that) || that)); + this.emit('setItem', event); + + if (event.intercepted) return event.returnValue; + return event.target.call(event.that, event.data.name, event.data.value); + }); + this.ctx.override(this.storeProto, 'removeItem', (target, that, args) => { + if (!args.length) return target.apply((this.wrappers.get(that) || that), args); + let [ name ] = args; + + const event = new _hook_js__WEBPACK_IMPORTED_MODULE_1__["default"]({ name }, target, (this.wrappers.get(that) || that)); + this.emit('removeItem', event); + + if (event.intercepted) return event.returnValue; + return event.target.call(event.that, event.data.name); + }); + this.ctx.override(this.storeProto, 'clear', (target, that) => { + const event = new _hook_js__WEBPACK_IMPORTED_MODULE_1__["default"](null, target, (this.wrappers.get(that) || that)); + this.emit('clear', event); + + if (event.intercepted) return event.returnValue; + return event.target.call(event.that); + }); + this.ctx.override(this.storeProto, 'key', (target, that, args) => { + if (!args.length) return target.apply((this.wrappers.get(that) || that), args); + let [ index ] = args; + + const event = new _hook_js__WEBPACK_IMPORTED_MODULE_1__["default"]({ index }, target, (this.wrappers.get(that) || that)); + this.emit('key', event); + + if (event.intercepted) return event.returnValue; + return event.target.call(event.that, event.data.index); + }); + }; + overrideLength() { + this.ctx.overrideDescriptor(this.storeProto, 'length', { + get: (target, that) => { + const event = new _hook_js__WEBPACK_IMPORTED_MODULE_1__["default"]({ length: target.call((this.wrappers.get(that) || that)) }, target, (this.wrappers.get(that) || that)); + this.emit('length', event); + + if (event.intercepted) return event.returnValue; + return event.data.length; + }, + }); + }; + emulate(storage, obj = {}) { + this.ctx.nativeMethods.setPrototypeOf(obj, this.storeProto); + + const proxy = new this.ctx.window.Proxy(obj, { + get: (target, prop) => { + if (prop in this.storeProto || typeof prop === 'symbol') return storage[prop]; + + const event = new _hook_js__WEBPACK_IMPORTED_MODULE_1__["default"]({ name: prop }, null, storage); + this.emit('get', event); + + if (event.intercepted) return event.returnValue; + return storage[event.data.name]; + }, + set: (target, prop, value) => { + if (prop in this.storeProto || typeof prop === 'symbol') return storage[prop] = value; + + const event = new _hook_js__WEBPACK_IMPORTED_MODULE_1__["default"]({ name: prop, value }, null, storage); + this.emit('set', event); + + if (event.intercepted) return event.returnValue; + + return storage[event.data.name] = event.data.value; + }, + deleteProperty: (target, prop) => { + if (typeof prop === 'symbol') return delete storage[prop]; + + const event = new _hook_js__WEBPACK_IMPORTED_MODULE_1__["default"]({ name: prop }, null, storage); + this.emit('delete', event); + + if (event.intercepted) return event.returnValue; + + return delete storage[event.data.name]; + }, + }); + + this.wrappers.set(proxy, storage); + this.ctx.nativeMethods.setPrototypeOf(proxy, this.storeProto); + + return proxy; + }; + +}; + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (StorageApi); + + +class StorageWrapper { + constructor(api, storage, wrap, unwrap, origin) { + this.api = api; + this.ctx = api.ctx; + this.storage = storage; + this.wrap = wrap; + this.unwrap = unwrap; + this.origin = origin; + this.emulation = {}; + }; + clear() { + for (const key in this.storage) { + const data = this.unwrap(key); + if (!data || data.origin !== this.origin) continue; + this.api.removeItem.call(this.storage, key); + }; + this.emulation = {}; + this.ctx.nativeMethods.setPrototypeOf(this.emulation, this.api.storeProto); + }; + __init() { + for (const key in this.storage) { + const data = this.unwrap(key); + if (!data || data.origin !== this.origin) continue; + + this.emulation[data.name] = this.api.getItem.call(this.storage, key); + }; + this.ctx.nativeMethods.setPrototypeOf(this.emulation, this.api.storeProto); + }; +}; + +/***/ }), +/* 173 */ +/***/ (function(module) { + +!function(e,t){ true?module.exports=t():0}(this,(function(){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var i=t[n]={i:n,l:!1,exports:{}};return e[n].call(i.exports,i,i.exports,r),i.l=!0,i.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)r.d(n,i,function(t){return e[t]}.bind(null,i));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=90)}({17:function(e,t,r){"use strict";t.__esModule=!0,t.default=void 0;var n=r(18),i=function(){function e(){}return e.getFirstMatch=function(e,t){var r=t.match(e);return r&&r.length>0&&r[1]||""},e.getSecondMatch=function(e,t){var r=t.match(e);return r&&r.length>1&&r[2]||""},e.matchAndReturnConst=function(e,t,r){if(e.test(t))return r},e.getWindowsVersionName=function(e){switch(e){case"NT":return"NT";case"XP":return"XP";case"NT 5.0":return"2000";case"NT 5.1":return"XP";case"NT 5.2":return"2003";case"NT 6.0":return"Vista";case"NT 6.1":return"7";case"NT 6.2":return"8";case"NT 6.3":return"8.1";case"NT 10.0":return"10";default:return}},e.getMacOSVersionName=function(e){var t=e.split(".").splice(0,2).map((function(e){return parseInt(e,10)||0}));if(t.push(0),10===t[0])switch(t[1]){case 5:return"Leopard";case 6:return"Snow Leopard";case 7:return"Lion";case 8:return"Mountain Lion";case 9:return"Mavericks";case 10:return"Yosemite";case 11:return"El Capitan";case 12:return"Sierra";case 13:return"High Sierra";case 14:return"Mojave";case 15:return"Catalina";default:return}},e.getAndroidVersionName=function(e){var t=e.split(".").splice(0,2).map((function(e){return parseInt(e,10)||0}));if(t.push(0),!(1===t[0]&&t[1]<5))return 1===t[0]&&t[1]<6?"Cupcake":1===t[0]&&t[1]>=6?"Donut":2===t[0]&&t[1]<2?"Eclair":2===t[0]&&2===t[1]?"Froyo":2===t[0]&&t[1]>2?"Gingerbread":3===t[0]?"Honeycomb":4===t[0]&&t[1]<1?"Ice Cream Sandwich":4===t[0]&&t[1]<4?"Jelly Bean":4===t[0]&&t[1]>=4?"KitKat":5===t[0]?"Lollipop":6===t[0]?"Marshmallow":7===t[0]?"Nougat":8===t[0]?"Oreo":9===t[0]?"Pie":void 0},e.getVersionPrecision=function(e){return e.split(".").length},e.compareVersions=function(t,r,n){void 0===n&&(n=!1);var i=e.getVersionPrecision(t),s=e.getVersionPrecision(r),a=Math.max(i,s),o=0,u=e.map([t,r],(function(t){var r=a-e.getVersionPrecision(t),n=t+new Array(r+1).join(".0");return e.map(n.split("."),(function(e){return new Array(20-e.length).join("0")+e})).reverse()}));for(n&&(o=a-Math.min(i,s)),a-=1;a>=o;){if(u[0][a]>u[1][a])return 1;if(u[0][a]===u[1][a]){if(a===o)return 0;a-=1}else if(u[0][a]1?i-1:0),a=1;a0){var a=Object.keys(r),u=o.default.find(a,(function(e){return t.isOS(e)}));if(u){var d=this.satisfies(r[u]);if(void 0!==d)return d}var c=o.default.find(a,(function(e){return t.isPlatform(e)}));if(c){var f=this.satisfies(r[c]);if(void 0!==f)return f}}if(s>0){var l=Object.keys(i),h=o.default.find(l,(function(e){return t.isBrowser(e,!0)}));if(void 0!==h)return this.compareVersion(i[h])}},t.isBrowser=function(e,t){void 0===t&&(t=!1);var r=this.getBrowserName().toLowerCase(),n=e.toLowerCase(),i=o.default.getBrowserTypeByAlias(n);return t&&i&&(n=i.toLowerCase()),n===r},t.compareVersion=function(e){var t=[0],r=e,n=!1,i=this.getBrowserVersion();if("string"==typeof i)return">"===e[0]||"<"===e[0]?(r=e.substr(1),"="===e[1]?(n=!0,r=e.substr(2)):t=[],">"===e[0]?t.push(1):t.push(-1)):"="===e[0]?r=e.substr(1):"~"===e[0]&&(n=!0,r=e.substr(1)),t.indexOf(o.default.compareVersions(i,r,n))>-1},t.isOS=function(e){return this.getOSName(!0)===String(e).toLowerCase()},t.isPlatform=function(e){return this.getPlatformType(!0)===String(e).toLowerCase()},t.isEngine=function(e){return this.getEngineName(!0)===String(e).toLowerCase()},t.is=function(e,t){return void 0===t&&(t=!1),this.isBrowser(e,t)||this.isOS(e)||this.isPlatform(e)},t.some=function(e){var t=this;return void 0===e&&(e=[]),e.some((function(e){return t.is(e)}))},e}();t.default=d,e.exports=t.default},92:function(e,t,r){"use strict";t.__esModule=!0,t.default=void 0;var n,i=(n=r(17))&&n.__esModule?n:{default:n};var s=/version\/(\d+(\.?_?\d+)+)/i,a=[{test:[/googlebot/i],describe:function(e){var t={name:"Googlebot"},r=i.default.getFirstMatch(/googlebot\/(\d+(\.\d+))/i,e)||i.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/opera/i],describe:function(e){var t={name:"Opera"},r=i.default.getFirstMatch(s,e)||i.default.getFirstMatch(/(?:opera)[\s/](\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/opr\/|opios/i],describe:function(e){var t={name:"Opera"},r=i.default.getFirstMatch(/(?:opr|opios)[\s/](\S+)/i,e)||i.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/SamsungBrowser/i],describe:function(e){var t={name:"Samsung Internet for Android"},r=i.default.getFirstMatch(s,e)||i.default.getFirstMatch(/(?:SamsungBrowser)[\s/](\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/Whale/i],describe:function(e){var t={name:"NAVER Whale Browser"},r=i.default.getFirstMatch(s,e)||i.default.getFirstMatch(/(?:whale)[\s/](\d+(?:\.\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/MZBrowser/i],describe:function(e){var t={name:"MZ Browser"},r=i.default.getFirstMatch(/(?:MZBrowser)[\s/](\d+(?:\.\d+)+)/i,e)||i.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/focus/i],describe:function(e){var t={name:"Focus"},r=i.default.getFirstMatch(/(?:focus)[\s/](\d+(?:\.\d+)+)/i,e)||i.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/swing/i],describe:function(e){var t={name:"Swing"},r=i.default.getFirstMatch(/(?:swing)[\s/](\d+(?:\.\d+)+)/i,e)||i.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/coast/i],describe:function(e){var t={name:"Opera Coast"},r=i.default.getFirstMatch(s,e)||i.default.getFirstMatch(/(?:coast)[\s/](\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/opt\/\d+(?:.?_?\d+)+/i],describe:function(e){var t={name:"Opera Touch"},r=i.default.getFirstMatch(/(?:opt)[\s/](\d+(\.?_?\d+)+)/i,e)||i.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/yabrowser/i],describe:function(e){var t={name:"Yandex Browser"},r=i.default.getFirstMatch(/(?:yabrowser)[\s/](\d+(\.?_?\d+)+)/i,e)||i.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/ucbrowser/i],describe:function(e){var t={name:"UC Browser"},r=i.default.getFirstMatch(s,e)||i.default.getFirstMatch(/(?:ucbrowser)[\s/](\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/Maxthon|mxios/i],describe:function(e){var t={name:"Maxthon"},r=i.default.getFirstMatch(s,e)||i.default.getFirstMatch(/(?:Maxthon|mxios)[\s/](\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/epiphany/i],describe:function(e){var t={name:"Epiphany"},r=i.default.getFirstMatch(s,e)||i.default.getFirstMatch(/(?:epiphany)[\s/](\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/puffin/i],describe:function(e){var t={name:"Puffin"},r=i.default.getFirstMatch(s,e)||i.default.getFirstMatch(/(?:puffin)[\s/](\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/sleipnir/i],describe:function(e){var t={name:"Sleipnir"},r=i.default.getFirstMatch(s,e)||i.default.getFirstMatch(/(?:sleipnir)[\s/](\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/k-meleon/i],describe:function(e){var t={name:"K-Meleon"},r=i.default.getFirstMatch(s,e)||i.default.getFirstMatch(/(?:k-meleon)[\s/](\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/micromessenger/i],describe:function(e){var t={name:"WeChat"},r=i.default.getFirstMatch(/(?:micromessenger)[\s/](\d+(\.?_?\d+)+)/i,e)||i.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/qqbrowser/i],describe:function(e){var t={name:/qqbrowserlite/i.test(e)?"QQ Browser Lite":"QQ Browser"},r=i.default.getFirstMatch(/(?:qqbrowserlite|qqbrowser)[/](\d+(\.?_?\d+)+)/i,e)||i.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/msie|trident/i],describe:function(e){var t={name:"Internet Explorer"},r=i.default.getFirstMatch(/(?:msie |rv:)(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/\sedg\//i],describe:function(e){var t={name:"Microsoft Edge"},r=i.default.getFirstMatch(/\sedg\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/edg([ea]|ios)/i],describe:function(e){var t={name:"Microsoft Edge"},r=i.default.getSecondMatch(/edg([ea]|ios)\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/vivaldi/i],describe:function(e){var t={name:"Vivaldi"},r=i.default.getFirstMatch(/vivaldi\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/seamonkey/i],describe:function(e){var t={name:"SeaMonkey"},r=i.default.getFirstMatch(/seamonkey\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/sailfish/i],describe:function(e){var t={name:"Sailfish"},r=i.default.getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i,e);return r&&(t.version=r),t}},{test:[/silk/i],describe:function(e){var t={name:"Amazon Silk"},r=i.default.getFirstMatch(/silk\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/phantom/i],describe:function(e){var t={name:"PhantomJS"},r=i.default.getFirstMatch(/phantomjs\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/slimerjs/i],describe:function(e){var t={name:"SlimerJS"},r=i.default.getFirstMatch(/slimerjs\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/blackberry|\bbb\d+/i,/rim\stablet/i],describe:function(e){var t={name:"BlackBerry"},r=i.default.getFirstMatch(s,e)||i.default.getFirstMatch(/blackberry[\d]+\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/(web|hpw)[o0]s/i],describe:function(e){var t={name:"WebOS Browser"},r=i.default.getFirstMatch(s,e)||i.default.getFirstMatch(/w(?:eb)?[o0]sbrowser\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/bada/i],describe:function(e){var t={name:"Bada"},r=i.default.getFirstMatch(/dolfin\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/tizen/i],describe:function(e){var t={name:"Tizen"},r=i.default.getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.?_?\d+)+)/i,e)||i.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/qupzilla/i],describe:function(e){var t={name:"QupZilla"},r=i.default.getFirstMatch(/(?:qupzilla)[\s/](\d+(\.?_?\d+)+)/i,e)||i.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/firefox|iceweasel|fxios/i],describe:function(e){var t={name:"Firefox"},r=i.default.getFirstMatch(/(?:firefox|iceweasel|fxios)[\s/](\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/electron/i],describe:function(e){var t={name:"Electron"},r=i.default.getFirstMatch(/(?:electron)\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/MiuiBrowser/i],describe:function(e){var t={name:"Miui"},r=i.default.getFirstMatch(/(?:MiuiBrowser)[\s/](\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/chromium/i],describe:function(e){var t={name:"Chromium"},r=i.default.getFirstMatch(/(?:chromium)[\s/](\d+(\.?_?\d+)+)/i,e)||i.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/chrome|crios|crmo/i],describe:function(e){var t={name:"Chrome"},r=i.default.getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/GSA/i],describe:function(e){var t={name:"Google Search"},r=i.default.getFirstMatch(/(?:GSA)\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:function(e){var t=!e.test(/like android/i),r=e.test(/android/i);return t&&r},describe:function(e){var t={name:"Android Browser"},r=i.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/playstation 4/i],describe:function(e){var t={name:"PlayStation 4"},r=i.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/safari|applewebkit/i],describe:function(e){var t={name:"Safari"},r=i.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/.*/i],describe:function(e){var t=-1!==e.search("\\(")?/^(.*)\/(.*)[ \t]\((.*)/:/^(.*)\/(.*) /;return{name:i.default.getFirstMatch(t,e),version:i.default.getSecondMatch(t,e)}}}];t.default=a,e.exports=t.default},93:function(e,t,r){"use strict";t.__esModule=!0,t.default=void 0;var n,i=(n=r(17))&&n.__esModule?n:{default:n},s=r(18);var a=[{test:[/Roku\/DVP/],describe:function(e){var t=i.default.getFirstMatch(/Roku\/DVP-(\d+\.\d+)/i,e);return{name:s.OS_MAP.Roku,version:t}}},{test:[/windows phone/i],describe:function(e){var t=i.default.getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i,e);return{name:s.OS_MAP.WindowsPhone,version:t}}},{test:[/windows /i],describe:function(e){var t=i.default.getFirstMatch(/Windows ((NT|XP)( \d\d?.\d)?)/i,e),r=i.default.getWindowsVersionName(t);return{name:s.OS_MAP.Windows,version:t,versionName:r}}},{test:[/Macintosh(.*?) FxiOS(.*?)\//],describe:function(e){var t={name:s.OS_MAP.iOS},r=i.default.getSecondMatch(/(Version\/)(\d[\d.]+)/,e);return r&&(t.version=r),t}},{test:[/macintosh/i],describe:function(e){var t=i.default.getFirstMatch(/mac os x (\d+(\.?_?\d+)+)/i,e).replace(/[_\s]/g,"."),r=i.default.getMacOSVersionName(t),n={name:s.OS_MAP.MacOS,version:t};return r&&(n.versionName=r),n}},{test:[/(ipod|iphone|ipad)/i],describe:function(e){var t=i.default.getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i,e).replace(/[_\s]/g,".");return{name:s.OS_MAP.iOS,version:t}}},{test:function(e){var t=!e.test(/like android/i),r=e.test(/android/i);return t&&r},describe:function(e){var t=i.default.getFirstMatch(/android[\s/-](\d+(\.\d+)*)/i,e),r=i.default.getAndroidVersionName(t),n={name:s.OS_MAP.Android,version:t};return r&&(n.versionName=r),n}},{test:[/(web|hpw)[o0]s/i],describe:function(e){var t=i.default.getFirstMatch(/(?:web|hpw)[o0]s\/(\d+(\.\d+)*)/i,e),r={name:s.OS_MAP.WebOS};return t&&t.length&&(r.version=t),r}},{test:[/blackberry|\bbb\d+/i,/rim\stablet/i],describe:function(e){var t=i.default.getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i,e)||i.default.getFirstMatch(/blackberry\d+\/(\d+([_\s]\d+)*)/i,e)||i.default.getFirstMatch(/\bbb(\d+)/i,e);return{name:s.OS_MAP.BlackBerry,version:t}}},{test:[/bada/i],describe:function(e){var t=i.default.getFirstMatch(/bada\/(\d+(\.\d+)*)/i,e);return{name:s.OS_MAP.Bada,version:t}}},{test:[/tizen/i],describe:function(e){var t=i.default.getFirstMatch(/tizen[/\s](\d+(\.\d+)*)/i,e);return{name:s.OS_MAP.Tizen,version:t}}},{test:[/linux/i],describe:function(){return{name:s.OS_MAP.Linux}}},{test:[/CrOS/],describe:function(){return{name:s.OS_MAP.ChromeOS}}},{test:[/PlayStation 4/],describe:function(e){var t=i.default.getFirstMatch(/PlayStation 4[/\s](\d+(\.\d+)*)/i,e);return{name:s.OS_MAP.PlayStation4,version:t}}}];t.default=a,e.exports=t.default},94:function(e,t,r){"use strict";t.__esModule=!0,t.default=void 0;var n,i=(n=r(17))&&n.__esModule?n:{default:n},s=r(18);var a=[{test:[/googlebot/i],describe:function(){return{type:"bot",vendor:"Google"}}},{test:[/huawei/i],describe:function(e){var t=i.default.getFirstMatch(/(can-l01)/i,e)&&"Nova",r={type:s.PLATFORMS_MAP.mobile,vendor:"Huawei"};return t&&(r.model=t),r}},{test:[/nexus\s*(?:7|8|9|10).*/i],describe:function(){return{type:s.PLATFORMS_MAP.tablet,vendor:"Nexus"}}},{test:[/ipad/i],describe:function(){return{type:s.PLATFORMS_MAP.tablet,vendor:"Apple",model:"iPad"}}},{test:[/Macintosh(.*?) FxiOS(.*?)\//],describe:function(){return{type:s.PLATFORMS_MAP.tablet,vendor:"Apple",model:"iPad"}}},{test:[/kftt build/i],describe:function(){return{type:s.PLATFORMS_MAP.tablet,vendor:"Amazon",model:"Kindle Fire HD 7"}}},{test:[/silk/i],describe:function(){return{type:s.PLATFORMS_MAP.tablet,vendor:"Amazon"}}},{test:[/tablet(?! pc)/i],describe:function(){return{type:s.PLATFORMS_MAP.tablet}}},{test:function(e){var t=e.test(/ipod|iphone/i),r=e.test(/like (ipod|iphone)/i);return t&&!r},describe:function(e){var t=i.default.getFirstMatch(/(ipod|iphone)/i,e);return{type:s.PLATFORMS_MAP.mobile,vendor:"Apple",model:t}}},{test:[/nexus\s*[0-6].*/i,/galaxy nexus/i],describe:function(){return{type:s.PLATFORMS_MAP.mobile,vendor:"Nexus"}}},{test:[/[^-]mobi/i],describe:function(){return{type:s.PLATFORMS_MAP.mobile}}},{test:function(e){return"blackberry"===e.getBrowserName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.mobile,vendor:"BlackBerry"}}},{test:function(e){return"bada"===e.getBrowserName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.mobile}}},{test:function(e){return"windows phone"===e.getBrowserName()},describe:function(){return{type:s.PLATFORMS_MAP.mobile,vendor:"Microsoft"}}},{test:function(e){var t=Number(String(e.getOSVersion()).split(".")[0]);return"android"===e.getOSName(!0)&&t>=3},describe:function(){return{type:s.PLATFORMS_MAP.tablet}}},{test:function(e){return"android"===e.getOSName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.mobile}}},{test:function(e){return"macos"===e.getOSName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.desktop,vendor:"Apple"}}},{test:function(e){return"windows"===e.getOSName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.desktop}}},{test:function(e){return"linux"===e.getOSName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.desktop}}},{test:function(e){return"playstation 4"===e.getOSName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.tv}}},{test:function(e){return"roku"===e.getOSName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.tv}}}];t.default=a,e.exports=t.default},95:function(e,t,r){"use strict";t.__esModule=!0,t.default=void 0;var n,i=(n=r(17))&&n.__esModule?n:{default:n},s=r(18);var a=[{test:function(e){return"microsoft edge"===e.getBrowserName(!0)},describe:function(e){if(/\sedg\//i.test(e))return{name:s.ENGINE_MAP.Blink};var t=i.default.getFirstMatch(/edge\/(\d+(\.?_?\d+)+)/i,e);return{name:s.ENGINE_MAP.EdgeHTML,version:t}}},{test:[/trident/i],describe:function(e){var t={name:s.ENGINE_MAP.Trident},r=i.default.getFirstMatch(/trident\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:function(e){return e.test(/presto/i)},describe:function(e){var t={name:s.ENGINE_MAP.Presto},r=i.default.getFirstMatch(/presto\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:function(e){var t=e.test(/gecko/i),r=e.test(/like gecko/i);return t&&!r},describe:function(e){var t={name:s.ENGINE_MAP.Gecko},r=i.default.getFirstMatch(/gecko\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/(apple)?webkit\/537\.36/i],describe:function(){return{name:s.ENGINE_MAP.Blink}}},{test:[/(apple)?webkit/i],describe:function(e){var t={name:s.ENGINE_MAP.WebKit},r=i.default.getFirstMatch(/webkit\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}}];t.default=a,e.exports=t.default}})})); + /***/ }) /******/ ]); /************************************************************************/ @@ -38598,7 +38862,7 @@ class URLApi extends _events_js__WEBPACK_IMPORTED_MODULE_0__["default"] { /******/ }; /******/ /******/ // Execute the module function -/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Return the exports of the module /******/ return module.exports; @@ -38651,10 +38915,11 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _cookie_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(147); /* harmony import */ var _rewrite_html_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(148); /* harmony import */ var _rewrite_css_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(149); -/* harmony import */ var _rewrite_script_test_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(150); +/* harmony import */ var _rewrite_script_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(150); /* harmony import */ var idb__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(151); /* harmony import */ var _parsel_js__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(138); /* harmony import */ var _client_index_js__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(153); +/* harmony import */ var bowser__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(173); @@ -38670,6 +38935,8 @@ __webpack_require__.r(__webpack_exports__); + + const valid_chars = "!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~"; const reserved_chars = "%"; @@ -38686,6 +38953,8 @@ class Ultraviolet { this.meta = options.meta || {}; this.meta.base ||= undefined; this.meta.origin ||= ''; + this.bundleScript = options.bundleScript || '/uv.bundle.js'; + this.handlerScript = options.handlerScript || '/uv.handler.js'; this.meta.url ||= this.meta.base || ''; this.codec = Ultraviolet.codec; this.html = new _html_js__WEBPACK_IMPORTED_MODULE_0__["default"](this); @@ -38693,10 +38962,12 @@ class Ultraviolet { this.js = new _js_js__WEBPACK_IMPORTED_MODULE_2__["default"](this); this.parsel = _parsel_js__WEBPACK_IMPORTED_MODULE_11__["default"]; this.openDB = this.constructor.openDB; + this.Bowser = this.constructor.Bowser; this.client = typeof self !== 'undefined' ? new _client_index_js__WEBPACK_IMPORTED_MODULE_12__["default"]((options.window || self)) : null; this.master = '__uv'; this.dataPrefix = '__uv$'; this.attributePrefix = '__uv'; + this.createHtmlInject = _rewrite_html_js__WEBPACK_IMPORTED_MODULE_7__.createInjection; this.attrs = { isUrl: _rewrite_html_js__WEBPACK_IMPORTED_MODULE_7__.isUrl, isForbidden: _rewrite_html_js__WEBPACK_IMPORTED_MODULE_7__.isForbidden, @@ -38790,31 +39061,17 @@ class Ultraviolet { // HTML (0,_rewrite_html_js__WEBPACK_IMPORTED_MODULE_7__.attributes)(this); (0,_rewrite_html_js__WEBPACK_IMPORTED_MODULE_7__.text)(this); - + (0,_rewrite_html_js__WEBPACK_IMPORTED_MODULE_7__.injectHead)(this); // CSS (0,_rewrite_css_js__WEBPACK_IMPORTED_MODULE_8__.url)(this); (0,_rewrite_css_js__WEBPACK_IMPORTED_MODULE_8__.importStyle)(this); - // JS - /* - getProperty(this); - call(this) - setProperty(this); - sourceMethods(this); - importDeclaration(this); - dynamicImport(this); - wrapEval(this); - wrapIdentifier(this) - */ - - (0,_rewrite_script_test_js__WEBPACK_IMPORTED_MODULE_9__.importDeclaration)(this); - (0,_rewrite_script_test_js__WEBPACK_IMPORTED_MODULE_9__.dynamicImport)(this); - (0,_rewrite_script_test_js__WEBPACK_IMPORTED_MODULE_9__.property)(this); - (0,_rewrite_script_test_js__WEBPACK_IMPORTED_MODULE_9__.wrapEval)(this); - (0,_rewrite_script_test_js__WEBPACK_IMPORTED_MODULE_9__.identifier)(this); - (0,_rewrite_script_test_js__WEBPACK_IMPORTED_MODULE_9__.unwrap)(this); - - //destructureDeclaration(this) + (0,_rewrite_script_js__WEBPACK_IMPORTED_MODULE_9__.importDeclaration)(this); + (0,_rewrite_script_js__WEBPACK_IMPORTED_MODULE_9__.dynamicImport)(this); + (0,_rewrite_script_js__WEBPACK_IMPORTED_MODULE_9__.property)(this); + (0,_rewrite_script_js__WEBPACK_IMPORTED_MODULE_9__.wrapEval)(this); + (0,_rewrite_script_js__WEBPACK_IMPORTED_MODULE_9__.identifier)(this); + (0,_rewrite_script_js__WEBPACK_IMPORTED_MODULE_9__.unwrap)(this); }; get rewriteHtml() { return this.html.rewrite.bind(this.html); @@ -38838,6 +39095,7 @@ class Ultraviolet { static mime = _mime_js__WEBPACK_IMPORTED_MODULE_5__["default"]; static setCookie = set_cookie_parser__WEBPACK_IMPORTED_MODULE_3__; static openDB = idb__WEBPACK_IMPORTED_MODULE_10__.openDB; + static Bowser = bowser__WEBPACK_IMPORTED_MODULE_13__; }; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Ultraviolet); diff --git a/lib/uv.handler.js b/lib/uv.handler.js index 5985871..c3b2b79 100644 --- a/lib/uv.handler.js +++ b/lib/uv.handler.js @@ -1,7 +1,15 @@ +if (!self.__uv) { + __uvHook(self, { + prefix: '/sw/', + encodeUrl: Ultraviolet.codec.xor.encode, + decodeUrl: Ultraviolet.codec.xor.decode, + }); +}; + async function __uvHook(window, config = {}) { if ('__uv' in window && window.__uv instanceof Ultraviolet) return false; - + const worker = !window.window; const master = '__uv'; const methodPrefix = '__uv$'; @@ -9,23 +17,23 @@ async function __uvHook(window, config = {}) { ...config, window, }); - + const { client } = __uv; const { HTMLMediaElement, - HTMLScriptElement, - HTMLAudioElement, - HTMLVideoElement, - HTMLInputElement, - HTMLEmbedElement, - HTMLTrackElement, - HTMLAnchorElement, + HTMLScriptElement, + HTMLAudioElement, + HTMLVideoElement, + HTMLInputElement, + HTMLEmbedElement, + HTMLTrackElement, + HTMLAnchorElement, HTMLIFrameElement, HTMLAreaElement, - HTMLLinkElement, + HTMLLinkElement, HTMLBaseElement, HTMLFormElement, - HTMLImageElement, + HTMLImageElement, HTMLSourceElement, } = window; @@ -34,9 +42,10 @@ async function __uvHook(window, config = {}) { enumerable: false, }); - __uv.meta.origin = location.origin; + __uv.meta.origin = location.origin; __uv.location = client.location.emulate( (href) => { + if (href === 'about:srcdoc') return new URL(href); if (href.startsWith('blob:')) href = href.slice('blob:'.length); return new URL(__uv.sourceUrl(href)); }, @@ -51,8 +60,46 @@ async function __uvHook(window, config = {}) { __uv.blobUrls = new window.Map(); __uv.referrer = ''; __uv.cookies = []; + __uv.localStorageObj = {}; + __uv.sessionStorageObj = {}; - let rawBase = window.document ? client.node.baseURI.get.call(window.document) : window.location.href; + if (__uv.location.href === 'about:srcdoc') { + __uv.meta = window.parent.__uv.meta; + }; + + // Storage wrappers + + client.nativeMethods.defineProperty(client.storage.storeProto, '__uv$storageObj', { + get() { + if (this === client.storage.sessionStorage) return __uv.sessionStorageObj; + if (this === client.storage.localStorage) return __uv.localStorageObj; + }, + enumerable: false, + }); + + if (window.localStorage) { + for (const key in window.localStorage) { + if (key.startsWith(methodPrefix + __uv.location.origin + '@')) { + __uv.localStorageObj[key.slice((methodPrefix + __uv.location.origin + '@').length)] = window.localStorage.getItem(key); + }; + }; + + __uv.lsWrap = client.storage.emulate(client.storage.localStorage, __uv.localStorageObj); + }; + + if (window.sessionStorage) { + for (const key in window.sessionStorage) { + if (key.startsWith(methodPrefix + __uv.location.origin + '@')) { + __uv.sessionStorageObj[key.slice((methodPrefix + __uv.location.origin + '@').length)] = window.sessionStorage.getItem(key); + }; + }; + + __uv.ssWrap = client.storage.emulate(client.storage.sessionStorage, __uv.sessionStorageObj); + }; + + + + let rawBase = window.document ? client.node.baseURI.get.call(window.document) : window.location.href; let base = __uv.sourceUrl(rawBase); client.nativeMethods.defineProperty(__uv.meta, 'base', { @@ -76,6 +123,8 @@ async function __uvHook(window, config = {}) { function: methodPrefix + 'function', string: methodPrefix + 'string', eval: methodPrefix + 'eval', + parent: methodPrefix + 'parent', + top: methodPrefix + 'top', }; __uv.filterKeys = [ @@ -86,10 +135,13 @@ async function __uvHook(window, config = {}) { __uv.methods.function, __uv.methods.string, __uv.methods.eval, + __uv.methods.parent, + __uv.methods.top, + methodPrefix + 'storageObj', 'Ultraviolet', '__uvHook', ]; - + client.on('wrap', (target, wrapped) => { client.nativeMethods.defineProperty(wrapped, 'name', client.nativeMethods.getOwnPropertyDescriptor(target, 'name')); @@ -106,7 +158,7 @@ async function __uvHook(window, config = {}) { }); }); - client.fetch.on('request', event => { + client.fetch.on('request', event => { event.data.input = __uv.rewriteUrl(event.data.input); }); @@ -127,7 +179,7 @@ async function __uvHook(window, config = {}) { event.data.value = __uv.sourceUrl(event.data.value); }); - + // Workers client.workers.on('worker', event => { event.data.url = __uv.rewriteUrl(event.data.url); @@ -140,7 +192,7 @@ async function __uvHook(window, config = {}) { client.workers.on('importScripts', event => { for (const i in event.data.scripts) { event.data.scripts[i] = __uv.rewriteUrl(event.data.scripts[i]); - }; + }; }); client.workers.on('postMessage', event => { @@ -156,16 +208,16 @@ async function __uvHook(window, config = {}) { // Navigator client.navigator.on('sendBeacon', event => { - event.data.url = __uv.rewriteUrl(event.data.url); + event.data.url = __uv.rewriteUrl(event.data.url); }); // Cookies client.document.on('getCookie', event => { event.data.value = __uv.cookieStr; }); - + client.document.on('setCookie', event => { - Promise.resolve(__uv.cookie.setCookies(event.data.value, __uv.db, __uv.meta)).then(() => { + Promise.resolve(__uv.cookie.setCookies(event.data.value, __uv.db, __uv.meta)).then(() => { __uv.cookie.db().then(db => { __uv.cookie.getCookies(db).then(cookies => { __uv.cookieStr = __uv.cookie.serialize(cookies, __uv.meta, true); @@ -187,7 +239,7 @@ async function __uvHook(window, config = {}) { // HTML client.element.on('setInnerHTML', event => { - switch(event.that.tagName) { + switch (event.that.tagName) { case 'SCRIPT': event.data.value = __uv.js.rewrite(event.data.value); break; @@ -200,7 +252,7 @@ async function __uvHook(window, config = {}) { }); client.element.on('getInnerHTML', event => { - switch(event.that.tagName) { + switch (event.that.tagName) { case 'SCRIPT': event.data.value = __uv.js.source(event.data.value); break; @@ -213,8 +265,8 @@ async function __uvHook(window, config = {}) { event.data.value = __uv.rewriteHtml(event.data.value, { document: event.that.tagName === 'HTML' }); }); - client.element.on('getOuterHTML', event => { - switch(event.that.tagName) { + client.element.on('getOuterHTML', event => { + switch (event.that.tagName) { case 'HEAD': event.data.value = __uv.sourceHtml( event.data.value.replace(/(.*)<\/head>/s, '$2') @@ -230,17 +282,17 @@ async function __uvHook(window, config = {}) { break; }; - //event.data.value = __uv.sourceHtml(event.data.value, { document: event.that.tagName === 'HTML' }); + //event.data.value = __uv.sourceHtml(event.data.value, { document: event.that.tagName === 'HTML' }); }); client.document.on('write', event => { if (!event.data.html.length) return false; - event.data.html = [ __uv.rewriteHtml(event.data.html.join('')) ]; + event.data.html = [__uv.rewriteHtml(event.data.html.join(''))]; }); client.document.on('writeln', event => { if (!event.data.html.length) return false; - event.data.html = [ __uv.rewriteHtml(event.data.html.join('')) ]; + event.data.html = [__uv.rewriteHtml(event.data.html.join(''))]; }); client.element.on('insertAdjacentHTML', event => { @@ -260,10 +312,10 @@ async function __uvHook(window, config = {}) { // History client.history.on('replaceState', event => { - if (event.data.url) event.data.url = __uv.rewriteUrl(event.data.url, '__uv' in event.that ? event.that.__uv.meta : __uv.meta); + if (event.data.url) event.data.url = __uv.rewriteUrl(event.data.url, '__uv' in event.that ? event.that.__uv.meta : __uv.meta); }); client.history.on('pushState', event => { - if (event.data.url) event.data.url = __uv.rewriteUrl(event.data.url, '__uv' in event.that ? event.that.__uv.meta : __uv.meta); + if (event.data.url) event.data.url = __uv.rewriteUrl(event.data.url, '__uv' in event.that ? event.that.__uv.meta : __uv.meta); }); // Element get set attribute methods @@ -280,7 +332,7 @@ async function __uvHook(window, config = {}) { let to = event.data.origin; let call = __uv.call; - + if (event.that) { call = event.that.__uv$source.call; }; @@ -293,9 +345,9 @@ async function __uvHook(window, config = {}) { }; event.respondWith( - worker ? - call(event.target, [ event.data.message, event.data.transfer ], event.that) : - call(event.target, [ event.data.message, event.data.origin, event.data.transfer ], event.that) + worker ? + call(event.target, [event.data.message, event.data.transfer], event.that) : + call(event.target, [event.data.message, event.data.origin, event.data.transfer], event.that) ); }); @@ -343,38 +395,43 @@ async function __uvHook(window, config = {}) { if (__uv.attrs.isHtml(event.data.name)) { event.target.call(event.that, __uv.attributePrefix + '-attr-' + event.data.name, event.data.value); - event.data.value = __uv.rewriteHtml(event.data.value, { ...__uv.meta, document: true }); + event.data.value = __uv.rewriteHtml(event.data.value, {...__uv.meta, document: true, injectHead: __uv.createHtmlInject(__uv.handlerScript, __uv.bundleScript, __uv.cookieStr, window.location.href) }); + }; + + if (__uv.attrs.isSrcset(event.data.name)) { + event.target.call(event.that, __uv.attributePrefix + '-attr-' + event.data.name, event.data.value); + event.data.value = __uv.html.wrapSrcset(event.data.value); }; if (__uv.attrs.isForbidden(event.data.name)) { event.data.name = __uv.attributePrefix + '-attr-' + event.data.name; }; - }); + }); client.element.on('audio', event => { event.data.url = __uv.rewriteUrl(event.data.url); }); // Element Property Attributes - client.element.hookProperty([ HTMLAnchorElement, HTMLAreaElement, HTMLLinkElement, HTMLBaseElement ], 'href', { + client.element.hookProperty([HTMLAnchorElement, HTMLAreaElement, HTMLLinkElement, HTMLBaseElement], 'href', { get: (target, that) => { return __uv.sourceUrl( target.call(that) ); }, - set: (target, that, [ val ]) => { + set: (target, that, [val]) => { client.element.setAttribute.call(that, __uv.attributePrefix + '-attr-href', val) target.call(that, __uv.rewriteUrl(val)); }, }); - client.element.hookProperty([ HTMLScriptElement, HTMLMediaElement, HTMLImageElement, HTMLInputElement, HTMLEmbedElement, HTMLIFrameElement, HTMLTrackElement, HTMLSourceElement ], 'src', { + client.element.hookProperty([HTMLScriptElement, HTMLMediaElement, HTMLImageElement, HTMLInputElement, HTMLEmbedElement, HTMLIFrameElement, HTMLTrackElement, HTMLSourceElement], 'src', { get: (target, that) => { return __uv.sourceUrl( target.call(that) ); }, - set: (target, that, [ val ]) => { + set: (target, that, [val]) => { if (new String(val).toString().trim().startsWith('blob:') && that instanceof HTMLMediaElement) { client.element.setAttribute.call(that, __uv.attributePrefix + '-attr-src', val) return target.call(that, __uv.blobUrls.get(val) || val); @@ -385,32 +442,42 @@ async function __uvHook(window, config = {}) { }, }); - client.element.hookProperty([ HTMLFormElement ], 'action', { + client.element.hookProperty([HTMLFormElement], 'action', { get: (target, that) => { return __uv.sourceUrl( target.call(that) ); }, - set: (target, that, [ val ]) => { + set: (target, that, [val]) => { client.element.setAttribute.call(that, __uv.attributePrefix + '-attr-action', val) target.call(that, __uv.rewriteUrl(val)); }, }); + client.element.hookProperty([HTMLImageElement], 'srcset', { + get: (target, that) => { + return client.element.getAttribute.call(that, __uv.attributePrefix + '-attr-srcset') || target.call(that); + }, + set: (target, that, [val]) => { + client.element.setAttribute.call(that, __uv.attributePrefix + '-attr-srcset', val) + target.call(that, __uv.html.wrapSrcset(val)); + }, + }); + client.element.hookProperty(HTMLScriptElement, 'integrity', { get: (target, that) => { return client.element.getAttribute.call(that, __uv.attributePrefix + '-attr-integrity'); }, - set: (target, that, [ val ]) => { + set: (target, that, [val]) => { client.element.setAttribute.call(that, __uv.attributePrefix + '-attr-integrity', val); }, }); - + client.element.hookProperty(HTMLIFrameElement, 'sandbox', { get: (target, that) => { return client.element.getAttribute.call(that, __uv.attributePrefix + '-attr-sandbox') || target.call(that); }, - set: (target, that, [ val ]) => { + set: (target, that, [val]) => { client.element.setAttribute.call(that, __uv.attributePrefix + '-attr-sandbox', val); }, }); @@ -419,9 +486,9 @@ async function __uvHook(window, config = {}) { get: (target, that) => { const win = target.call(that); try { - if (!win.__uv) __uvHook(win); + if (!win.__uv) __uvHook(win, config); return win; - } catch(e) { + } catch (e) { return win; }; }, @@ -432,14 +499,26 @@ async function __uvHook(window, config = {}) { const doc = target.call(that); try { const win = doc.defaultView - if (!win.__uv) __uvHook(win); + if (!win.__uv) __uvHook(win, config); return doc; - } catch(e) { + } catch (e) { return win; }; }, }); + client.element.hookProperty(HTMLIFrameElement, 'srcdoc', { + get: (target, that) => { + return client.element.getAttribute.call(that, __uv.attributePrefix + '-attr-srcdoc') || target.call(that); + }, + set: (target, that, [val]) => { + target.call(that, __uv.rewriteHtml(val, { + document: true, + injectHead: __uv.createHtmlInject(__uv.handlerScript, __uv.bundleScript, __uv.cookieStr, window.location.href) + })) + }, + }); + client.node.on('getTextContent', event => { if (event.that.tagName === 'SCRIPT') { event.data.value = __uv.js.source(event.data.value); @@ -453,7 +532,7 @@ async function __uvHook(window, config = {}) { }); // Document - client.document.on('getDomain', event => { + client.document.on('getDomain', event => { event.data.value = __uv.domain; }); client.document.on('setDomain', event => { @@ -475,7 +554,7 @@ async function __uvHook(window, config = {}) { client.document.on('parseFromString', event => { if (event.data.type !== 'text/html') return false; - event.data.string = __uv.rewriteHtml(event.data.string, { ...__uv.meta, document: true, }); + event.data.string = __uv.rewriteHtml(event.data.string, {...__uv.meta, document: true, }); }); // Attribute (node.attributes) @@ -498,17 +577,14 @@ async function __uvHook(window, config = {}) { if (__uv.attrs.isHtml(event.data.name)) { client.element.setAttribute.call(event.that.ownerElement, __uv.attributePrefix + '-attr-' + event.data.name, event.data.value); - event.data.value = __uv.rewriteHtml(event.data.value, { ...__uv.meta, document: true }); + event.data.value = __uv.rewriteHtml(event.data.value, {...__uv.meta, document: true, injectHead: __uv.createHtmlInject(__uv.handlerScript, __uv.bundleScript, __uv.cookieStr, window.location.href) }); }; - - }); - client.override(window.JSON, 'stringify', (target, that, args) => { - try { - return target.apply(that, args); - } catch (e) { - console.log(e, 'Error', args); + if (__uv.attrs.isSrcset(event.data.name)) { + client.element.setAttribute.call(event.that.ownerElement, __uv.attributePrefix + '-attr-' + event.data.name, event.data.value); + event.data.value = __uv.html.wrapSrcset(event.data.value); }; + }); // URL @@ -532,6 +608,70 @@ async function __uvHook(window, config = {}) { }; }); + client.storage.on('refresh', event => { + + }); + + client.storage.on('get', event => { + event.data.name = methodPrefix + __uv.meta.url.origin + '@' + event.data.name; + }); + + client.storage.on('set', event => { + if (event.that.__uv$storageObj) { + event.that.__uv$storageObj[event.data.name] = event.data.value; + }; + event.data.name = methodPrefix + __uv.meta.url.origin + '@' + event.data.name; + }); + + client.storage.on('delete', event => { + if (event.that.__uv$storageObj) { + delete event.that.__uv$storageObj[event.data.name]; + }; + event.data.name = methodPrefix + __uv.meta.url.origin + '@' + event.data.name; + }); + + client.storage.on('getItem', event => { + event.data.name = methodPrefix + __uv.meta.url.origin + '@' + event.data.name; + }); + + client.storage.on('setItem', event => { + if (event.that.__uv$storageObj) { + event.that.__uv$storageObj[event.data.name] = event.data.value; + }; + event.data.name = methodPrefix + __uv.meta.url.origin + '@' + event.data.name; + }); + + client.storage.on('removeItem', event => { + if (event.that.__uv$storageObj) { + delete event.that.__uv$storageObj[event.data.name]; + }; + event.data.name = methodPrefix + __uv.meta.url.origin + '@' + event.data.name; + }); + + client.storage.on('clear', event => { + if (event.that.__uv$storageObj) { + for (const key of client.nativeMethods.keys.call(null, event.that.__uv$storageObj)) { + delete event.that.__uv$storageObj[key]; + client.storage.removeItem.call(event.that, methodPrefix + __uv.meta.url.origin + '@' + key); + event.respondWith(); + }; + }; + }); + + client.storage.on('length', event => { + if (event.that.__uv$storageObj) { + event.respondWith(client.nativeMethods.keys.call(null, event.that.__uv$storageObj).length); + }; + }); + + client.storage.on('key', event => { + if (event.that.__uv$storageObj) { + event.respondWith( + (client.nativeMethods.keys.call(null, event.that.__uv$storageObj)[event.data.index] || null) + ); + }; + }); + client.websocket.on('websocket', event => { const url = new URL(event.data.url); @@ -557,7 +697,7 @@ async function __uvHook(window, config = {}) { path: url.pathname + url.search, }; - if (protocols.length) headers['Sec-WebSocket-Protocol'] = protocols.join(', '); + if (protocols.length) headers['Sec-WebSocket-Protocol'] = protocols.join(', '); event.data.url = `wss://${window.location.host}/bare/v1/`; event.data.protocols = [ @@ -590,8 +730,6 @@ async function __uvHook(window, config = {}) { }); client.object.on('getOwnPropertyDescriptors', event => { - console.log(event.data.descriptors); - for (const forbidden of __uv.filterKeys) { delete event.data.descriptors[forbidden]; }; @@ -607,7 +745,7 @@ async function __uvHook(window, config = {}) { client.element.overrideAttribute(); client.element.overrideInsertAdjacentHTML(); client.element.overrideAudio(); - // client.element.overrideQuerySelector(); + // client.element.overrideQuerySelector(); client.node.overrideBaseURI(); client.node.overrideTextContent(); client.attribute.override(); @@ -617,6 +755,8 @@ async function __uvHook(window, config = {}) { client.document.overrideWrite(); client.document.overrideReferrer(); client.document.overrideParseFromString(); + client.storage.overrideMethods(); + client.storage.overrideLength(); //client.document.overrideQuerySelector(); client.object.overrideGetPropertyNames(); client.object.overrideGetOwnPropertyDescriptors(); @@ -643,20 +783,34 @@ async function __uvHook(window, config = {}) { (href) => { return new URL(__uv.sourceUrl(href)); } - ) - - client.nativeMethods.defineProperty(__uv, '$wrap', { - get() { - return function(name) { - if (name === 'location') return __uv.methods.location; - if (name === 'eval') return __uv.methods.eval; - return name; - }; - }, - set: val => { - console.log('waht the fuck', val); + ); + + client.overrideDescriptor(window, 'localStorage', { + get: (target, that) => { + return (that || window).__uv.lsWrap; }, }); + client.overrideDescriptor(window, 'sessionStorage', { + get: (target, that) => { + return (that || window).__uv.ssWrap; + }, + }); + + + client.override(window, 'open', (target, that, args) => { + if (!args.length) return target.apply(that, args); + let [url] = args; + + url = __uv.rewriteUrl(url); + + return target.call(that, url); + }); + + __uv.$wrap = function(name) { + if (name === 'location') return __uv.methods.location; + if (name === 'eval') return __uv.methods.eval; + return name; + }; __uv.$get = function(that) { @@ -667,7 +821,7 @@ async function __uvHook(window, config = {}) { __uv.eval = client.wrap(window, 'eval', (target, that, args) => { if (!args.length || typeof args[0] !== 'string') return target.apply(that, args); - let [ script ] = args; + let [script] = args; script = __uv.rewriteJS(script); return target.call(that, script); @@ -687,12 +841,9 @@ async function __uvHook(window, config = {}) { }, enumerable: false }); - + client.nativeMethods.defineProperty(window.Object.prototype, __uv.methods.setSource, { value: function(source) { - - if (!client.nativeMethods.isExtensible(this)) console.log('you suck'); - if (!client.nativeMethods.isExtensible(this)) return this; client.nativeMethods.defineProperty(this, __uv.methods.source, { @@ -715,7 +866,6 @@ async function __uvHook(window, config = {}) { client.nativeMethods.defineProperty(window.Object.prototype, __uv.methods.location, { configurable: true, get() { - return (this === window.document || this === window) ? __uv.location : this.location; }, set(val) { @@ -727,6 +877,57 @@ async function __uvHook(window, config = {}) { }, }); + client.nativeMethods.defineProperty(window.Object.prototype, __uv.methods.parent, { + configurable: true, + get() { + const val = this.parent; + + if (this === window) { + try { + return '__uv' in val ? val : this; + } catch (e) { + return this; + }; + }; + return val; + }, + set(val) { + this.parent = val; + }, + }); + + client.nativeMethods.defineProperty(window.Object.prototype, __uv.methods.top, { + configurable: true, + get() { + const val = this.top; + + if (this === window) { + if (val === this.parent) return this[__uv.methods.parent]; + try { + if (!('__uv' in val)) { + let current = this; + + while (current.parent !== val) { + current = current.parent + }; + + return '__uv' in current ? current : this; + + } else { + return val; + }; + } catch (e) { + return this; + }; + }; + return val; + }, + set(val) { + this.top = val; + }, + }); + + client.nativeMethods.defineProperty(window.Object.prototype, __uv.methods.eval, { configurable: true, get() { @@ -736,8 +937,4 @@ async function __uvHook(window, config = {}) { this.eval = val; }, }); -}; - -if (!self.__uv) { - __uvHook(self, {}); }; \ No newline at end of file diff --git a/lib/uv.sw.js b/lib/uv.sw.js index 1440546..86b2929 100644 --- a/lib/uv.sw.js +++ b/lib/uv.sw.js @@ -40,7 +40,6 @@ const headers = { ], forward: [ 'accept-encoding', - 'accept', 'connection', 'content-length', 'content-type', @@ -64,7 +63,11 @@ const statusCode = { ], }; -const handler = UVServiceWorker('/bare/v1/', {}); +const handler = UVServiceWorker('/bare/v1/', { + prefix: '/sw/', + encodeUrl: Ultraviolet.codec.xor.encode, + decodeUrl: Ultraviolet.codec.xor.decode, +}); addEventListener('fetch', async event => { @@ -73,6 +76,11 @@ addEventListener('fetch', }, ); +// Immediate activation. +addEventListener('install', () => { + self.skipWaiting(); +}); + function UVServiceWorker(bare = '/bare/v1/', options) { try { @@ -103,6 +111,7 @@ function UVServiceWorker(bare = '/bare/v1/', options) { uv.meta.origin = location.origin; uv.meta.base = uv.meta.url = new URL(uv.sourceUrl(request.url)); + /* uv.html.on('element', (element, type) => { if (type !== 'rewrite') return false; if (element.tagName !== 'head') return false; @@ -144,6 +153,7 @@ function UVServiceWorker(bare = '/bare/v1/', options) { } ); }); + */ if (uv.meta.url.protocol === 'blob:') { requestCtx.blob = true; @@ -153,6 +163,8 @@ function UVServiceWorker(bare = '/bare/v1/', options) { requestCtx.headers = Object.fromEntries([...request.headers.entries()]); + requestCtx.host = uv.meta.url.host; + if (request.referrer && request.referrer.startsWith(location.origin)) { const referer = new URL(uv.sourceUrl(request.referrer)); @@ -165,6 +177,14 @@ function UVServiceWorker(bare = '/bare/v1/', options) { const cookies = await uv.cookie.getCookies(db) || []; const cookieStr = uv.cookie.serialize(cookies, uv.meta, false); + + const browser = Ultraviolet.Bowser.getParser(self.navigator.userAgent).getBrowserName(); + const forward = [...headers.forward]; + + if (browser === 'Firefox' && !(request.destination === 'iframe' || request.destination === 'document')) { + forward.shift(); + }; + if (cookieStr) requestCtx.headers.cookie = cookieStr; const bareHeaders = { @@ -173,7 +193,7 @@ function UVServiceWorker(bare = '/bare/v1/', options) { 'x-bare-path': uv.meta.url.pathname + uv.meta.url.search, 'x-bare-port': uv.meta.url.port, 'x-bare-headers': JSON.stringify(requestCtx.headers), - 'x-bare-forward-headers': JSON.stringify(requestCtx.forward), + 'x-bare-forward-headers': JSON.stringify(forward), }; const fetchOptions = { @@ -185,11 +205,13 @@ function UVServiceWorker(bare = '/bare/v1/', options) { }; if (requestCtx.body) fetchOptions.body = requestCtx.body; + const response = await fetch(requestCtx.url, fetchOptions); + if (response.status === 500) { return Promise.reject('Err'); }; - + const sendData = !requestCtx.blob ? getBarerResponse(response) : { status: response.status, statusText: response.statusText, @@ -252,7 +274,12 @@ function UVServiceWorker(bare = '/bare/v1/', options) { await response.text(), { document: true , - cookies, + injectHead: uv.createHtmlInject( + scripts.handler, + scripts.package, + uv.cookie.serialize(cookies, uv.meta, true), + request.referrer + ) } ); }; @@ -269,14 +296,12 @@ function UVServiceWorker(bare = '/bare/v1/', options) { statusText: responseCtx.statusText, }); } catch(e) { - console.log(e); return new Response(e.toString(), { status: 500, }); }; }; } catch(e) { - console.log(e); return (event) => { event.respondWith(new Response(e.toString(), { status: 500, diff --git a/package-lock.json b/package-lock.json index a6fefe1..6523ad3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "bowser": "^2.11.0", "css-tree": "^2.0.4", "esotope-hammerhead": "^0.6.1", "idb": "^7.0.0", @@ -333,6 +334,11 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/bowser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1908,6 +1914,11 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "bowser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", diff --git a/package.json b/package.json index f025c92..7a72d77 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "license": "ISC", "type": "module", "dependencies": { + "bowser": "^2.11.0", "css-tree": "^2.0.4", "esotope-hammerhead": "^0.6.1", "idb": "^7.0.0", diff --git a/rewrite/cookie.js b/rewrite/cookie.js index b34fe97..65fdcef 100644 --- a/rewrite/cookie.js +++ b/rewrite/cookie.js @@ -36,7 +36,23 @@ async function db(openDB) { function serialize(cookies = [], meta, js) { let str = ''; + const now = new Date(); for (const cookie of cookies) { + + let expired = false; + + if (cookie.set) { + if (cookie.maxAge) { + expired = cookie.set.getTime() + (cookie.maxAge * 1e3) < now; + } else if (cookie.expires) { + expired = cookie.expires > now; + }; + }; + + if (expired) { + + continue; + }; if (!validateCookie(cookie, meta, js)) continue; if (str.length) str += '; '; str += cookie.name; @@ -47,15 +63,34 @@ function serialize(cookies = [], meta, js) { }; async function getCookies(db) { - return await db.getAll('cookies'); + const now = new Date(); + return (await db.getAll('cookies')).filter(cookie => { + + let expired = false; + if (cookie.set) { + if (cookie.maxAge) { + expired = (cookie.set.getTime() + (cookie.maxAge * 1e3)) < now; + } else if (cookie.expires) { + expired = new Date(cookie.expires.toLocaleString()) < now; + }; + }; + + if (expired) { + db.delete('cookies', cookie.id); + return false; + }; + + return true; + }); }; function setCookies(data, db, meta) { if (!db) return false; + const cookies = setCookie(data, { decodeValues: false, }) - + for (const cookie of cookies) { if (!cookie.domain) cookie.domain = '.' + meta.url.hostname; if (!cookie.path) cookie.path = '/'; @@ -67,6 +102,7 @@ function setCookies(data, db, meta) { db.put('cookies', { ...cookie, id: `${cookie.domain}@${cookie.path}@${cookie.name}`, + set: new Date(Date.now()), }); }; return true; diff --git a/rewrite/css.js b/rewrite/css.js index e82cc7d..5d7dd47 100644 --- a/rewrite/css.js +++ b/rewrite/css.js @@ -28,7 +28,6 @@ class CSS extends EventEmitter { }); return this.generate(ast); } catch(e) { - console.log(e) return str; }; }; diff --git a/rewrite/index.js b/rewrite/index.js index 6f79b7e..444ddbf 100644 --- a/rewrite/index.js +++ b/rewrite/index.js @@ -5,13 +5,15 @@ import setCookie from 'set-cookie-parser'; import { xor, base64, plain } from './codecs.js'; import mimeTypes from './mime.js'; import { validateCookie, db, getCookies, setCookies, serialize } from './cookie.js'; -import { attributes, isUrl, isForbidden, isHtml, isSrcset, isStyle, text } from './rewrite.html.js'; +import { attributes, isUrl, isForbidden, isHtml, isSrcset, isStyle, text, injectHead, createInjection } from './rewrite.html.js'; import { importStyle, url } from './rewrite.css.js'; //import { call, destructureDeclaration, dynamicImport, getProperty, importDeclaration, setProperty, sourceMethods, wrapEval, wrapIdentifier } from './rewrite.script.js'; -import { dynamicImport, identifier, importDeclaration, property, unwrap, wrapEval } from './rewrite.script.test.js'; +import { dynamicImport, identifier, importDeclaration, property, unwrap, wrapEval } from './rewrite.script.js'; import { openDB } from 'idb'; import parsel from './parsel.js'; import UVClient from '../client/index.js'; +import Bowser from 'bowser'; + const valid_chars = "!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~"; const reserved_chars = "%"; @@ -29,6 +31,8 @@ class Ultraviolet { this.meta = options.meta || {}; this.meta.base ||= undefined; this.meta.origin ||= ''; + this.bundleScript = options.bundleScript || '/uv.bundle.js'; + this.handlerScript = options.handlerScript || '/uv.handler.js'; this.meta.url ||= this.meta.base || ''; this.codec = Ultraviolet.codec; this.html = new HTML(this); @@ -36,10 +40,12 @@ class Ultraviolet { this.js = new JS(this); this.parsel = parsel; this.openDB = this.constructor.openDB; + this.Bowser = this.constructor.Bowser; this.client = typeof self !== 'undefined' ? new UVClient((options.window || self)) : null; this.master = '__uv'; this.dataPrefix = '__uv$'; this.attributePrefix = '__uv'; + this.createHtmlInject = createInjection; this.attrs = { isUrl, isForbidden, @@ -133,31 +139,17 @@ class Ultraviolet { // HTML attributes(this); text(this); - + injectHead(this); // CSS url(this); importStyle(this); - // JS - /* - getProperty(this); - call(this) - setProperty(this); - sourceMethods(this); - importDeclaration(this); - dynamicImport(this); - wrapEval(this); - wrapIdentifier(this) - */ - importDeclaration(this); dynamicImport(this); property(this); wrapEval(this); identifier(this); unwrap(this); - - //destructureDeclaration(this) }; get rewriteHtml() { return this.html.rewrite.bind(this.html); @@ -181,6 +173,7 @@ class Ultraviolet { static mime = mimeTypes; static setCookie = setCookie; static openDB = openDB; + static Bowser = Bowser; }; export default Ultraviolet; diff --git a/rewrite/js.js b/rewrite/js.js index daa9261..d503a93 100644 --- a/rewrite/js.js +++ b/rewrite/js.js @@ -90,33 +90,4 @@ class JS extends EventEmitter { }; }; -class NodeEvent extends EventEmitter { - constructor(node, parent = null) { - super(); - this._node = node; - for (let key in node) { - Object.defineProperty(this, key, { - get: () => node[key], - sel: val => node[key] = val, - }); - }; - this.parent = parent; - }; - iterate(handler) { - for (const key in this._node) { - if (key === 'parent') continue; - if (Array.isArray(this._node[key])) { - this._node[key].forEach(entry => { - const child = new this.constructor(entry, this._node); - handler(child); - }); - } else { - const child = new this.constructor(entry, this._node); - walk(this._node[key], this._node, handler); - }; - }; - }; -}; - -export default JS; -export { NodeEvent }; \ No newline at end of file +export default JS; \ No newline at end of file diff --git a/rewrite/rewrite.html.js b/rewrite/rewrite.html.js index e116512..897ea54 100644 --- a/rewrite/rewrite.html.js +++ b/rewrite/rewrite.html.js @@ -1,5 +1,5 @@ function attributes(ctx, meta = ctx.meta) { - const { html, js, css, attributePrefix } = ctx; + const { html, js, css, attributePrefix, handlerScript, bundleScript } = ctx; const origPrefix = attributePrefix + '-attr-'; html.on('attr', (attr, type) => { @@ -20,7 +20,11 @@ function attributes(ctx, meta = ctx.meta) { if (type === 'rewrite' && isHtml(attr.name)) { attr.node.setAttribute(origPrefix + attr.name, attr.value); - attr.value = html.rewrite(attr.value, { ...meta, document: true }); + attr.value = html.rewrite(attr.value, { + ...meta, + document: true, + injectHead: attr.options.injectHead || [], + }); }; @@ -154,6 +158,53 @@ function isEvent(name) { ].indexOf(name) > -1; }; +function injectHead(ctx) { + const { html, js, css, attributePrefix } = ctx; + const origPrefix = attributePrefix + '-attr-'; + html.on('element', (element, type) => { + if (type !== 'rewrite') return false; + if (element.tagName !== 'head') return false; + if (!('injectHead' in element.options)) return false; + + element.childNodes.unshift( + ...element.options.injectHead + ); + }); +}; + +function createInjection(handler = '/uv.handler.js', bundle = '/uv.bundle.js', cookies = '', referrer = '') { + return [ + { + tagName: 'script', + nodeName: 'script', + childNodes: [ + { + nodeName: '#text', + value: `window.__uv$cookies = atob("${btoa(cookies)}");\nwindow.__uv$referrer = atob("${btoa(referrer)}");` + }, + ], + attrs: [], + skip: true, + }, + { + tagName: 'script', + nodeName: 'script', + childNodes: [], + attrs: [ + { name: 'src', value: bundle, skip: true } + ], + }, + { + tagName: 'script', + nodeName: 'script', + childNodes: [], + attrs: [ + { name: 'src', value: handler, skip: true } + ], + }, + ]; +}; + function isForbidden(name) { return ['http-equiv', 'integrity', 'sandbox', 'nonce', 'crossorigin'].indexOf(name) > -1; }; @@ -171,4 +222,4 @@ function isSrcset(name) { }; -export { attributes, text, isUrl, isEvent, isForbidden, isHtml, isStyle, isSrcset }; \ No newline at end of file +export { attributes, createInjection, text, isUrl, isEvent, isForbidden, isHtml, isStyle, isSrcset, injectHead }; \ No newline at end of file diff --git a/rewrite/rewrite.script.js b/rewrite/rewrite.script.js index 65b564d..4e360b1 100644 --- a/rewrite/rewrite.script.js +++ b/rewrite/rewrite.script.js @@ -1,384 +1,92 @@ import { Syntax } from 'esotope-hammerhead'; -const master = '__uv'; -const methodPrefix = '__uv$'; -const uvMethods = { - get: methodPrefix + 'get', - proxy: methodPrefix + 'proxy', - call: methodPrefix + 'call', - set: methodPrefix + 'set', - script: methodPrefix + 'script', - url: methodPrefix + 'url', - object: methodPrefix + 'obj' -}; -const uvMethodTypes = { - [methodPrefix + 'get']: 'get', - [methodPrefix + 'proxy']: 'proxy', - [methodPrefix + 'call']: 'call', - [methodPrefix + 'set']: 'set', - [methodPrefix + 'script']: 'script', - [methodPrefix + 'url']: 'url', - [methodPrefix + 'obj']: 'object' -}; -const shortHandAssignment = { - '+=': '+', - '-=': '-', - '*=': '*', - '/=': '/', - '%=': '%', - '**=': '**', - '<<=': '<<', - '>>=': '>>', - '>>>=': '>>>', - '&=': '&', - '^=': '^', - '|=': '|', -}; -const assignmentOperators = ['=', '+=', '-=', '*=', '/=', '%=', '**=', '<<=', '>>=', '>>>=', '&=', '^=', '|=']; - -function getProperty(ctx) { +function property(ctx) { const { js } = ctx; - js.on(Syntax.MemberExpression, (node, data, type) => { - if (type !== 'rewrite') return false; - if (node.object.type === Syntax.Super) - return false; - if (node.parent.type === Syntax.AssignmentExpression && node.parent.left === node) - return false; - if (node.parent.type === Syntax.CallExpression && node.parent.callee === node) - return false; - if (node.parent.type === Syntax.UnaryExpression && node.parent.operator === 'delete') - return false; - if (node.parent.type === Syntax.UpdateExpression && (node.parent.operator === '++' || parent.operator === '--')) - return false; - if (node.parent.type === Syntax.NewExpression && node.parent.callee === node) - return false; - if (node.parent.type === Syntax.ForInStatement && node.parent.left === node) return false; - if (node.computed && node.property.type === Syntax.Literal && !shouldWrapProperty(node.property.value)) - return false; - if (!node.computed && node.property.type === Syntax.Identifier && !shouldWrapProperty(node.property.name)) - return false; + js.on('MemberExpression', (node, data, type) => { + if (node.object.type === 'Super') return false; - data.changes.push({ - node: `${uvMethods.get}((`, - start: node.start, - end: node.object.start, - }) - - node.object.iterateEnd = function () { + if (type === 'rewrite' && computedProperty(node)) { data.changes.push({ - start: node.object.end, + node: '__uv.$wrap((', + start: node.property.start, end: node.property.start, - }); - - data.changes.push({ - node: '), (' - }); - - if (node.computed) { - node.property.iterateEnd = function () { - data.changes.push({ - start: node.property.end, - end: node.end, - node: `), ${master}, true)` - }); - - }; - } else { + }) + node.iterateEnd = function() { data.changes.push({ - end: node.end, - node: '"' + node.property.name + `"), ${master}, false)` - }) + node: '))', + start: node.property.end, + end: node.property.end, + }); }; - - }; - }) -}; - -function call(ctx) { - const { js } = ctx; - js.on(Syntax.CallExpression, (node, data, type) => { - if (type !== 'rewrite') return false; - if (node.callee.type !== Syntax.MemberExpression) - return false; - if (node.callee.object.type === Syntax.Super) - return false; - if (node.callee.computed && node.callee.property.type === Syntax.Literal && !shouldWrapProperty(node.callee.property.value)) - return false; - if (!node.callee.computed && node.callee.property.type === Syntax.Identifier && !shouldWrapProperty(node.callee.property.name)) - return false; - - const { callee } = node; - - data.changes.push({ - node: `${uvMethods.call}((`, - start: node.start, - end: callee.object.start, - }) - - callee.object.iterateEnd = function () { - data.changes.push({ - start: callee.object.end, - end: callee.property.start, - }); - - data.changes.push({ - node: '), (' - }); - - if (callee.computed) { - callee.property.iterateEnd = function() { - - data.changes.push({ - end: node.arguments.length ? node.arguments[0].start : callee.end, - start: callee.property.end, - node: '), [' - }) - node.iterateEnd = function() { - data.changes.push({ - end: node.end, - start: node.arguments.length ? node.arguments[node.arguments.length - 1].end : callee.end, - node: `], ${master}, true)` - }) - }; - }; - } else { - data.changes.push({ - end: node.arguments.length ? node.arguments[0].start : false, - node: '"' + callee.property.name + '"), [' - }) - node.iterateEnd = function() { - data.changes.push({ - end: node.end, - start: node.arguments.length ? node.arguments[node.arguments.length - 1].end : false, - node: `], ${master}, false)` - }) - }; - }; - - }; - }); -}; - -function setProperty(ctx) { - const { js } = ctx; - js.on(Syntax.AssignmentExpression, (node, data, type) => { - if (type !== 'rewrite') return false; - if (node.left.type !== Syntax.MemberExpression) return false; - if (!assignmentOperators.includes(node.operator)) return false; - if (node.left.object.type === Syntax.Super) - return false; - if (node.left.computed && node.left.property.type === Syntax.Literal && !shouldWrapProperty(node.left.property.value)) - return false; - if (!node.left.computed && node.left.property.type === Syntax.Identifier && !shouldWrapProperty(node.left.property.name)) - return false; - - const { left, right } = node; - - data.changes.push({ - node: `${uvMethods.set}((`, - start: left.object.start, - end: left.object.start, - }); - - left.object.iterateEnd = function () { - data.changes.push({ - start: left.object.end, - end: left.property.start, - }); - - data.changes.push({ - node: '), (' - }); - - if (left.computed) { - left.property.iterateEnd = function() { - data.changes.push({ - end: right.start, - node: '' + left.property.name + '), ' - }) - if (shortHandAssignment[node.operator]) { - data.changes.push({ - node: data.input.slice(left.start, left.end) + ` ${shortHandAssignment[node.operator]} ` - }) - }; - node.iterateEnd = function() { - data.changes.push({ - end: node.end, - start: right.end, - node: `, ${master}, true)` - }) - }; - }; - } else { - data.changes.push({ - end: right.start, - node: '"' + left.property.name + '"), ' - }) - if (shortHandAssignment[node.operator]) { - data.changes.push({ - node: data.input.slice(left.start, left.end) + ` ${shortHandAssignment[node.operator]} ` - }) - }; - node.iterateEnd = function() { - data.changes.push({ - end: node.end, - start: right.end, - node: `, ${master}, false)` - }) - }; - }; - - }; - }); -}; - -function wrapEval(ctx) { - const { js } = ctx; - js.on(Syntax.CallExpression, (node, data, type) => { - if (type !== 'rewrite') return false; - if (!node.arguments.length) return false; - if (node.callee.type !== Syntax.Identifier) return false; - if (node.callee.name !== 'eval') return false; - - const [ script ] = node.arguments; - data.changes.push({ - node: uvMethods.script + '(', - start: script.start, - end: script.start, - }) - node.iterateEnd = function() { + }; + + if (!node.computed && node.property.name === 'location' && type === 'rewrite' || node.property.name === '__uv$location' && type === 'source') { data.changes.push({ - node: ')', - start: script.end, - end: script.end, + start: node.property.start, + end: node.property.end, + node: type === 'rewrite' ? '__uv$setSource(__uv).__uv$location' : 'location' }); }; - }); -}; -function sourceMethods(ctx) { - const { js } = ctx; - js.on(Syntax.CallExpression, (node, data, type) => { - if (type !== 'source') return false; - if (node.callee.type !== Syntax.Identifier) return false; - if (!uvMethodTypes[node.callee.name]) return false; - const info = uvWrapperInfo(node, data); + if (!node.computed && node.property.name === 'top' && type === 'rewrite' || node.property.name === '__uv$top' && type === 'source') { + data.changes.push({ + start: node.property.start, + end: node.property.end, + node: type === 'rewrite' ? '__uv$setSource(__uv).__uv$top' : 'top' + }); + }; - switch(uvMethodTypes[node.callee.name]) { - case 'set': + if (!node.computed && node.property.name === 'parent' && type === 'rewrite' || node.property.name === '__uv$parent' && type === 'source') { + data.changes.push({ + start: node.property.start, + end: node.property.end, + node: type === 'rewrite' ? '__uv$setSource(__uv).__uv$parent' : 'parent' + }); + }; + + + if (!node.computed && node.property.name === 'postMessage' && type === 'rewrite') { + data.changes.push({ + start: node.property.start, + end: node.property.end, + node:'__uv$setSource(__uv).postMessage', + }); + }; + + + if (!node.computed && node.property.name === 'eval' && type === 'rewrite' || node.property.name === '__uv$eval' && type === 'source') { + data.changes.push({ + start: node.property.start, + end: node.property.end, + node: type === 'rewrite' ? '__uv$setSource(__uv).__uv$eval' : 'eval' + }); + }; + + if (!node.computed && node.property.name === '__uv$setSource' && type === 'source' && node.parent.type === Syntax.CallExpression) { + const { parent, property } = node; + data.changes.push({ + start: property.start - 1, + end: parent.end, + }); + + node.iterateEnd = function() { data.changes.push({ - node: info.computed ? `${info.object}[${info.property}] = ${info.value}` : `${info.object}.${info.property} = ${info.value}`, - start: node.start, - end: node.end, + start: property.start, + end: parent.end, }); - break; - case 'get': - data.changes.push({ - node: info.computed ? `${info.object}[${info.property}]` : `${info.object}.${info.property}`, - start: node.start, - end: node.end, - }); - break; - case 'call': - data.changes.push({ - node: info.computed ? `${info.object}[${info.property}](${info.args})` : `${info.object}.${info.property}${info.args}`, - start: node.start, - end: node.end, - }); - break; - case 'script': - data.changes.push({ - node: info.script, - start: node.start, - end: node.end - }); - break; - case 'url': - data.changes.push({ - node: info.url, - start: node.start, - end: node.end - }); - break; - case 'proxy': - data.changes.push({ - node: info.name, - start: node.start, - end: node.end, - }); - break; + }; }; }); }; -function uvWrapperInfo(node, { input }) { - const method = uvMethodTypes[node.callee.name]; - - switch(method) { - case 'set': - { - const [ object, property, value, source, computed ] = node.arguments; - return { - method, - object: input.slice(object.start - 1, object.end + 1), - property: property.type === Syntax.Literal && !computed.value ? property.value : input.slice(property.start, property.end), - computed: !!computed.value, - value: input.slice(value.start, value.end), - }; - }; - case 'get': - { - const [ object, property, source, computed ] = node.arguments; - return { - method, - object: input.slice(object.start - 1, object.end + 1), - property: property.type === Syntax.Literal && !computed.value ? property.value : input.slice(property.start, property.end), - computed: !!computed.value, - } - }; - case 'call': - { - const [ object, property, args, source, computed ] = node.arguments; - return { - method, - object: input.slice(object.start - 1, object.end + 1), - property: property.type === Syntax.Literal && !computed.value ? property.value : input.slice(property.start, property.end), - args: input.slice(args.start + 1, args.end - 1), - computed: !!computed.value, - }; - }; - case 'script': - { - const [ script ] = node.arguments; - return { - script: input.slice(script.start, script.end), - } - } - case 'url': - { - const [ url ] = node.arguments; - return { - url: input.slice(url.start, url.end), - } - } - case 'proxy': - { - const [ name ] = node.arguments; - return { name }; - }; - default: - return false; - }; -}; - -function wrapIdentifier(ctx) { +function identifier(ctx) { const { js } = ctx; - js.on(Syntax.Identifier, (node, data, type) => { + js.on('Identifier', (node, data, type) => { if (type !== 'rewrite') return false; const { parent } = node; - if (!shouldWrapIdentifier(node.name)) return false; + if (!['location', 'eval', 'parent', 'top'].includes(node.name)) return false; if (parent.type === Syntax.VariableDeclarator && parent.id === node) return false; if ((parent.type === Syntax.AssignmentExpression || parent.type === Syntax.AssignmentPattern) && parent.left === node) return false; if ((parent.type === Syntax.FunctionExpression || parent.type === Syntax.FunctionDeclaration) && parent.id === node) return false; @@ -393,14 +101,40 @@ function wrapIdentifier(ctx) { if (parent.type === Syntax.RestElement) return false; if (parent.type === Syntax.ExportSpecifier) return false; if (parent.type === Syntax.ImportSpecifier) return false; + data.changes.push({ start: node.start, end: node.end, - node: `${uvMethods.proxy}(${node.name}, __uv)` + node: '__uv.$get(' + node.name + ')' }); }); }; +function wrapEval(ctx) { + const { js } = ctx; + js.on('CallExpression', (node, data, type) => { + if (type !== 'rewrite') return false; + if (!node.arguments.length) return false; + if (node.callee.type !== 'Identifier') return false; + if (node.callee.name !== 'eval') return false; + + const [ script ] = node.arguments; + + data.changes.push({ + node: '__uv.js.rewrite(', + start: script.start, + end: script.start, + }) + node.iterateEnd = function() { + data.changes.push({ + node: ')', + start: script.end, + end: script.end, + }); + }; + }); +}; + function importDeclaration(ctx) { const { js } = ctx; js.on(Syntax.Literal, (node, data, type) => { @@ -420,7 +154,7 @@ function dynamicImport(ctx) { js.on(Syntax.ImportExpression, (node, data, type) => { if (type !== 'rewrite') return false; data.changes.push({ - node: uvMethods.url + '(', + node: '__uv.rewriteUrl(', start: node.source.start, end: node.source.start, }) @@ -434,41 +168,76 @@ function dynamicImport(ctx) { }); }; -function destructureDeclaration(ctx) { +function unwrap(ctx) { const { js } = ctx; - js.on(Syntax.VariableDeclarator, (node, data, type) => { - if (type !== 'rewrite') return false; - if (node.id.type !== Syntax.ObjectPattern) return false; - const names = []; + js.on('CallExpression', (node, data, type) => { + if (type !== 'source') return false; + if (!isWrapped(node.callee)) return false; - for (const { key } of node.id.properties) { - names.push(key.name); + switch(node.callee.property.name) { + case '$wrap': + if (!node.arguments || node.parent.type !== Syntax.MemberExpression || node.parent.property !== node) return false; + const [ property ] = node.arguments; + + data.changes.push({ + start: node.callee.start, + end: property.start, + }); + + node.iterateEnd = function() { + data.changes.push({ + start: node.end - 2, + end: node.end, + }); + }; + break; + case '$get': + case 'rewriteUrl': + const [ arg ] = node.arguments; + + data.changes.push({ + start: node.callee.start, + end: arg.start, + }); + + node.iterateEnd = function() { + data.changes.push({ + start: node.end - 1, + end: node.end, + }); + }; + break; + case 'rewrite': + const [ script ] = node.arguments; + data.changes.push({ + start: node.callee.start, + end: script.start, + }); + node.iterateEnd = function() { + data.changes.push({ + start: node.end - 1, + end: node.end, + }); + }; }; - console.log(names); - - data.changes.push({ - node: uvMethods.object + '(', - start: node.init.start, - end: node.init.start, - }) - - node.iterateEnd = function() { - data.changes.push({ - node: ')', - start: node.init.end, - end: node.init.end, - }); - }; }); }; -function shouldWrapProperty(name) { - return name === 'eval' || name === 'postMessage' || name === 'location' || name === 'parent' || name === 'top'; +function isWrapped(node) { + if (node.type !== Syntax.MemberExpression) return false; + if (node.property.name === 'rewrite' && isWrapped(node.object)) return true; + if (node.object.type !== Syntax.Identifier || node.object.name !== '__uv') return false; + if (!['js', '$get', '$wrap', 'rewriteUrl'].includes(node.property.name)) return false; + return true; }; -function shouldWrapIdentifier(name) { - return name === 'postMessage' || name === 'location' || name === 'parent' || name === 'top'; +function computedProperty(parent) { + if (!parent.computed) return false; + const { property: node } = parent; + if (node.type === 'Literal' && !['location', 'top', 'parent']) return false; + return true; }; -export { getProperty, destructureDeclaration, setProperty, call, sourceMethods, importDeclaration, dynamicImport, wrapIdentifier, wrapEval }; \ No newline at end of file + +export { property, wrapEval, dynamicImport, importDeclaration, identifier, unwrap }; \ No newline at end of file diff --git a/server/v1/request.js b/server/v1/request.js index 56bd5f4..c4689ba 100644 --- a/server/v1/request.js +++ b/server/v1/request.js @@ -11,12 +11,12 @@ function request(request, response) { remoteRequest.on('response', remoteResponse => { const send = prepareResponse(remoteResponse); + response.writeHead(...send); remoteResponse.pipe(response); }); remoteRequest.on('error', e => { - console.log(e); json(response, 500, { error: e.toString() }); @@ -24,7 +24,6 @@ function request(request, response) { request.pipe(remoteRequest); } catch(e) { - console.log(e); json(response, 500, { error: e.toString() }); diff --git a/server/v1/test/static/sw.js b/server/v1/test/static/sw.js index 81e3941..c037b82 100644 --- a/server/v1/test/static/sw.js +++ b/server/v1/test/static/sw.js @@ -13,8 +13,6 @@ addEventListener('fetch', async event => { sendHeaders.Referer = 'https://www.google.com' + request.referrer.slice(location.origin.length); }; - console.log(Object.fromEntries([...request.headers.entries()]), sendHeaders); - event.respondWith( fetch('/bare/v1/', { headers: { diff --git a/server/v1/util.js b/server/v1/util.js index 0279e7e..696fe1b 100644 --- a/server/v1/util.js +++ b/server/v1/util.js @@ -1,7 +1,7 @@ export function prepareResponse({ headers, statusCode, statusMessage }) { const sendHeaders = { 'x-bare-headers': JSON.stringify(headers), - 'x-bare-status': statusCode, + 'x-bare-status': statusCode.toString(), 'x-bare-status-text': statusMessage, }; diff --git a/worker/context.js b/worker/context.js new file mode 100644 index 0000000..e66a52c --- /dev/null +++ b/worker/context.js @@ -0,0 +1,14 @@ +class RequestContext { + constructor(ctx = {}) { + this.url = ctx.url || ''; + this.method = ctx.method || 'GET'; + this.body = ctx.body || null; + this.headers = ctx.headers || {}; + this.mode = ctx.mode || 'cors'; + this.redirect = ctx.redirect || 'manual'; + this.referrer = ctx.referrer || ''; + this.destination = ctx.destination || ''; + }; +}; + +export { RequestContext }; \ No newline at end of file diff --git a/worker/index.js b/worker/index.js new file mode 100644 index 0000000..31bec81 --- /dev/null +++ b/worker/index.js @@ -0,0 +1,10 @@ +import { RequestContext } from "./context"; + +class ServiceWorkerProxy extends EventTarget { + constructor() { + + }; + static createRequest(options = {}) { + return new RequestContext(options); + }; +}; \ No newline at end of file