Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
QuiteAFancyEmerald
GitHub Repository: QuiteAFancyEmerald/Holy-Unblocker
Path: blob/master/views/uv/uv.handler.js
5227 views
1
/* -----------------------------------------------
2
/* Authors: Titanium Network
3
/* GNU Affero General Public License v3.0: https://www.gnu.org/licenses/agpl-3.0.en.html
4
/* Modified by Yoct to remove __uv$config.
5
/* Ultraviolet Handler Script
6
/* ----------------------------------------------- */
7
8
/**
9
* @type {import('../uv').UltravioletCtor}
10
*/
11
const Ultraviolet = self.Ultraviolet;
12
13
/**
14
* @type {import('../uv').UVClientCtor}
15
*/
16
const UVClient = self.UVClient;
17
18
/**
19
* @type {import('../uv').UVConfig}
20
*/
21
const __uv$config = self['{{__uv$config}}'];
22
23
/**
24
* @type {string}
25
*/
26
const __uv$cookies = self.__uv$cookies;
27
28
if (typeof __uv$cookies !== 'string')
29
throw new TypeError('Unable to load global UV data');
30
31
if (!self.__uv) __uvHook(self);
32
33
self.__uvHook = __uvHook;
34
35
/**
36
*
37
* @param {typeof globalThis} window
38
* @returns
39
*/
40
function __uvHook(window) {
41
if ('__uv' in window && window.__uv instanceof Ultraviolet) return false;
42
43
if (window.document && !!window.window) {
44
window.document
45
.querySelectorAll('script[__uv-script]')
46
.forEach((node) => node.remove());
47
}
48
49
const worker = !window.window;
50
const master = '__uv';
51
const methodPrefix = '__uv$';
52
const __uv = new Ultraviolet(__uv$config);
53
54
/*if (typeof config.construct === 'function') {
55
config.construct(__uv, worker ? 'worker' : 'window');
56
}*/
57
let bareClient;
58
if (!worker) {
59
// websockets
60
bareClient = new Ultraviolet.BareClient();
61
} else {
62
bareClient = new Ultraviolet.BareClient(
63
new Promise((resolve) => {
64
addEventListener('message', ({ data }) => {
65
if (typeof data !== 'object') return;
66
if ('__uv$type' in data && data.__uv$type === 'baremuxinit') {
67
resolve(data.port);
68
}
69
});
70
})
71
);
72
}
73
74
const client = new UVClient(window, bareClient, worker);
75
const {
76
HTMLMediaElement,
77
HTMLScriptElement,
78
HTMLAudioElement,
79
HTMLVideoElement,
80
HTMLInputElement,
81
HTMLEmbedElement,
82
HTMLTrackElement,
83
HTMLAnchorElement,
84
HTMLIFrameElement,
85
HTMLAreaElement,
86
HTMLLinkElement,
87
HTMLBaseElement,
88
HTMLFormElement,
89
HTMLImageElement,
90
HTMLSourceElement,
91
} = window;
92
93
client.nativeMethods.defineProperty(window, '__uv', {
94
value: __uv,
95
enumerable: false,
96
});
97
98
__uv.meta.origin = location.origin;
99
__uv.location = client.location.emulate(
100
(href) => {
101
if (href === 'about:srcdoc') return new URL(href);
102
if (href.startsWith('blob:')) href = href.slice('blob:'.length);
103
return new URL(__uv.sourceUrl(href));
104
},
105
(href) => {
106
return __uv.rewriteUrl(href);
107
}
108
);
109
110
let cookieStr = __uv$cookies;
111
112
__uv.meta.url = __uv.location;
113
__uv.domain = __uv.meta.url.host;
114
__uv.blobUrls = new window.Map();
115
__uv.referrer = '';
116
__uv.cookies = [];
117
__uv.localStorageObj = {};
118
__uv.sessionStorageObj = {};
119
120
if (__uv.location.href === 'about:srcdoc') {
121
__uv.meta = window.parent.__uv.meta;
122
}
123
124
if (window.EventTarget) {
125
__uv.addEventListener = window.EventTarget.prototype.addEventListener;
126
__uv.removeListener = window.EventTarget.prototype.removeListener;
127
__uv.dispatchEvent = window.EventTarget.prototype.dispatchEvent;
128
}
129
130
// Storage wrappers
131
client.nativeMethods.defineProperty(
132
client.storage.storeProto,
133
'__uv$storageObj',
134
{
135
get() {
136
if (this === client.storage.sessionStorage)
137
return __uv.sessionStorageObj;
138
if (this === client.storage.localStorage) return __uv.localStorageObj;
139
},
140
enumerable: false,
141
}
142
);
143
144
if (window.localStorage) {
145
for (const key in window.localStorage) {
146
if (key.startsWith(methodPrefix + __uv.location.origin + '@')) {
147
__uv.localStorageObj[
148
key.slice((methodPrefix + __uv.location.origin + '@').length)
149
] = window.localStorage.getItem(key);
150
}
151
}
152
153
__uv.lsWrap = client.storage.emulate(
154
client.storage.localStorage,
155
__uv.localStorageObj
156
);
157
}
158
159
if (window.sessionStorage) {
160
for (const key in window.sessionStorage) {
161
if (key.startsWith(methodPrefix + __uv.location.origin + '@')) {
162
__uv.sessionStorageObj[
163
key.slice((methodPrefix + __uv.location.origin + '@').length)
164
] = window.sessionStorage.getItem(key);
165
}
166
}
167
168
__uv.ssWrap = client.storage.emulate(
169
client.storage.sessionStorage,
170
__uv.sessionStorageObj
171
);
172
}
173
174
let rawBase = window.document
175
? client.node.baseURI.get.call(window.document)
176
: window.location.href;
177
let base = __uv.sourceUrl(rawBase);
178
179
client.nativeMethods.defineProperty(__uv.meta, 'base', {
180
get() {
181
if (!window.document) return __uv.meta.url.href;
182
183
if (client.node.baseURI.get.call(window.document) !== rawBase) {
184
rawBase = client.node.baseURI.get.call(window.document);
185
base = __uv.sourceUrl(rawBase);
186
}
187
188
return base;
189
},
190
});
191
192
__uv.methods = {
193
setSource: methodPrefix + 'setSource',
194
source: methodPrefix + 'source',
195
location: methodPrefix + 'location',
196
function: methodPrefix + 'function',
197
string: methodPrefix + 'string',
198
eval: methodPrefix + 'eval',
199
parent: methodPrefix + 'parent',
200
top: methodPrefix + 'top',
201
};
202
203
__uv.filterKeys = [
204
master,
205
__uv.methods.setSource,
206
__uv.methods.source,
207
__uv.methods.location,
208
__uv.methods.function,
209
__uv.methods.string,
210
__uv.methods.eval,
211
__uv.methods.parent,
212
__uv.methods.top,
213
methodPrefix + 'protocol',
214
methodPrefix + 'storageObj',
215
methodPrefix + 'url',
216
methodPrefix + 'modifiedStyle',
217
methodPrefix + 'config',
218
methodPrefix + 'dispatched',
219
'Ultraviolet',
220
'__uvHook',
221
];
222
223
client.on('wrap', (target, wrapped) => {
224
client.nativeMethods.defineProperty(
225
wrapped,
226
'name',
227
client.nativeMethods.getOwnPropertyDescriptor(target, 'name')
228
);
229
client.nativeMethods.defineProperty(
230
wrapped,
231
'length',
232
client.nativeMethods.getOwnPropertyDescriptor(target, 'length')
233
);
234
235
client.nativeMethods.defineProperty(wrapped, __uv.methods.string, {
236
enumerable: false,
237
value: client.nativeMethods.fnToString.call(target),
238
});
239
240
client.nativeMethods.defineProperty(wrapped, __uv.methods.function, {
241
enumerable: false,
242
value: target,
243
});
244
});
245
246
client.fetch.on('request', (event) => {
247
event.data.input = __uv.rewriteUrl(event.data.input);
248
});
249
250
client.fetch.on('requestUrl', (event) => {
251
event.data.value = __uv.sourceUrl(event.data.value);
252
});
253
254
client.fetch.on('responseUrl', (event) => {
255
event.data.value = __uv.sourceUrl(event.data.value);
256
});
257
258
// XMLHttpRequest
259
client.xhr.on('open', (event) => {
260
event.data.input = __uv.rewriteUrl(event.data.input);
261
});
262
263
client.xhr.on('responseUrl', (event) => {
264
event.data.value = __uv.sourceUrl(event.data.value);
265
});
266
267
// Workers
268
client.workers.on('worker', (event) => {
269
event.data.url = __uv.rewriteUrl(event.data.url);
270
});
271
272
client.workers.on('addModule', (event) => {
273
event.data.url = __uv.rewriteUrl(event.data.url);
274
});
275
276
client.workers.on('importScripts', (event) => {
277
for (const i in event.data.scripts) {
278
event.data.scripts[i] = __uv.rewriteUrl(event.data.scripts[i]);
279
}
280
});
281
282
client.workers.on('postMessage', (event) => {
283
let to = event.data.origin;
284
285
event.data.origin = '*';
286
event.data.message = {
287
__data: event.data.message,
288
__origin: __uv.meta.url.origin,
289
__to: to,
290
};
291
});
292
293
// Navigator
294
client.navigator.on('sendBeacon', (event) => {
295
event.data.url = __uv.rewriteUrl(event.data.url);
296
});
297
298
// Cookies
299
client.document.on('getCookie', (event) => {
300
event.data.value = cookieStr;
301
});
302
303
client.document.on('setCookie', (event) => {
304
__uv.cookie.db().then((db) => {
305
__uv.cookie.setCookies(event.data.value, db, __uv.meta);
306
307
__uv.cookie.getCookies(db).then((cookies) => {
308
cookieStr = __uv.cookie.serialize(cookies, __uv.meta, true);
309
});
310
});
311
312
const cookie = __uv.cookie.setCookie(event.data.value)[0];
313
314
if (!cookie.path) cookie.path = '/';
315
if (!cookie.domain) cookie.domain = __uv.meta.url.hostname;
316
317
if (__uv.cookie.validateCookie(cookie, __uv.meta, true)) {
318
if (cookieStr.length) cookieStr += '; ';
319
cookieStr += `${cookie.name}=${cookie.value}`;
320
}
321
322
event.respondWith(event.data.value);
323
});
324
325
// HTML
326
client.element.on('setInnerHTML', (event) => {
327
switch (event.that.tagName) {
328
case 'SCRIPT':
329
event.data.value = __uv.js.rewrite(event.data.value);
330
break;
331
case 'STYLE':
332
event.data.value = __uv.rewriteCSS(event.data.value);
333
break;
334
default:
335
event.data.value = __uv.rewriteHtml(event.data.value);
336
}
337
});
338
339
client.element.on('getInnerHTML', (event) => {
340
switch (event.that.tagName) {
341
case 'SCRIPT':
342
event.data.value = __uv.js.source(event.data.value);
343
break;
344
default:
345
event.data.value = __uv.sourceHtml(event.data.value);
346
}
347
});
348
349
client.element.on('setOuterHTML', (event) => {
350
event.data.value = __uv.rewriteHtml(event.data.value, {
351
document: event.that.tagName === 'HTML',
352
});
353
});
354
355
client.element.on('getOuterHTML', (event) => {
356
switch (event.that.tagName) {
357
case 'HEAD':
358
event.data.value = __uv
359
.sourceHtml(
360
event.data.value.replace(
361
/<head(.*)>(.*)<\/head>/s,
362
'<op-head$1>$2</op-head>'
363
)
364
)
365
.replace(/<op-head(.*)>(.*)<\/op-head>/s, '<head$1>$2</head>');
366
break;
367
case 'BODY':
368
event.data.value = __uv
369
.sourceHtml(
370
event.data.value.replace(
371
/<body(.*)>(.*)<\/body>/s,
372
'<op-body$1>$2</op-body>'
373
)
374
)
375
.replace(/<op-body(.*)>(.*)<\/op-body>/s, '<body$1>$2</body>');
376
break;
377
default:
378
event.data.value = __uv.sourceHtml(event.data.value, {
379
document: event.that.tagName === 'HTML',
380
});
381
break;
382
}
383
384
//event.data.value = __uv.sourceHtml(event.data.value, { document: event.that.tagName === 'HTML' });
385
});
386
387
client.document.on('write', (event) => {
388
if (!event.data.html.length) return false;
389
event.data.html = [__uv.rewriteHtml(event.data.html.join(''))];
390
});
391
392
client.document.on('writeln', (event) => {
393
if (!event.data.html.length) return false;
394
event.data.html = [__uv.rewriteHtml(event.data.html.join(''))];
395
});
396
397
client.element.on('insertAdjacentHTML', (event) => {
398
event.data.html = __uv.rewriteHtml(event.data.html);
399
});
400
401
// EventSource
402
403
client.eventSource.on('construct', (event) => {
404
event.data.url = __uv.rewriteUrl(event.data.url);
405
});
406
407
client.eventSource.on('url', (event) => {
408
event.data.url = __uv.rewriteUrl(event.data.url);
409
});
410
411
// IDB
412
client.idb.on('idbFactoryOpen', (event) => {
413
// Don't modify the Ultraviolet cookie database
414
if (event.data.name === '__op') return;
415
event.data.name = `${__uv.meta.url.origin}@${event.data.name}`;
416
});
417
418
client.idb.on('idbFactoryName', (event) => {
419
event.data.value = event.data.value.slice(
420
__uv.meta.url.origin.length + 1 /*the @*/
421
);
422
});
423
424
// History
425
client.history.on('replaceState', (event) => {
426
if (event.data.url)
427
event.data.url = __uv.rewriteUrl(
428
event.data.url,
429
'__uv' in event.that ? event.that.__uv.meta : __uv.meta
430
);
431
});
432
client.history.on('pushState', (event) => {
433
if (event.data.url)
434
event.data.url = __uv.rewriteUrl(
435
event.data.url,
436
'__uv' in event.that ? event.that.__uv.meta : __uv.meta
437
);
438
});
439
440
// Element get set attribute methods
441
client.element.on('getAttribute', (event) => {
442
if (
443
client.element.hasAttribute.call(
444
event.that,
445
__uv.attributePrefix + '-attr-' + event.data.name
446
)
447
) {
448
event.respondWith(
449
event.target.call(
450
event.that,
451
__uv.attributePrefix + '-attr-' + event.data.name
452
)
453
);
454
}
455
});
456
457
// Message
458
client.message.on('postMessage', (event) => {
459
let to = event.data.origin;
460
let call = __uv.call;
461
462
if (event.that) {
463
call = event.that.__uv$source.call;
464
}
465
466
event.data.origin = '*';
467
event.data.message = {
468
__data: event.data.message,
469
__origin: (event.that || event.target).__uv$source.location.origin,
470
__to: to,
471
};
472
473
event.respondWith(
474
worker
475
? call(
476
event.target,
477
[event.data.message, event.data.transfer],
478
event.that
479
)
480
: call(
481
event.target,
482
[event.data.message, event.data.origin, event.data.transfer],
483
event.that
484
)
485
);
486
});
487
488
client.message.on('data', (event) => {
489
const { value: data } = event.data;
490
if (typeof data === 'object' && '__data' in data && '__origin' in data) {
491
event.respondWith(data.__data);
492
}
493
});
494
495
client.message.on('origin', (event) => {
496
const data = client.message.messageData.get.call(event.that);
497
if (typeof data === 'object' && data.__data && data.__origin) {
498
event.respondWith(data.__origin);
499
}
500
});
501
502
client.overrideDescriptor(window, 'origin', {
503
get: () => {
504
return __uv.location.origin;
505
},
506
});
507
508
client.node.on('baseURI', (event) => {
509
if (event.data.value.startsWith(window.location.origin))
510
event.data.value = __uv.sourceUrl(event.data.value);
511
});
512
513
client.element.on('setAttribute', (event) => {
514
if (
515
event.that instanceof HTMLMediaElement &&
516
event.data.name === 'src' &&
517
event.data.value.startsWith('blob:')
518
) {
519
event.target.call(
520
event.that,
521
__uv.attributePrefix + '-attr-' + event.data.name,
522
event.data.value
523
);
524
event.data.value = __uv.blobUrls.get(event.data.value);
525
return;
526
}
527
528
if (__uv.attrs.isUrl(event.data.name)) {
529
event.target.call(
530
event.that,
531
__uv.attributePrefix + '-attr-' + event.data.name,
532
event.data.value
533
);
534
event.data.value = __uv.rewriteUrl(event.data.value);
535
}
536
537
if (__uv.attrs.isStyle(event.data.name)) {
538
event.target.call(
539
event.that,
540
__uv.attributePrefix + '-attr-' + event.data.name,
541
event.data.value
542
);
543
event.data.value = __uv.rewriteCSS(event.data.value, {
544
context: 'declarationList',
545
});
546
}
547
548
if (__uv.attrs.isHtml(event.data.name)) {
549
event.target.call(
550
event.that,
551
__uv.attributePrefix + '-attr-' + event.data.name,
552
event.data.value
553
);
554
event.data.value = __uv.rewriteHtml(event.data.value, {
555
...__uv.meta,
556
document: true,
557
injectHead: __uv.createHtmlInject(
558
__uv.handlerScript,
559
__uv.bundleScript,
560
__uv.clientScript,
561
__uv.configScript,
562
cookieStr,
563
window.location.href
564
),
565
});
566
}
567
568
if (__uv.attrs.isSrcset(event.data.name)) {
569
event.target.call(
570
event.that,
571
__uv.attributePrefix + '-attr-' + event.data.name,
572
event.data.value
573
);
574
event.data.value = __uv.html.wrapSrcset(event.data.value.toString());
575
}
576
577
if (__uv.attrs.isForbidden(event.data.name)) {
578
event.data.name = __uv.attributePrefix + '-attr-' + event.data.name;
579
}
580
});
581
582
client.element.on('audio', (event) => {
583
event.data.url = __uv.rewriteUrl(event.data.url);
584
});
585
586
// Element Property Attributes
587
client.element.hookProperty(
588
[HTMLAnchorElement, HTMLAreaElement, HTMLLinkElement, HTMLBaseElement],
589
'href',
590
{
591
get: (target, that) => {
592
return __uv.sourceUrl(target.call(that));
593
},
594
set: (target, that, [val]) => {
595
client.element.setAttribute.call(
596
that,
597
__uv.attributePrefix + '-attr-href',
598
val
599
);
600
target.call(that, __uv.rewriteUrl(val));
601
},
602
}
603
);
604
605
client.element.hookProperty(
606
[
607
HTMLScriptElement,
608
HTMLAudioElement,
609
HTMLVideoElement,
610
HTMLMediaElement,
611
HTMLImageElement,
612
HTMLInputElement,
613
HTMLEmbedElement,
614
HTMLIFrameElement,
615
HTMLTrackElement,
616
HTMLSourceElement,
617
],
618
'src',
619
{
620
get: (target, that) => {
621
return __uv.sourceUrl(target.call(that));
622
},
623
set: (target, that, [val]) => {
624
if (
625
new String(val).toString().trim().startsWith('blob:') &&
626
that instanceof HTMLMediaElement
627
) {
628
client.element.setAttribute.call(
629
that,
630
__uv.attributePrefix + '-attr-src',
631
val
632
);
633
return target.call(that, __uv.blobUrls.get(val) || val);
634
}
635
636
client.element.setAttribute.call(
637
that,
638
__uv.attributePrefix + '-attr-src',
639
val
640
);
641
target.call(that, __uv.rewriteUrl(val));
642
},
643
}
644
);
645
646
client.element.hookProperty([HTMLFormElement], 'action', {
647
get: (target, that) => {
648
return __uv.sourceUrl(target.call(that));
649
},
650
set: (target, that, [val]) => {
651
client.element.setAttribute.call(
652
that,
653
__uv.attributePrefix + '-attr-action',
654
val
655
);
656
target.call(that, __uv.rewriteUrl(val));
657
},
658
});
659
660
client.element.hookProperty([HTMLImageElement], 'srcset', {
661
get: (target, that) => {
662
return (
663
client.element.getAttribute.call(
664
that,
665
__uv.attributePrefix + '-attr-srcset'
666
) || target.call(that)
667
);
668
},
669
set: (target, that, [val]) => {
670
client.element.setAttribute.call(
671
that,
672
__uv.attributePrefix + '-attr-srcset',
673
val
674
);
675
target.call(that, __uv.html.wrapSrcset(val.toString()));
676
},
677
});
678
679
client.element.hookProperty(HTMLScriptElement, 'integrity', {
680
get: (target, that) => {
681
return client.element.getAttribute.call(
682
that,
683
__uv.attributePrefix + '-attr-integrity'
684
);
685
},
686
set: (target, that, [val]) => {
687
client.element.setAttribute.call(
688
that,
689
__uv.attributePrefix + '-attr-integrity',
690
val
691
);
692
},
693
});
694
695
client.element.hookProperty(HTMLIFrameElement, 'sandbox', {
696
get: (target, that) => {
697
return (
698
client.element.getAttribute.call(
699
that,
700
__uv.attributePrefix + '-attr-sandbox'
701
) || target.call(that)
702
);
703
},
704
set: (target, that, [val]) => {
705
client.element.setAttribute.call(
706
that,
707
__uv.attributePrefix + '-attr-sandbox',
708
val
709
);
710
},
711
});
712
713
// HTMLIFrameElement may not be defined (workers)
714
const contentWindowGet =
715
HTMLIFrameElement &&
716
Object.getOwnPropertyDescriptor(
717
HTMLIFrameElement.prototype,
718
'contentWindow'
719
).get;
720
721
function uvInject(that) {
722
const win = contentWindowGet.call(that);
723
724
if (!win.__uv)
725
try {
726
__uvHook(win);
727
} catch (e) {
728
console.error('catastrophic failure');
729
console.error(e);
730
}
731
}
732
733
client.element.hookProperty(HTMLIFrameElement, 'contentWindow', {
734
get: (target, that) => {
735
uvInject(that);
736
return target.call(that);
737
},
738
});
739
740
client.element.hookProperty(HTMLIFrameElement, 'contentDocument', {
741
get: (target, that) => {
742
uvInject(that);
743
return target.call(that);
744
},
745
});
746
747
client.element.hookProperty(HTMLIFrameElement, 'srcdoc', {
748
get: (target, that) => {
749
return (
750
client.element.getAttribute.call(
751
that,
752
__uv.attributePrefix + '-attr-srcdoc'
753
) || target.call(that)
754
);
755
},
756
set: (target, that, [val]) => {
757
target.call(
758
that,
759
__uv.rewriteHtml(val, {
760
document: true,
761
injectHead: __uv.createHtmlInject(
762
__uv.handlerScript,
763
__uv.bundleScript,
764
__uv.clientScript,
765
__uv.configScript,
766
cookieStr,
767
window.location.href
768
),
769
})
770
);
771
},
772
});
773
774
client.node.on('getTextContent', (event) => {
775
if (event.that.tagName === 'SCRIPT') {
776
event.data.value = __uv.js.source(event.data.value);
777
}
778
});
779
780
client.node.on('setTextContent', (event) => {
781
if (event.that.tagName === 'SCRIPT') {
782
event.data.value = __uv.js.rewrite(event.data.value);
783
}
784
});
785
786
// Until proper rewriting is implemented for service workers.
787
// Not sure atm how to implement it with the already built in service worker
788
if ('serviceWorker' in window.navigator) {
789
delete window.Navigator.prototype.serviceWorker;
790
}
791
792
// Document
793
client.document.on('getDomain', (event) => {
794
event.data.value = __uv.domain;
795
});
796
client.document.on('setDomain', (event) => {
797
if (
798
!event.data.value
799
.toString()
800
.endsWith(__uv.meta.url.hostname.split('.').slice(-2).join('.'))
801
)
802
return event.respondWith('');
803
event.respondWith((__uv.domain = event.data.value));
804
});
805
806
client.document.on('url', (event) => {
807
event.data.value = __uv.location.href;
808
});
809
810
client.document.on('documentURI', (event) => {
811
event.data.value = __uv.location.href;
812
});
813
814
client.document.on('referrer', (event) => {
815
event.data.value = __uv.referrer || __uv.sourceUrl(event.data.value);
816
});
817
818
client.document.on('parseFromString', (event) => {
819
if (event.data.type !== 'text/html') return false;
820
event.data.string = __uv.rewriteHtml(event.data.string, {
821
...__uv.meta,
822
document: true,
823
});
824
});
825
826
// Attribute (node.attributes)
827
client.attribute.on('getValue', (event) => {
828
if (
829
client.element.hasAttribute.call(
830
event.that.ownerElement,
831
__uv.attributePrefix + '-attr-' + event.data.name
832
)
833
) {
834
event.data.value = client.element.getAttribute.call(
835
event.that.ownerElement,
836
__uv.attributePrefix + '-attr-' + event.data.name
837
);
838
}
839
});
840
841
client.attribute.on('setValue', (event) => {
842
if (__uv.attrs.isUrl(event.data.name)) {
843
client.element.setAttribute.call(
844
event.that.ownerElement,
845
__uv.attributePrefix + '-attr-' + event.data.name,
846
event.data.value
847
);
848
event.data.value = __uv.rewriteUrl(event.data.value);
849
}
850
851
if (__uv.attrs.isStyle(event.data.name)) {
852
client.element.setAttribute.call(
853
event.that.ownerElement,
854
__uv.attributePrefix + '-attr-' + event.data.name,
855
event.data.value
856
);
857
event.data.value = __uv.rewriteCSS(event.data.value, {
858
context: 'declarationList',
859
});
860
}
861
862
if (__uv.attrs.isHtml(event.data.name)) {
863
client.element.setAttribute.call(
864
event.that.ownerElement,
865
__uv.attributePrefix + '-attr-' + event.data.name,
866
event.data.value
867
);
868
event.data.value = __uv.rewriteHtml(event.data.value, {
869
...__uv.meta,
870
document: true,
871
injectHead: __uv.createHtmlInject(
872
__uv.handlerScript,
873
__uv.bundleScript,
874
__uv.clientScript,
875
__uv.configScript,
876
cookieStr,
877
window.location.href
878
),
879
});
880
}
881
882
if (__uv.attrs.isSrcset(event.data.name)) {
883
client.element.setAttribute.call(
884
event.that.ownerElement,
885
__uv.attributePrefix + '-attr-' + event.data.name,
886
event.data.value
887
);
888
event.data.value = __uv.html.wrapSrcset(event.data.value.toString());
889
}
890
});
891
892
// URL
893
client.url.on('createObjectURL', (event) => {
894
let url = event.target.call(event.that, event.data.object);
895
if (url.startsWith('blob:' + location.origin)) {
896
let newUrl =
897
'blob:' +
898
(__uv.meta.url.href !== 'about:blank'
899
? __uv.meta.url.origin
900
: window.parent.__uv.meta.url.origin) +
901
url.slice('blob:'.length + location.origin.length);
902
__uv.blobUrls.set(newUrl, url);
903
event.respondWith(newUrl);
904
} else {
905
event.respondWith(url);
906
}
907
});
908
909
client.url.on('revokeObjectURL', (event) => {
910
if (__uv.blobUrls.has(event.data.url)) {
911
const old = event.data.url;
912
event.data.url = __uv.blobUrls.get(event.data.url);
913
__uv.blobUrls.delete(old);
914
}
915
});
916
917
client.storage.on('get', (event) => {
918
event.data.name =
919
methodPrefix + __uv.meta.url.origin + '@' + event.data.name;
920
});
921
922
client.storage.on('set', (event) => {
923
if (event.that.__uv$storageObj) {
924
event.that.__uv$storageObj[event.data.name] = event.data.value;
925
}
926
event.data.name =
927
methodPrefix + __uv.meta.url.origin + '@' + event.data.name;
928
});
929
930
client.storage.on('delete', (event) => {
931
if (event.that.__uv$storageObj) {
932
delete event.that.__uv$storageObj[event.data.name];
933
}
934
event.data.name =
935
methodPrefix + __uv.meta.url.origin + '@' + event.data.name;
936
});
937
938
client.storage.on('getItem', (event) => {
939
event.data.name =
940
methodPrefix + __uv.meta.url.origin + '@' + event.data.name;
941
});
942
943
client.storage.on('setItem', (event) => {
944
if (event.that.__uv$storageObj) {
945
event.that.__uv$storageObj[event.data.name] = event.data.value;
946
}
947
event.data.name =
948
methodPrefix + __uv.meta.url.origin + '@' + event.data.name;
949
});
950
951
client.storage.on('removeItem', (event) => {
952
if (event.that.__uv$storageObj) {
953
delete event.that.__uv$storageObj[event.data.name];
954
}
955
event.data.name =
956
methodPrefix + __uv.meta.url.origin + '@' + event.data.name;
957
});
958
959
client.storage.on('clear', (event) => {
960
if (event.that.__uv$storageObj) {
961
for (const key of client.nativeMethods.keys.call(
962
null,
963
event.that.__uv$storageObj
964
)) {
965
delete event.that.__uv$storageObj[key];
966
client.storage.removeItem.call(
967
event.that,
968
methodPrefix + __uv.meta.url.origin + '@' + key
969
);
970
event.respondWith();
971
}
972
}
973
});
974
975
client.storage.on('length', (event) => {
976
if (event.that.__uv$storageObj) {
977
event.respondWith(
978
client.nativeMethods.keys.call(null, event.that.__uv$storageObj).length
979
);
980
}
981
});
982
983
client.storage.on('key', (event) => {
984
if (event.that.__uv$storageObj) {
985
event.respondWith(
986
client.nativeMethods.keys.call(null, event.that.__uv$storageObj)[
987
event.data.index
988
] || null
989
);
990
}
991
});
992
993
client.function.on('function', (event) => {
994
event.data.script = __uv.rewriteJS(event.data.script);
995
});
996
997
client.function.on('toString', (event) => {
998
if (__uv.methods.string in event.that)
999
event.respondWith(event.that[__uv.methods.string]);
1000
});
1001
1002
client.object.on('getOwnPropertyNames', (event) => {
1003
event.data.names = event.data.names.filter(
1004
(element) => !__uv.filterKeys.includes(element)
1005
);
1006
});
1007
1008
client.object.on('getOwnPropertyDescriptors', (event) => {
1009
for (const forbidden of __uv.filterKeys) {
1010
delete event.data.descriptors[forbidden];
1011
}
1012
});
1013
1014
client.style.on('setProperty', (event) => {
1015
if (client.style.dashedUrlProps.includes(event.data.property)) {
1016
event.data.value = __uv.rewriteCSS(event.data.value, {
1017
context: 'value',
1018
...__uv.meta,
1019
});
1020
}
1021
});
1022
1023
client.style.on('getPropertyValue', (event) => {
1024
if (client.style.dashedUrlProps.includes(event.data.property)) {
1025
event.respondWith(
1026
__uv.sourceCSS(event.target.call(event.that, event.data.property), {
1027
context: 'value',
1028
...__uv.meta,
1029
})
1030
);
1031
}
1032
});
1033
1034
if ('CSS2Properties' in window) {
1035
for (const key of client.style.urlProps) {
1036
client.overrideDescriptor(window.CSS2Properties.prototype, key, {
1037
get: (target, that) => {
1038
return __uv.sourceCSS(target.call(that), {
1039
context: 'value',
1040
...__uv.meta,
1041
});
1042
},
1043
set: (target, that, val) => {
1044
target.call(
1045
that,
1046
__uv.rewriteCSS(val, {
1047
context: 'value',
1048
...__uv.meta,
1049
})
1050
);
1051
},
1052
});
1053
}
1054
} else if ('HTMLElement' in window) {
1055
client.overrideDescriptor(window.HTMLElement.prototype, 'style', {
1056
get: (target, that) => {
1057
const value = target.call(that);
1058
if (!value[methodPrefix + 'modifiedStyle']) {
1059
for (const key of client.style.urlProps) {
1060
client.nativeMethods.defineProperty(value, key, {
1061
enumerable: true,
1062
configurable: true,
1063
get() {
1064
const value =
1065
client.style.getPropertyValue.call(this, key) || '';
1066
return __uv.sourceCSS(value, {
1067
context: 'value',
1068
...__uv.meta,
1069
});
1070
},
1071
set(val) {
1072
client.style.setProperty.call(
1073
this,
1074
client.style.propToDashed[key] || key,
1075
__uv.rewriteCSS(val, {
1076
context: 'value',
1077
...__uv.meta,
1078
})
1079
);
1080
},
1081
});
1082
client.nativeMethods.defineProperty(
1083
value,
1084
methodPrefix + 'modifiedStyle',
1085
{
1086
enumerable: false,
1087
value: true,
1088
}
1089
);
1090
}
1091
}
1092
return value;
1093
},
1094
});
1095
}
1096
1097
client.style.on('setCssText', (event) => {
1098
event.data.value = __uv.rewriteCSS(event.data.value, {
1099
context: 'declarationList',
1100
...__uv.meta,
1101
});
1102
});
1103
1104
client.style.on('getCssText', (event) => {
1105
event.data.value = __uv.sourceCSS(event.data.value, {
1106
context: 'declarationList',
1107
...__uv.meta,
1108
});
1109
});
1110
1111
// Proper hash emulation.
1112
__uv.addEventListener.call(window, 'hashchange', (event) => {
1113
if (event.__uv$dispatched) return false;
1114
event.stopImmediatePropagation();
1115
const hash = window.location.hash;
1116
client.history.replaceState.call(window.history, '', '', event.oldURL);
1117
__uv.location.hash = hash;
1118
});
1119
1120
client.location.on('hashchange', (oldUrl, newUrl, ctx) => {
1121
if (ctx.HashChangeEvent && client.history.replaceState) {
1122
client.history.replaceState.call(
1123
window.history,
1124
'',
1125
'',
1126
__uv.rewriteUrl(newUrl)
1127
);
1128
1129
const event = new ctx.HashChangeEvent('hashchange', {
1130
newURL: newUrl,
1131
oldURL: oldUrl,
1132
});
1133
1134
client.nativeMethods.defineProperty(event, methodPrefix + 'dispatched', {
1135
value: true,
1136
enumerable: false,
1137
});
1138
1139
__uv.dispatchEvent.call(window, event);
1140
}
1141
});
1142
1143
// Hooking functions & descriptors
1144
client.fetch.overrideRequest();
1145
client.fetch.overrideUrl();
1146
client.xhr.overrideOpen();
1147
client.xhr.overrideResponseUrl();
1148
client.element.overrideHtml();
1149
client.element.overrideAttribute();
1150
client.element.overrideInsertAdjacentHTML();
1151
client.element.overrideAudio();
1152
// client.element.overrideQuerySelector();
1153
client.node.overrideBaseURI();
1154
client.node.overrideTextContent();
1155
client.attribute.overrideNameValue();
1156
client.document.overrideDomain();
1157
client.document.overrideURL();
1158
client.document.overrideDocumentURI();
1159
client.document.overrideWrite();
1160
client.document.overrideReferrer();
1161
client.document.overrideParseFromString();
1162
client.storage.overrideMethods();
1163
client.storage.overrideLength();
1164
//client.document.overrideQuerySelector();
1165
client.object.overrideGetPropertyNames();
1166
client.object.overrideGetOwnPropertyDescriptors();
1167
client.idb.overrideName();
1168
client.idb.overrideOpen();
1169
client.history.overridePushState();
1170
client.history.overrideReplaceState();
1171
client.eventSource.overrideConstruct();
1172
client.eventSource.overrideUrl();
1173
client.websocket.overrideWebSocket(bareClient);
1174
client.url.overrideObjectURL();
1175
client.document.overrideCookie();
1176
client.message.overridePostMessage();
1177
client.message.overrideMessageOrigin();
1178
client.message.overrideMessageData();
1179
client.workers.overrideWorker();
1180
client.workers.overrideAddModule();
1181
client.workers.overrideImportScripts();
1182
client.workers.overridePostMessage();
1183
client.style.overrideSetGetProperty();
1184
client.style.overrideCssText();
1185
client.navigator.overrideSendBeacon();
1186
client.function.overrideFunction();
1187
client.function.overrideToString();
1188
client.location.overrideWorkerLocation((href) => {
1189
return new URL(__uv.sourceUrl(href));
1190
});
1191
1192
client.overrideDescriptor(window, 'localStorage', {
1193
get: (target, that) => {
1194
return (that || window).__uv.lsWrap;
1195
},
1196
});
1197
client.overrideDescriptor(window, 'sessionStorage', {
1198
get: (target, that) => {
1199
return (that || window).__uv.ssWrap;
1200
},
1201
});
1202
1203
client.override(window, 'open', (target, that, args) => {
1204
if (!args.length) return target.apply(that, args);
1205
let [url] = args;
1206
1207
url = __uv.rewriteUrl(url);
1208
1209
return target.call(that, url);
1210
});
1211
1212
__uv.$wrap = function (name) {
1213
if (name === 'location') return __uv.methods.location;
1214
if (name === 'eval') return __uv.methods.eval;
1215
return name;
1216
};
1217
1218
__uv.$get = function (that) {
1219
if (that === window.location) return __uv.location;
1220
if (that === window.eval) return __uv.eval;
1221
if (that === window.parent) {
1222
return window.__uv$parent;
1223
}
1224
if (that === window.top) {
1225
return window.__uv$top;
1226
}
1227
return that;
1228
};
1229
1230
__uv.eval = client.wrap(window, 'eval', (target, that, args) => {
1231
if (!args.length || typeof args[0] !== 'string')
1232
return target.apply(that, args);
1233
let [script] = args;
1234
1235
script = __uv.rewriteJS(script);
1236
return target.call(that, script);
1237
});
1238
1239
__uv.call = function (target, args, that) {
1240
return that ? target.apply(that, args) : target(...args);
1241
};
1242
1243
__uv.call$ = function (obj, prop, args = []) {
1244
return obj[prop].apply(obj, args);
1245
};
1246
1247
client.nativeMethods.defineProperty(window.Object.prototype, master, {
1248
get: () => {
1249
return __uv;
1250
},
1251
enumerable: false,
1252
});
1253
1254
client.nativeMethods.defineProperty(
1255
window.Object.prototype,
1256
__uv.methods.setSource,
1257
{
1258
value: function (source) {
1259
if (!client.nativeMethods.isExtensible(this)) return this;
1260
1261
client.nativeMethods.defineProperty(this, __uv.methods.source, {
1262
value: source,
1263
writable: true,
1264
enumerable: false,
1265
});
1266
1267
return this;
1268
},
1269
enumerable: false,
1270
}
1271
);
1272
1273
client.nativeMethods.defineProperty(
1274
window.Object.prototype,
1275
__uv.methods.source,
1276
{
1277
value: __uv,
1278
writable: true,
1279
enumerable: false,
1280
}
1281
);
1282
1283
client.nativeMethods.defineProperty(
1284
window.Object.prototype,
1285
__uv.methods.location,
1286
{
1287
configurable: true,
1288
get() {
1289
return this === window.document || this === window
1290
? __uv.location
1291
: this.location;
1292
},
1293
set(val) {
1294
if (this === window.document || this === window) {
1295
__uv.location.href = val;
1296
} else {
1297
this.location = val;
1298
}
1299
},
1300
}
1301
);
1302
1303
client.nativeMethods.defineProperty(
1304
window.Object.prototype,
1305
__uv.methods.parent,
1306
{
1307
configurable: true,
1308
get() {
1309
const val = this.parent;
1310
1311
if (this === window) {
1312
try {
1313
return '__uv' in val ? val : this;
1314
} catch (e) {
1315
return this;
1316
}
1317
}
1318
return val;
1319
},
1320
set(val) {
1321
this.parent = val;
1322
},
1323
}
1324
);
1325
1326
client.nativeMethods.defineProperty(
1327
window.Object.prototype,
1328
__uv.methods.top,
1329
{
1330
configurable: true,
1331
get() {
1332
const val = this.top;
1333
1334
if (this === window) {
1335
if (val === this.parent) return this[__uv.methods.parent];
1336
try {
1337
if (!('__uv' in val)) {
1338
let current = this;
1339
1340
while (current.parent !== val) {
1341
current = current.parent;
1342
}
1343
1344
return '__uv' in current ? current : this;
1345
} else {
1346
return val;
1347
}
1348
} catch (e) {
1349
return this;
1350
}
1351
}
1352
return val;
1353
},
1354
set(val) {
1355
this.top = val;
1356
},
1357
}
1358
);
1359
1360
client.nativeMethods.defineProperty(
1361
window.Object.prototype,
1362
__uv.methods.eval,
1363
{
1364
configurable: true,
1365
get() {
1366
return this === window ? __uv.eval : this.eval;
1367
},
1368
set(val) {
1369
this.eval = val;
1370
},
1371
}
1372
);
1373
}
1374
1375