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