mirror of
https://github.com/titaniumnetwork-dev/Ultraviolet.git
synced 2025-05-16 04:50:01 -04:00
t
This commit is contained in:
parent
82f5f76588
commit
2c06fed426
25 changed files with 1131 additions and 604 deletions
|
@ -3,7 +3,7 @@ import path from "path";
|
||||||
|
|
||||||
const __dirname = path.resolve(path.dirname(decodeURI(new URL(import.meta.url).pathname))).slice(3);
|
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({
|
webpack({
|
||||||
mode: 'none',
|
mode: 'none',
|
||||||
|
|
|
@ -15,6 +15,7 @@ import NavigatorApi from "./navigator.js";
|
||||||
import Workers from "./worker.js";
|
import Workers from "./worker.js";
|
||||||
import URLApi from "./url.js";
|
import URLApi from "./url.js";
|
||||||
import EventEmitter from "./events.js";
|
import EventEmitter from "./events.js";
|
||||||
|
import StorageApi from "./storage.js";
|
||||||
|
|
||||||
class UVClient extends EventEmitter {
|
class UVClient extends EventEmitter {
|
||||||
constructor(window = self, worker = !window.window) {
|
constructor(window = self, worker = !window.window) {
|
||||||
|
@ -25,9 +26,14 @@ class UVClient extends EventEmitter {
|
||||||
defineProperty: this.window.Object.defineProperty,
|
defineProperty: this.window.Object.defineProperty,
|
||||||
getOwnPropertyDescriptor: this.window.Object.getOwnPropertyDescriptor,
|
getOwnPropertyDescriptor: this.window.Object.getOwnPropertyDescriptor,
|
||||||
getOwnPropertyDescriptors: this.window.Object.getOwnPropertyDescriptors,
|
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,
|
isArray: this.window.Array.isArray,
|
||||||
setPrototypeOf: this.window.Object.setPrototypeOf,
|
setPrototypeOf: this.window.Object.setPrototypeOf,
|
||||||
isExtensible: this.window.Object.isExtensible,
|
isExtensible: this.window.Object.isExtensible,
|
||||||
|
Map: this.window.Map,
|
||||||
|
Proxy: this.window.Proxy,
|
||||||
};
|
};
|
||||||
this.worker = worker;
|
this.worker = worker;
|
||||||
this.fetch = new Fetch(this);
|
this.fetch = new Fetch(this);
|
||||||
|
@ -46,6 +52,7 @@ class UVClient extends EventEmitter {
|
||||||
this.url = new URLApi(this);
|
this.url = new URLApi(this);
|
||||||
this.workers = new Workers(this);
|
this.workers = new Workers(this);
|
||||||
this.location = new LocationApi(this);
|
this.location = new LocationApi(this);
|
||||||
|
this.storage = new StorageApi(this);
|
||||||
};
|
};
|
||||||
initLocation(rewriteUrl, sourceUrl) {
|
initLocation(rewriteUrl, sourceUrl) {
|
||||||
this.location = new LocationApi(this, sourceUrl, rewriteUrl, this.worker);
|
this.location = new LocationApi(this, sourceUrl, rewriteUrl, this.worker);
|
||||||
|
|
|
@ -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', {
|
this.ctx.nativeMethods.defineProperty(emulation, 'toString', {
|
||||||
value: this.ctx.wrap(this.location, 'toString', () => {
|
value: this.ctx.wrap(this.location, 'toString', () => {
|
||||||
|
|
155
client/storage.js
Normal file
155
client/storage.js
Normal file
|
@ -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);
|
||||||
|
};
|
||||||
|
};
|
|
@ -1,4 +1,4 @@
|
||||||
{
|
{
|
||||||
"prefix": "/service/",
|
"prefix": "/sw/",
|
||||||
"bare": "/bare/"
|
"bare": "/bare/"
|
||||||
}
|
}
|
|
@ -5,7 +5,7 @@
|
||||||
<script>
|
<script>
|
||||||
if ('serviceWorker' in navigator) {
|
if ('serviceWorker' in navigator) {
|
||||||
navigator.serviceWorker.register('/uv.sw.js', {
|
navigator.serviceWorker.register('/uv.sw.js', {
|
||||||
scope: '/service/'
|
scope: '/sw/'
|
||||||
});
|
});
|
||||||
navigator.serviceWorker.ready.then(() => {
|
navigator.serviceWorker.ready.then(() => {
|
||||||
location.reload()
|
location.reload()
|
||||||
|
|
21
example/static/iframe.html
Normal file
21
example/static/iframe.html
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
iframe {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<iframe src="https://localhost/sw/hvtrs8%2F-wuw%2Cgmoelg.aoo%2F"></iframe>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -14,4 +14,4 @@
|
||||||
addEventListener('message', e => console.log(e.source.postMessage !== window.postMessage));
|
addEventListener('message', e => console.log(e.source.postMessage !== window.postMessage));
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>__uv$get(frame, 'postMessage', __uv)
|
</html>
|
2
index.js
2
index.js
|
@ -18,7 +18,7 @@ console.log(
|
||||||
*/
|
*/
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
uv.rewriteJS('window.eval(saasdsd)')
|
uv.rewriteJS('top')
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
386
lib/uv.bundle.js
386
lib/uv.bundle.js
File diff suppressed because one or more lines are too long
|
@ -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 = {}) {
|
async function __uvHook(window, config = {}) {
|
||||||
if ('__uv' in window && window.__uv instanceof Ultraviolet) return false;
|
if ('__uv' in window && window.__uv instanceof Ultraviolet) return false;
|
||||||
|
|
||||||
|
|
||||||
const worker = !window.window;
|
const worker = !window.window;
|
||||||
const master = '__uv';
|
const master = '__uv';
|
||||||
const methodPrefix = '__uv$';
|
const methodPrefix = '__uv$';
|
||||||
|
@ -9,23 +17,23 @@ async function __uvHook(window, config = {}) {
|
||||||
...config,
|
...config,
|
||||||
window,
|
window,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { client } = __uv;
|
const { client } = __uv;
|
||||||
const {
|
const {
|
||||||
HTMLMediaElement,
|
HTMLMediaElement,
|
||||||
HTMLScriptElement,
|
HTMLScriptElement,
|
||||||
HTMLAudioElement,
|
HTMLAudioElement,
|
||||||
HTMLVideoElement,
|
HTMLVideoElement,
|
||||||
HTMLInputElement,
|
HTMLInputElement,
|
||||||
HTMLEmbedElement,
|
HTMLEmbedElement,
|
||||||
HTMLTrackElement,
|
HTMLTrackElement,
|
||||||
HTMLAnchorElement,
|
HTMLAnchorElement,
|
||||||
HTMLIFrameElement,
|
HTMLIFrameElement,
|
||||||
HTMLAreaElement,
|
HTMLAreaElement,
|
||||||
HTMLLinkElement,
|
HTMLLinkElement,
|
||||||
HTMLBaseElement,
|
HTMLBaseElement,
|
||||||
HTMLFormElement,
|
HTMLFormElement,
|
||||||
HTMLImageElement,
|
HTMLImageElement,
|
||||||
HTMLSourceElement,
|
HTMLSourceElement,
|
||||||
} = window;
|
} = window;
|
||||||
|
|
||||||
|
@ -34,9 +42,10 @@ async function __uvHook(window, config = {}) {
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
__uv.meta.origin = location.origin;
|
__uv.meta.origin = location.origin;
|
||||||
__uv.location = client.location.emulate(
|
__uv.location = client.location.emulate(
|
||||||
(href) => {
|
(href) => {
|
||||||
|
if (href === 'about:srcdoc') return new URL(href);
|
||||||
if (href.startsWith('blob:')) href = href.slice('blob:'.length);
|
if (href.startsWith('blob:')) href = href.slice('blob:'.length);
|
||||||
return new URL(__uv.sourceUrl(href));
|
return new URL(__uv.sourceUrl(href));
|
||||||
},
|
},
|
||||||
|
@ -51,8 +60,46 @@ async function __uvHook(window, config = {}) {
|
||||||
__uv.blobUrls = new window.Map();
|
__uv.blobUrls = new window.Map();
|
||||||
__uv.referrer = '';
|
__uv.referrer = '';
|
||||||
__uv.cookies = [];
|
__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);
|
let base = __uv.sourceUrl(rawBase);
|
||||||
|
|
||||||
client.nativeMethods.defineProperty(__uv.meta, 'base', {
|
client.nativeMethods.defineProperty(__uv.meta, 'base', {
|
||||||
|
@ -76,6 +123,8 @@ async function __uvHook(window, config = {}) {
|
||||||
function: methodPrefix + 'function',
|
function: methodPrefix + 'function',
|
||||||
string: methodPrefix + 'string',
|
string: methodPrefix + 'string',
|
||||||
eval: methodPrefix + 'eval',
|
eval: methodPrefix + 'eval',
|
||||||
|
parent: methodPrefix + 'parent',
|
||||||
|
top: methodPrefix + 'top',
|
||||||
};
|
};
|
||||||
|
|
||||||
__uv.filterKeys = [
|
__uv.filterKeys = [
|
||||||
|
@ -86,10 +135,13 @@ async function __uvHook(window, config = {}) {
|
||||||
__uv.methods.function,
|
__uv.methods.function,
|
||||||
__uv.methods.string,
|
__uv.methods.string,
|
||||||
__uv.methods.eval,
|
__uv.methods.eval,
|
||||||
|
__uv.methods.parent,
|
||||||
|
__uv.methods.top,
|
||||||
|
methodPrefix + 'storageObj',
|
||||||
'Ultraviolet',
|
'Ultraviolet',
|
||||||
'__uvHook',
|
'__uvHook',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
client.on('wrap', (target, wrapped) => {
|
client.on('wrap', (target, wrapped) => {
|
||||||
client.nativeMethods.defineProperty(wrapped, 'name', client.nativeMethods.getOwnPropertyDescriptor(target, 'name'));
|
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);
|
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);
|
event.data.value = __uv.sourceUrl(event.data.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Workers
|
// Workers
|
||||||
client.workers.on('worker', event => {
|
client.workers.on('worker', event => {
|
||||||
event.data.url = __uv.rewriteUrl(event.data.url);
|
event.data.url = __uv.rewriteUrl(event.data.url);
|
||||||
|
@ -140,7 +192,7 @@ async function __uvHook(window, config = {}) {
|
||||||
client.workers.on('importScripts', event => {
|
client.workers.on('importScripts', event => {
|
||||||
for (const i in event.data.scripts) {
|
for (const i in event.data.scripts) {
|
||||||
event.data.scripts[i] = __uv.rewriteUrl(event.data.scripts[i]);
|
event.data.scripts[i] = __uv.rewriteUrl(event.data.scripts[i]);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
client.workers.on('postMessage', event => {
|
client.workers.on('postMessage', event => {
|
||||||
|
@ -156,16 +208,16 @@ async function __uvHook(window, config = {}) {
|
||||||
|
|
||||||
// Navigator
|
// Navigator
|
||||||
client.navigator.on('sendBeacon', event => {
|
client.navigator.on('sendBeacon', event => {
|
||||||
event.data.url = __uv.rewriteUrl(event.data.url);
|
event.data.url = __uv.rewriteUrl(event.data.url);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Cookies
|
// Cookies
|
||||||
client.document.on('getCookie', event => {
|
client.document.on('getCookie', event => {
|
||||||
event.data.value = __uv.cookieStr;
|
event.data.value = __uv.cookieStr;
|
||||||
});
|
});
|
||||||
|
|
||||||
client.document.on('setCookie', event => {
|
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.db().then(db => {
|
||||||
__uv.cookie.getCookies(db).then(cookies => {
|
__uv.cookie.getCookies(db).then(cookies => {
|
||||||
__uv.cookieStr = __uv.cookie.serialize(cookies, __uv.meta, true);
|
__uv.cookieStr = __uv.cookie.serialize(cookies, __uv.meta, true);
|
||||||
|
@ -187,7 +239,7 @@ async function __uvHook(window, config = {}) {
|
||||||
|
|
||||||
// HTML
|
// HTML
|
||||||
client.element.on('setInnerHTML', event => {
|
client.element.on('setInnerHTML', event => {
|
||||||
switch(event.that.tagName) {
|
switch (event.that.tagName) {
|
||||||
case 'SCRIPT':
|
case 'SCRIPT':
|
||||||
event.data.value = __uv.js.rewrite(event.data.value);
|
event.data.value = __uv.js.rewrite(event.data.value);
|
||||||
break;
|
break;
|
||||||
|
@ -200,7 +252,7 @@ async function __uvHook(window, config = {}) {
|
||||||
});
|
});
|
||||||
|
|
||||||
client.element.on('getInnerHTML', event => {
|
client.element.on('getInnerHTML', event => {
|
||||||
switch(event.that.tagName) {
|
switch (event.that.tagName) {
|
||||||
case 'SCRIPT':
|
case 'SCRIPT':
|
||||||
event.data.value = __uv.js.source(event.data.value);
|
event.data.value = __uv.js.source(event.data.value);
|
||||||
break;
|
break;
|
||||||
|
@ -213,8 +265,8 @@ async function __uvHook(window, config = {}) {
|
||||||
event.data.value = __uv.rewriteHtml(event.data.value, { document: event.that.tagName === 'HTML' });
|
event.data.value = __uv.rewriteHtml(event.data.value, { document: event.that.tagName === 'HTML' });
|
||||||
});
|
});
|
||||||
|
|
||||||
client.element.on('getOuterHTML', event => {
|
client.element.on('getOuterHTML', event => {
|
||||||
switch(event.that.tagName) {
|
switch (event.that.tagName) {
|
||||||
case 'HEAD':
|
case 'HEAD':
|
||||||
event.data.value = __uv.sourceHtml(
|
event.data.value = __uv.sourceHtml(
|
||||||
event.data.value.replace(/<head(.*)>(.*)<\/head>/s, '<op-head$1>$2</op-head>')
|
event.data.value.replace(/<head(.*)>(.*)<\/head>/s, '<op-head$1>$2</op-head>')
|
||||||
|
@ -230,17 +282,17 @@ async function __uvHook(window, config = {}) {
|
||||||
break;
|
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 => {
|
client.document.on('write', event => {
|
||||||
if (!event.data.html.length) return false;
|
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 => {
|
client.document.on('writeln', event => {
|
||||||
if (!event.data.html.length) return false;
|
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 => {
|
client.element.on('insertAdjacentHTML', event => {
|
||||||
|
@ -260,10 +312,10 @@ async function __uvHook(window, config = {}) {
|
||||||
|
|
||||||
// History
|
// History
|
||||||
client.history.on('replaceState', event => {
|
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 => {
|
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
|
// Element get set attribute methods
|
||||||
|
@ -280,7 +332,7 @@ async function __uvHook(window, config = {}) {
|
||||||
let to = event.data.origin;
|
let to = event.data.origin;
|
||||||
let call = __uv.call;
|
let call = __uv.call;
|
||||||
|
|
||||||
|
|
||||||
if (event.that) {
|
if (event.that) {
|
||||||
call = event.that.__uv$source.call;
|
call = event.that.__uv$source.call;
|
||||||
};
|
};
|
||||||
|
@ -293,9 +345,9 @@ async function __uvHook(window, config = {}) {
|
||||||
};
|
};
|
||||||
|
|
||||||
event.respondWith(
|
event.respondWith(
|
||||||
worker ?
|
worker ?
|
||||||
call(event.target, [ event.data.message, event.data.transfer ], event.that) :
|
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)
|
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)) {
|
if (__uv.attrs.isHtml(event.data.name)) {
|
||||||
event.target.call(event.that, __uv.attributePrefix + '-attr-' + event.data.name, event.data.value);
|
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)) {
|
if (__uv.attrs.isForbidden(event.data.name)) {
|
||||||
event.data.name = __uv.attributePrefix + '-attr-' + event.data.name;
|
event.data.name = __uv.attributePrefix + '-attr-' + event.data.name;
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
client.element.on('audio', event => {
|
client.element.on('audio', event => {
|
||||||
event.data.url = __uv.rewriteUrl(event.data.url);
|
event.data.url = __uv.rewriteUrl(event.data.url);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Element Property Attributes
|
// Element Property Attributes
|
||||||
client.element.hookProperty([ HTMLAnchorElement, HTMLAreaElement, HTMLLinkElement, HTMLBaseElement ], 'href', {
|
client.element.hookProperty([HTMLAnchorElement, HTMLAreaElement, HTMLLinkElement, HTMLBaseElement], 'href', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
return __uv.sourceUrl(
|
return __uv.sourceUrl(
|
||||||
target.call(that)
|
target.call(that)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
set: (target, that, [ val ]) => {
|
set: (target, that, [val]) => {
|
||||||
client.element.setAttribute.call(that, __uv.attributePrefix + '-attr-href', val)
|
client.element.setAttribute.call(that, __uv.attributePrefix + '-attr-href', val)
|
||||||
target.call(that, __uv.rewriteUrl(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) => {
|
get: (target, that) => {
|
||||||
return __uv.sourceUrl(
|
return __uv.sourceUrl(
|
||||||
target.call(that)
|
target.call(that)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
set: (target, that, [ val ]) => {
|
set: (target, that, [val]) => {
|
||||||
if (new String(val).toString().trim().startsWith('blob:') && that instanceof HTMLMediaElement) {
|
if (new String(val).toString().trim().startsWith('blob:') && that instanceof HTMLMediaElement) {
|
||||||
client.element.setAttribute.call(that, __uv.attributePrefix + '-attr-src', val)
|
client.element.setAttribute.call(that, __uv.attributePrefix + '-attr-src', val)
|
||||||
return target.call(that, __uv.blobUrls.get(val) || 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) => {
|
get: (target, that) => {
|
||||||
return __uv.sourceUrl(
|
return __uv.sourceUrl(
|
||||||
target.call(that)
|
target.call(that)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
set: (target, that, [ val ]) => {
|
set: (target, that, [val]) => {
|
||||||
client.element.setAttribute.call(that, __uv.attributePrefix + '-attr-action', val)
|
client.element.setAttribute.call(that, __uv.attributePrefix + '-attr-action', val)
|
||||||
target.call(that, __uv.rewriteUrl(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', {
|
client.element.hookProperty(HTMLScriptElement, 'integrity', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
return client.element.getAttribute.call(that, __uv.attributePrefix + '-attr-integrity');
|
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.setAttribute.call(that, __uv.attributePrefix + '-attr-integrity', val);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
client.element.hookProperty(HTMLIFrameElement, 'sandbox', {
|
client.element.hookProperty(HTMLIFrameElement, 'sandbox', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
return client.element.getAttribute.call(that, __uv.attributePrefix + '-attr-sandbox') || target.call(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);
|
client.element.setAttribute.call(that, __uv.attributePrefix + '-attr-sandbox', val);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -419,9 +486,9 @@ async function __uvHook(window, config = {}) {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const win = target.call(that);
|
const win = target.call(that);
|
||||||
try {
|
try {
|
||||||
if (!win.__uv) __uvHook(win);
|
if (!win.__uv) __uvHook(win, config);
|
||||||
return win;
|
return win;
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
return win;
|
return win;
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -432,14 +499,26 @@ async function __uvHook(window, config = {}) {
|
||||||
const doc = target.call(that);
|
const doc = target.call(that);
|
||||||
try {
|
try {
|
||||||
const win = doc.defaultView
|
const win = doc.defaultView
|
||||||
if (!win.__uv) __uvHook(win);
|
if (!win.__uv) __uvHook(win, config);
|
||||||
return doc;
|
return doc;
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
return win;
|
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 => {
|
client.node.on('getTextContent', event => {
|
||||||
if (event.that.tagName === 'SCRIPT') {
|
if (event.that.tagName === 'SCRIPT') {
|
||||||
event.data.value = __uv.js.source(event.data.value);
|
event.data.value = __uv.js.source(event.data.value);
|
||||||
|
@ -453,7 +532,7 @@ async function __uvHook(window, config = {}) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Document
|
// Document
|
||||||
client.document.on('getDomain', event => {
|
client.document.on('getDomain', event => {
|
||||||
event.data.value = __uv.domain;
|
event.data.value = __uv.domain;
|
||||||
});
|
});
|
||||||
client.document.on('setDomain', event => {
|
client.document.on('setDomain', event => {
|
||||||
|
@ -475,7 +554,7 @@ async function __uvHook(window, config = {}) {
|
||||||
|
|
||||||
client.document.on('parseFromString', event => {
|
client.document.on('parseFromString', event => {
|
||||||
if (event.data.type !== 'text/html') return false;
|
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)
|
// Attribute (node.attributes)
|
||||||
|
@ -498,17 +577,14 @@ async function __uvHook(window, config = {}) {
|
||||||
|
|
||||||
if (__uv.attrs.isHtml(event.data.name)) {
|
if (__uv.attrs.isHtml(event.data.name)) {
|
||||||
client.element.setAttribute.call(event.that.ownerElement, __uv.attributePrefix + '-attr-' + event.data.name, event.data.value);
|
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) => {
|
if (__uv.attrs.isSrcset(event.data.name)) {
|
||||||
try {
|
client.element.setAttribute.call(event.that.ownerElement, __uv.attributePrefix + '-attr-' + event.data.name, event.data.value);
|
||||||
return target.apply(that, args);
|
event.data.value = __uv.html.wrapSrcset(event.data.value);
|
||||||
} catch (e) {
|
|
||||||
console.log(e, 'Error', args);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// URL
|
// 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 => {
|
client.websocket.on('websocket', event => {
|
||||||
const url = new URL(event.data.url);
|
const url = new URL(event.data.url);
|
||||||
|
|
||||||
|
@ -557,7 +697,7 @@ async function __uvHook(window, config = {}) {
|
||||||
path: url.pathname + url.search,
|
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.url = `wss://${window.location.host}/bare/v1/`;
|
||||||
event.data.protocols = [
|
event.data.protocols = [
|
||||||
|
@ -590,8 +730,6 @@ async function __uvHook(window, config = {}) {
|
||||||
});
|
});
|
||||||
|
|
||||||
client.object.on('getOwnPropertyDescriptors', event => {
|
client.object.on('getOwnPropertyDescriptors', event => {
|
||||||
console.log(event.data.descriptors);
|
|
||||||
|
|
||||||
for (const forbidden of __uv.filterKeys) {
|
for (const forbidden of __uv.filterKeys) {
|
||||||
delete event.data.descriptors[forbidden];
|
delete event.data.descriptors[forbidden];
|
||||||
};
|
};
|
||||||
|
@ -607,7 +745,7 @@ async function __uvHook(window, config = {}) {
|
||||||
client.element.overrideAttribute();
|
client.element.overrideAttribute();
|
||||||
client.element.overrideInsertAdjacentHTML();
|
client.element.overrideInsertAdjacentHTML();
|
||||||
client.element.overrideAudio();
|
client.element.overrideAudio();
|
||||||
// client.element.overrideQuerySelector();
|
// client.element.overrideQuerySelector();
|
||||||
client.node.overrideBaseURI();
|
client.node.overrideBaseURI();
|
||||||
client.node.overrideTextContent();
|
client.node.overrideTextContent();
|
||||||
client.attribute.override();
|
client.attribute.override();
|
||||||
|
@ -617,6 +755,8 @@ async function __uvHook(window, config = {}) {
|
||||||
client.document.overrideWrite();
|
client.document.overrideWrite();
|
||||||
client.document.overrideReferrer();
|
client.document.overrideReferrer();
|
||||||
client.document.overrideParseFromString();
|
client.document.overrideParseFromString();
|
||||||
|
client.storage.overrideMethods();
|
||||||
|
client.storage.overrideLength();
|
||||||
//client.document.overrideQuerySelector();
|
//client.document.overrideQuerySelector();
|
||||||
client.object.overrideGetPropertyNames();
|
client.object.overrideGetPropertyNames();
|
||||||
client.object.overrideGetOwnPropertyDescriptors();
|
client.object.overrideGetOwnPropertyDescriptors();
|
||||||
|
@ -643,20 +783,34 @@ async function __uvHook(window, config = {}) {
|
||||||
(href) => {
|
(href) => {
|
||||||
return new URL(__uv.sourceUrl(href));
|
return new URL(__uv.sourceUrl(href));
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
client.nativeMethods.defineProperty(__uv, '$wrap', {
|
client.overrideDescriptor(window, 'localStorage', {
|
||||||
get() {
|
get: (target, that) => {
|
||||||
return function(name) {
|
return (that || window).__uv.lsWrap;
|
||||||
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, '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) {
|
__uv.$get = function(that) {
|
||||||
|
@ -667,7 +821,7 @@ async function __uvHook(window, config = {}) {
|
||||||
|
|
||||||
__uv.eval = client.wrap(window, 'eval', (target, that, args) => {
|
__uv.eval = client.wrap(window, 'eval', (target, that, args) => {
|
||||||
if (!args.length || typeof args[0] !== 'string') return target.apply(that, args);
|
if (!args.length || typeof args[0] !== 'string') return target.apply(that, args);
|
||||||
let [ script ] = args;
|
let [script] = args;
|
||||||
|
|
||||||
script = __uv.rewriteJS(script);
|
script = __uv.rewriteJS(script);
|
||||||
return target.call(that, script);
|
return target.call(that, script);
|
||||||
|
@ -687,12 +841,9 @@ async function __uvHook(window, config = {}) {
|
||||||
},
|
},
|
||||||
enumerable: false
|
enumerable: false
|
||||||
});
|
});
|
||||||
|
|
||||||
client.nativeMethods.defineProperty(window.Object.prototype, __uv.methods.setSource, {
|
client.nativeMethods.defineProperty(window.Object.prototype, __uv.methods.setSource, {
|
||||||
value: function(source) {
|
value: function(source) {
|
||||||
|
|
||||||
if (!client.nativeMethods.isExtensible(this)) console.log('you suck');
|
|
||||||
|
|
||||||
if (!client.nativeMethods.isExtensible(this)) return this;
|
if (!client.nativeMethods.isExtensible(this)) return this;
|
||||||
|
|
||||||
client.nativeMethods.defineProperty(this, __uv.methods.source, {
|
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, {
|
client.nativeMethods.defineProperty(window.Object.prototype, __uv.methods.location, {
|
||||||
configurable: true,
|
configurable: true,
|
||||||
get() {
|
get() {
|
||||||
|
|
||||||
return (this === window.document || this === window) ? __uv.location : this.location;
|
return (this === window.document || this === window) ? __uv.location : this.location;
|
||||||
},
|
},
|
||||||
set(val) {
|
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, {
|
client.nativeMethods.defineProperty(window.Object.prototype, __uv.methods.eval, {
|
||||||
configurable: true,
|
configurable: true,
|
||||||
get() {
|
get() {
|
||||||
|
@ -736,8 +937,4 @@ async function __uvHook(window, config = {}) {
|
||||||
this.eval = val;
|
this.eval = val;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
|
||||||
if (!self.__uv) {
|
|
||||||
__uvHook(self, {});
|
|
||||||
};
|
};
|
39
lib/uv.sw.js
39
lib/uv.sw.js
|
@ -40,7 +40,6 @@ const headers = {
|
||||||
],
|
],
|
||||||
forward: [
|
forward: [
|
||||||
'accept-encoding',
|
'accept-encoding',
|
||||||
'accept',
|
|
||||||
'connection',
|
'connection',
|
||||||
'content-length',
|
'content-length',
|
||||||
'content-type',
|
'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',
|
addEventListener('fetch',
|
||||||
async event => {
|
async event => {
|
||||||
|
@ -73,6 +76,11 @@ addEventListener('fetch',
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Immediate activation.
|
||||||
|
addEventListener('install', () => {
|
||||||
|
self.skipWaiting();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
function UVServiceWorker(bare = '/bare/v1/', options) {
|
function UVServiceWorker(bare = '/bare/v1/', options) {
|
||||||
try {
|
try {
|
||||||
|
@ -103,6 +111,7 @@ function UVServiceWorker(bare = '/bare/v1/', options) {
|
||||||
uv.meta.origin = location.origin;
|
uv.meta.origin = location.origin;
|
||||||
uv.meta.base = uv.meta.url = new URL(uv.sourceUrl(request.url));
|
uv.meta.base = uv.meta.url = new URL(uv.sourceUrl(request.url));
|
||||||
|
|
||||||
|
/*
|
||||||
uv.html.on('element', (element, type) => {
|
uv.html.on('element', (element, type) => {
|
||||||
if (type !== 'rewrite') return false;
|
if (type !== 'rewrite') return false;
|
||||||
if (element.tagName !== 'head') return false;
|
if (element.tagName !== 'head') return false;
|
||||||
|
@ -144,6 +153,7 @@ function UVServiceWorker(bare = '/bare/v1/', options) {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
if (uv.meta.url.protocol === 'blob:') {
|
if (uv.meta.url.protocol === 'blob:') {
|
||||||
requestCtx.blob = true;
|
requestCtx.blob = true;
|
||||||
|
@ -153,6 +163,8 @@ function UVServiceWorker(bare = '/bare/v1/', options) {
|
||||||
|
|
||||||
requestCtx.headers = Object.fromEntries([...request.headers.entries()]);
|
requestCtx.headers = Object.fromEntries([...request.headers.entries()]);
|
||||||
|
|
||||||
|
requestCtx.host = uv.meta.url.host;
|
||||||
|
|
||||||
if (request.referrer && request.referrer.startsWith(location.origin)) {
|
if (request.referrer && request.referrer.startsWith(location.origin)) {
|
||||||
const referer = new URL(uv.sourceUrl(request.referrer));
|
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 cookies = await uv.cookie.getCookies(db) || [];
|
||||||
const cookieStr = uv.cookie.serialize(cookies, uv.meta, false);
|
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;
|
if (cookieStr) requestCtx.headers.cookie = cookieStr;
|
||||||
|
|
||||||
const bareHeaders = {
|
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-path': uv.meta.url.pathname + uv.meta.url.search,
|
||||||
'x-bare-port': uv.meta.url.port,
|
'x-bare-port': uv.meta.url.port,
|
||||||
'x-bare-headers': JSON.stringify(requestCtx.headers),
|
'x-bare-headers': JSON.stringify(requestCtx.headers),
|
||||||
'x-bare-forward-headers': JSON.stringify(requestCtx.forward),
|
'x-bare-forward-headers': JSON.stringify(forward),
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchOptions = {
|
const fetchOptions = {
|
||||||
|
@ -185,11 +205,13 @@ function UVServiceWorker(bare = '/bare/v1/', options) {
|
||||||
};
|
};
|
||||||
if (requestCtx.body) fetchOptions.body = requestCtx.body;
|
if (requestCtx.body) fetchOptions.body = requestCtx.body;
|
||||||
|
|
||||||
|
|
||||||
const response = await fetch(requestCtx.url, fetchOptions);
|
const response = await fetch(requestCtx.url, fetchOptions);
|
||||||
|
|
||||||
if (response.status === 500) {
|
if (response.status === 500) {
|
||||||
return Promise.reject('Err');
|
return Promise.reject('Err');
|
||||||
};
|
};
|
||||||
|
|
||||||
const sendData = !requestCtx.blob ? getBarerResponse(response) : {
|
const sendData = !requestCtx.blob ? getBarerResponse(response) : {
|
||||||
status: response.status,
|
status: response.status,
|
||||||
statusText: response.statusText,
|
statusText: response.statusText,
|
||||||
|
@ -252,7 +274,12 @@ function UVServiceWorker(bare = '/bare/v1/', options) {
|
||||||
await response.text(),
|
await response.text(),
|
||||||
{
|
{
|
||||||
document: true ,
|
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,
|
statusText: responseCtx.statusText,
|
||||||
});
|
});
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.log(e);
|
|
||||||
return new Response(e.toString(), {
|
return new Response(e.toString(), {
|
||||||
status: 500,
|
status: 500,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.log(e);
|
|
||||||
return (event) => {
|
return (event) => {
|
||||||
event.respondWith(new Response(e.toString(), {
|
event.respondWith(new Response(e.toString(), {
|
||||||
status: 500,
|
status: 500,
|
||||||
|
|
11
package-lock.json
generated
11
package-lock.json
generated
|
@ -9,6 +9,7 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"bowser": "^2.11.0",
|
||||||
"css-tree": "^2.0.4",
|
"css-tree": "^2.0.4",
|
||||||
"esotope-hammerhead": "^0.6.1",
|
"esotope-hammerhead": "^0.6.1",
|
||||||
"idb": "^7.0.0",
|
"idb": "^7.0.0",
|
||||||
|
@ -333,6 +334,11 @@
|
||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||||
"dev": true
|
"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": {
|
"node_modules/brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
|
@ -1908,6 +1914,11 @@
|
||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||||
"dev": true
|
"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": {
|
"brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"bowser": "^2.11.0",
|
||||||
"css-tree": "^2.0.4",
|
"css-tree": "^2.0.4",
|
||||||
"esotope-hammerhead": "^0.6.1",
|
"esotope-hammerhead": "^0.6.1",
|
||||||
"idb": "^7.0.0",
|
"idb": "^7.0.0",
|
||||||
|
|
|
@ -36,7 +36,23 @@ async function db(openDB) {
|
||||||
|
|
||||||
function serialize(cookies = [], meta, js) {
|
function serialize(cookies = [], meta, js) {
|
||||||
let str = '';
|
let str = '';
|
||||||
|
const now = new Date();
|
||||||
for (const cookie of cookies) {
|
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 (!validateCookie(cookie, meta, js)) continue;
|
||||||
if (str.length) str += '; ';
|
if (str.length) str += '; ';
|
||||||
str += cookie.name;
|
str += cookie.name;
|
||||||
|
@ -47,15 +63,34 @@ function serialize(cookies = [], meta, js) {
|
||||||
};
|
};
|
||||||
|
|
||||||
async function getCookies(db) {
|
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) {
|
function setCookies(data, db, meta) {
|
||||||
if (!db) return false;
|
if (!db) return false;
|
||||||
|
|
||||||
const cookies = setCookie(data, {
|
const cookies = setCookie(data, {
|
||||||
decodeValues: false,
|
decodeValues: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
for (const cookie of cookies) {
|
for (const cookie of cookies) {
|
||||||
if (!cookie.domain) cookie.domain = '.' + meta.url.hostname;
|
if (!cookie.domain) cookie.domain = '.' + meta.url.hostname;
|
||||||
if (!cookie.path) cookie.path = '/';
|
if (!cookie.path) cookie.path = '/';
|
||||||
|
@ -67,6 +102,7 @@ function setCookies(data, db, meta) {
|
||||||
db.put('cookies', {
|
db.put('cookies', {
|
||||||
...cookie,
|
...cookie,
|
||||||
id: `${cookie.domain}@${cookie.path}@${cookie.name}`,
|
id: `${cookie.domain}@${cookie.path}@${cookie.name}`,
|
||||||
|
set: new Date(Date.now()),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -28,7 +28,6 @@ class CSS extends EventEmitter {
|
||||||
});
|
});
|
||||||
return this.generate(ast);
|
return this.generate(ast);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.log(e)
|
|
||||||
return str;
|
return str;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,13 +5,15 @@ import setCookie from 'set-cookie-parser';
|
||||||
import { xor, base64, plain } from './codecs.js';
|
import { xor, base64, plain } from './codecs.js';
|
||||||
import mimeTypes from './mime.js';
|
import mimeTypes from './mime.js';
|
||||||
import { validateCookie, db, getCookies, setCookies, serialize } from './cookie.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 { importStyle, url } from './rewrite.css.js';
|
||||||
//import { call, destructureDeclaration, dynamicImport, getProperty, importDeclaration, setProperty, sourceMethods, wrapEval, wrapIdentifier } from './rewrite.script.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 { openDB } from 'idb';
|
||||||
import parsel from './parsel.js';
|
import parsel from './parsel.js';
|
||||||
import UVClient from '../client/index.js';
|
import UVClient from '../client/index.js';
|
||||||
|
import Bowser from 'bowser';
|
||||||
|
|
||||||
|
|
||||||
const valid_chars = "!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~";
|
const valid_chars = "!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~";
|
||||||
const reserved_chars = "%";
|
const reserved_chars = "%";
|
||||||
|
@ -29,6 +31,8 @@ class Ultraviolet {
|
||||||
this.meta = options.meta || {};
|
this.meta = options.meta || {};
|
||||||
this.meta.base ||= undefined;
|
this.meta.base ||= undefined;
|
||||||
this.meta.origin ||= '';
|
this.meta.origin ||= '';
|
||||||
|
this.bundleScript = options.bundleScript || '/uv.bundle.js';
|
||||||
|
this.handlerScript = options.handlerScript || '/uv.handler.js';
|
||||||
this.meta.url ||= this.meta.base || '';
|
this.meta.url ||= this.meta.base || '';
|
||||||
this.codec = Ultraviolet.codec;
|
this.codec = Ultraviolet.codec;
|
||||||
this.html = new HTML(this);
|
this.html = new HTML(this);
|
||||||
|
@ -36,10 +40,12 @@ class Ultraviolet {
|
||||||
this.js = new JS(this);
|
this.js = new JS(this);
|
||||||
this.parsel = parsel;
|
this.parsel = parsel;
|
||||||
this.openDB = this.constructor.openDB;
|
this.openDB = this.constructor.openDB;
|
||||||
|
this.Bowser = this.constructor.Bowser;
|
||||||
this.client = typeof self !== 'undefined' ? new UVClient((options.window || self)) : null;
|
this.client = typeof self !== 'undefined' ? new UVClient((options.window || self)) : null;
|
||||||
this.master = '__uv';
|
this.master = '__uv';
|
||||||
this.dataPrefix = '__uv$';
|
this.dataPrefix = '__uv$';
|
||||||
this.attributePrefix = '__uv';
|
this.attributePrefix = '__uv';
|
||||||
|
this.createHtmlInject = createInjection;
|
||||||
this.attrs = {
|
this.attrs = {
|
||||||
isUrl,
|
isUrl,
|
||||||
isForbidden,
|
isForbidden,
|
||||||
|
@ -133,31 +139,17 @@ class Ultraviolet {
|
||||||
// HTML
|
// HTML
|
||||||
attributes(this);
|
attributes(this);
|
||||||
text(this);
|
text(this);
|
||||||
|
injectHead(this);
|
||||||
// CSS
|
// CSS
|
||||||
url(this);
|
url(this);
|
||||||
importStyle(this);
|
importStyle(this);
|
||||||
|
|
||||||
// JS
|
// JS
|
||||||
/*
|
|
||||||
getProperty(this);
|
|
||||||
call(this)
|
|
||||||
setProperty(this);
|
|
||||||
sourceMethods(this);
|
|
||||||
importDeclaration(this);
|
|
||||||
dynamicImport(this);
|
|
||||||
wrapEval(this);
|
|
||||||
wrapIdentifier(this)
|
|
||||||
*/
|
|
||||||
|
|
||||||
importDeclaration(this);
|
importDeclaration(this);
|
||||||
dynamicImport(this);
|
dynamicImport(this);
|
||||||
property(this);
|
property(this);
|
||||||
wrapEval(this);
|
wrapEval(this);
|
||||||
identifier(this);
|
identifier(this);
|
||||||
unwrap(this);
|
unwrap(this);
|
||||||
|
|
||||||
//destructureDeclaration(this)
|
|
||||||
};
|
};
|
||||||
get rewriteHtml() {
|
get rewriteHtml() {
|
||||||
return this.html.rewrite.bind(this.html);
|
return this.html.rewrite.bind(this.html);
|
||||||
|
@ -181,6 +173,7 @@ class Ultraviolet {
|
||||||
static mime = mimeTypes;
|
static mime = mimeTypes;
|
||||||
static setCookie = setCookie;
|
static setCookie = setCookie;
|
||||||
static openDB = openDB;
|
static openDB = openDB;
|
||||||
|
static Bowser = Bowser;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Ultraviolet;
|
export default Ultraviolet;
|
||||||
|
|
|
@ -90,33 +90,4 @@ class JS extends EventEmitter {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
class NodeEvent extends EventEmitter {
|
export default JS;
|
||||||
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 };
|
|
|
@ -1,5 +1,5 @@
|
||||||
function attributes(ctx, meta = ctx.meta) {
|
function attributes(ctx, meta = ctx.meta) {
|
||||||
const { html, js, css, attributePrefix } = ctx;
|
const { html, js, css, attributePrefix, handlerScript, bundleScript } = ctx;
|
||||||
const origPrefix = attributePrefix + '-attr-';
|
const origPrefix = attributePrefix + '-attr-';
|
||||||
|
|
||||||
html.on('attr', (attr, type) => {
|
html.on('attr', (attr, type) => {
|
||||||
|
@ -20,7 +20,11 @@ function attributes(ctx, meta = ctx.meta) {
|
||||||
|
|
||||||
if (type === 'rewrite' && isHtml(attr.name)) {
|
if (type === 'rewrite' && isHtml(attr.name)) {
|
||||||
attr.node.setAttribute(origPrefix + attr.name, attr.value);
|
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;
|
].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) {
|
function isForbidden(name) {
|
||||||
return ['http-equiv', 'integrity', 'sandbox', 'nonce', 'crossorigin'].indexOf(name) > -1;
|
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 };
|
export { attributes, createInjection, text, isUrl, isEvent, isForbidden, isHtml, isStyle, isSrcset, injectHead };
|
|
@ -1,384 +1,92 @@
|
||||||
import { Syntax } from 'esotope-hammerhead';
|
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 property(ctx) {
|
||||||
function getProperty(ctx) {
|
|
||||||
const { js } = ctx;
|
const { js } = ctx;
|
||||||
js.on(Syntax.MemberExpression, (node, data, type) => {
|
js.on('MemberExpression', (node, data, type) => {
|
||||||
if (type !== 'rewrite') return false;
|
if (node.object.type === 'Super') 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;
|
|
||||||
|
|
||||||
data.changes.push({
|
if (type === 'rewrite' && computedProperty(node)) {
|
||||||
node: `${uvMethods.get}((`,
|
|
||||||
start: node.start,
|
|
||||||
end: node.object.start,
|
|
||||||
})
|
|
||||||
|
|
||||||
node.object.iterateEnd = function () {
|
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
start: node.object.end,
|
node: '__uv.$wrap((',
|
||||||
|
start: node.property.start,
|
||||||
end: node.property.start,
|
end: node.property.start,
|
||||||
});
|
})
|
||||||
|
node.iterateEnd = function() {
|
||||||
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 {
|
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
end: node.end,
|
node: '))',
|
||||||
node: '"' + node.property.name + `"), ${master}, false)`
|
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,
|
if (!node.computed && node.property.name === 'location' && type === 'rewrite' || node.property.name === '__uv$location' && type === 'source') {
|
||||||
end: script.start,
|
|
||||||
})
|
|
||||||
node.iterateEnd = function() {
|
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
node: ')',
|
start: node.property.start,
|
||||||
start: script.end,
|
end: node.property.end,
|
||||||
end: script.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]) {
|
if (!node.computed && node.property.name === 'parent' && type === 'rewrite' || node.property.name === '__uv$parent' && type === 'source') {
|
||||||
case 'set':
|
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({
|
data.changes.push({
|
||||||
node: info.computed ? `${info.object}[${info.property}] = ${info.value}` : `${info.object}.${info.property} = ${info.value}`,
|
start: property.start,
|
||||||
start: node.start,
|
end: parent.end,
|
||||||
end: node.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 }) {
|
function identifier(ctx) {
|
||||||
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) {
|
|
||||||
const { js } = ctx;
|
const { js } = ctx;
|
||||||
js.on(Syntax.Identifier, (node, data, type) => {
|
js.on('Identifier', (node, data, type) => {
|
||||||
if (type !== 'rewrite') return false;
|
if (type !== 'rewrite') return false;
|
||||||
const { parent } = node;
|
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.VariableDeclarator && parent.id === node) return false;
|
||||||
if ((parent.type === Syntax.AssignmentExpression || parent.type === Syntax.AssignmentPattern) && parent.left === 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;
|
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.RestElement) return false;
|
||||||
if (parent.type === Syntax.ExportSpecifier) return false;
|
if (parent.type === Syntax.ExportSpecifier) return false;
|
||||||
if (parent.type === Syntax.ImportSpecifier) return false;
|
if (parent.type === Syntax.ImportSpecifier) return false;
|
||||||
|
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
start: node.start,
|
start: node.start,
|
||||||
end: node.end,
|
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) {
|
function importDeclaration(ctx) {
|
||||||
const { js } = ctx;
|
const { js } = ctx;
|
||||||
js.on(Syntax.Literal, (node, data, type) => {
|
js.on(Syntax.Literal, (node, data, type) => {
|
||||||
|
@ -420,7 +154,7 @@ function dynamicImport(ctx) {
|
||||||
js.on(Syntax.ImportExpression, (node, data, type) => {
|
js.on(Syntax.ImportExpression, (node, data, type) => {
|
||||||
if (type !== 'rewrite') return false;
|
if (type !== 'rewrite') return false;
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
node: uvMethods.url + '(',
|
node: '__uv.rewriteUrl(',
|
||||||
start: node.source.start,
|
start: node.source.start,
|
||||||
end: node.source.start,
|
end: node.source.start,
|
||||||
})
|
})
|
||||||
|
@ -434,41 +168,76 @@ function dynamicImport(ctx) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function destructureDeclaration(ctx) {
|
function unwrap(ctx) {
|
||||||
const { js } = ctx;
|
const { js } = ctx;
|
||||||
js.on(Syntax.VariableDeclarator, (node, data, type) => {
|
js.on('CallExpression', (node, data, type) => {
|
||||||
if (type !== 'rewrite') return false;
|
if (type !== 'source') return false;
|
||||||
if (node.id.type !== Syntax.ObjectPattern) return false;
|
if (!isWrapped(node.callee)) return false;
|
||||||
const names = [];
|
|
||||||
|
|
||||||
for (const { key } of node.id.properties) {
|
switch(node.callee.property.name) {
|
||||||
names.push(key.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) {
|
function isWrapped(node) {
|
||||||
return name === 'eval' || name === 'postMessage' || name === 'location' || name === 'parent' || name === 'top';
|
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) {
|
function computedProperty(parent) {
|
||||||
return name === 'postMessage' || name === 'location' || name === 'parent' || name === 'top';
|
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 };
|
|
||||||
|
export { property, wrapEval, dynamicImport, importDeclaration, identifier, unwrap };
|
|
@ -11,12 +11,12 @@ function request(request, response) {
|
||||||
|
|
||||||
remoteRequest.on('response', remoteResponse => {
|
remoteRequest.on('response', remoteResponse => {
|
||||||
const send = prepareResponse(remoteResponse);
|
const send = prepareResponse(remoteResponse);
|
||||||
|
|
||||||
response.writeHead(...send);
|
response.writeHead(...send);
|
||||||
remoteResponse.pipe(response);
|
remoteResponse.pipe(response);
|
||||||
});
|
});
|
||||||
|
|
||||||
remoteRequest.on('error', e => {
|
remoteRequest.on('error', e => {
|
||||||
console.log(e);
|
|
||||||
json(response, 500, {
|
json(response, 500, {
|
||||||
error: e.toString()
|
error: e.toString()
|
||||||
});
|
});
|
||||||
|
@ -24,7 +24,6 @@ function request(request, response) {
|
||||||
|
|
||||||
request.pipe(remoteRequest);
|
request.pipe(remoteRequest);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.log(e);
|
|
||||||
json(response, 500, {
|
json(response, 500, {
|
||||||
error: e.toString()
|
error: e.toString()
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,8 +13,6 @@ addEventListener('fetch', async event => {
|
||||||
sendHeaders.Referer = 'https://www.google.com' + request.referrer.slice(location.origin.length);
|
sendHeaders.Referer = 'https://www.google.com' + request.referrer.slice(location.origin.length);
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(Object.fromEntries([...request.headers.entries()]), sendHeaders);
|
|
||||||
|
|
||||||
event.respondWith(
|
event.respondWith(
|
||||||
fetch('/bare/v1/', {
|
fetch('/bare/v1/', {
|
||||||
headers: {
|
headers: {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
export function prepareResponse({ headers, statusCode, statusMessage }) {
|
export function prepareResponse({ headers, statusCode, statusMessage }) {
|
||||||
const sendHeaders = {
|
const sendHeaders = {
|
||||||
'x-bare-headers': JSON.stringify(headers),
|
'x-bare-headers': JSON.stringify(headers),
|
||||||
'x-bare-status': statusCode,
|
'x-bare-status': statusCode.toString(),
|
||||||
'x-bare-status-text': statusMessage,
|
'x-bare-status-text': statusMessage,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
14
worker/context.js
Normal file
14
worker/context.js
Normal file
|
@ -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 };
|
10
worker/index.js
Normal file
10
worker/index.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import { RequestContext } from "./context";
|
||||||
|
|
||||||
|
class ServiceWorkerProxy extends EventTarget {
|
||||||
|
constructor() {
|
||||||
|
|
||||||
|
};
|
||||||
|
static createRequest(options = {}) {
|
||||||
|
return new RequestContext(options);
|
||||||
|
};
|
||||||
|
};
|
Loading…
Add table
Add a link
Reference in a new issue