Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
OutRed
GitHub Repository: OutRed/artclass
Path: blob/main/static/uvold/uv.sw.js
595 views
1
importScripts('/uv/uv.bundle.js');
2
importScripts('/uv/uv.config.js');
3
4
class UVServiceWorker extends EventEmitter {
5
constructor(config = __uv$config) {
6
super();
7
if (!config.bare) config.bare = '/bare/';
8
this.addresses = typeof config.bare === 'string' ? [ new URL(config.bare, location) ] : config.bare.map(str => new URL(str, location));
9
this.headers = {
10
csp: [
11
'cross-origin-embedder-policy',
12
'cross-origin-opener-policy',
13
'cross-origin-resource-policy',
14
'content-security-policy',
15
'content-security-policy-report-only',
16
'expect-ct',
17
'feature-policy',
18
'origin-isolation',
19
'strict-transport-security',
20
'upgrade-insecure-requests',
21
'x-content-type-options',
22
'x-download-options',
23
'x-frame-options',
24
'x-permitted-cross-domain-policies',
25
'x-powered-by',
26
'x-xss-protection',
27
],
28
forward: [
29
'accept-encoding',
30
'connection',
31
'content-length',
32
],
33
};
34
this.method = {
35
empty: [
36
'GET',
37
'HEAD'
38
]
39
};
40
this.statusCode = {
41
empty: [
42
204,
43
304,
44
],
45
};
46
this.config = config;
47
this.browser = Ultraviolet.Bowser.getParser(self.navigator.userAgent).getBrowserName();
48
49
if (this.browser === 'Firefox') {
50
this.headers.forward.push('user-agent');
51
this.headers.forward.push('content-type');
52
};
53
};
54
async fetch({ request }) {
55
if (!request.url.startsWith(location.origin + (this.config.prefix || '/service/'))) {
56
return fetch(request);
57
};
58
try {
59
60
const ultraviolet = new Ultraviolet(this.config);
61
62
if (typeof this.config.construct === 'function') {
63
this.config.construct(ultraviolet, 'service');
64
};
65
66
const db = await ultraviolet.cookie.db();
67
68
ultraviolet.meta.origin = location.origin;
69
ultraviolet.meta.base = ultraviolet.meta.url = new URL(ultraviolet.sourceUrl(request.url));
70
71
const requestCtx = new RequestContext(
72
request,
73
this,
74
ultraviolet,
75
!this.method.empty.includes(request.method.toUpperCase()) ? await request.blob() : null
76
);
77
78
if (ultraviolet.meta.url.protocol === 'blob:') {
79
requestCtx.blob = true;
80
requestCtx.base = requestCtx.url = new URL(requestCtx.url.pathname);
81
};
82
83
if (request.referrer && request.referrer.startsWith(location.origin)) {
84
const referer = new URL(ultraviolet.sourceUrl(request.referrer));
85
86
if (requestCtx.headers.origin || ultraviolet.meta.url.origin !== referer.origin && request.mode === 'cors') {
87
requestCtx.headers.origin = referer.origin;
88
};
89
90
requestCtx.headers.referer = referer.href;
91
};
92
93
const cookies = await ultraviolet.cookie.getCookies(db) || [];
94
const cookieStr = ultraviolet.cookie.serialize(cookies, ultraviolet.meta, false);
95
96
if (this.browser === 'Firefox' && !(request.destination === 'iframe' || request.destination === 'document')) {
97
requestCtx.forward.shift();
98
};
99
100
if (cookieStr) requestCtx.headers.cookie = cookieStr;
101
requestCtx.headers.Host = requestCtx.url.host;
102
103
104
const reqEvent = new HookEvent(requestCtx, null, null);
105
this.emit('request', reqEvent);
106
107
if (reqEvent.intercepted) return reqEvent.returnValue;
108
109
const response = await fetch(requestCtx.send);
110
111
if (response.status === 500) {
112
return Promise.reject('');
113
};
114
115
const responseCtx = new ResponseContext(requestCtx, response, this);
116
const resEvent = new HookEvent(responseCtx, null, null);
117
118
this.emit('beforemod', resEvent);
119
if (resEvent.intercepted) return resEvent.returnValue;
120
121
for (const name of this.headers.csp) {
122
if (responseCtx.headers[name]) delete responseCtx.headers[name];
123
};
124
125
if (responseCtx.headers.location) {
126
responseCtx.headers.location = ultraviolet.rewriteUrl(responseCtx.headers.location);
127
};
128
129
if (responseCtx.headers['set-cookie']) {
130
Promise.resolve(ultraviolet.cookie.setCookies(responseCtx.headers['set-cookie'], db, ultraviolet.meta)).then(() => {
131
self.clients.matchAll().then(function (clients){
132
clients.forEach(function(client){
133
client.postMessage({
134
msg: 'updateCookies',
135
url: ultraviolet.meta.url.href,
136
});
137
});
138
});
139
});
140
delete responseCtx.headers['set-cookie'];
141
};
142
143
if (responseCtx.body) {
144
switch(request.destination) {
145
case 'script':
146
case 'worker':
147
responseCtx.body = `if (!self.__uv && self.importScripts) importScripts('${__uv$config.bundle}', '${__uv$config.config}', '${__uv$config.handler}');\n`;
148
responseCtx.body += ultraviolet.js.rewrite(
149
await response.text()
150
);
151
break;
152
case 'style':
153
responseCtx.body = ultraviolet.rewriteCSS(
154
await response.text()
155
);
156
break;
157
case 'iframe':
158
case 'document':
159
if (isHtml(ultraviolet.meta.url, (responseCtx.headers['content-type'] || ''))) {
160
responseCtx.body = ultraviolet.rewriteHtml(
161
await response.text(),
162
{
163
document: true ,
164
injectHead: ultraviolet.createHtmlInject(
165
this.config.handler,
166
this.config.bundle,
167
this.config.config,
168
ultraviolet.cookie.serialize(cookies, ultraviolet.meta, true),
169
request.referrer
170
)
171
}
172
);
173
};
174
};
175
};
176
177
if (requestCtx.headers.accept === 'text/event-stream') {
178
responseCtx.headers['content-type'] = 'text/event-stream';
179
};
180
181
this.emit('response', resEvent);
182
if (resEvent.intercepted) return resEvent.returnValue;
183
184
return new Response(responseCtx.body, {
185
headers: responseCtx.headers,
186
status: responseCtx.status,
187
statusText: responseCtx.statusText,
188
});
189
190
} catch(err) {
191
return new Response(err.toString(), {
192
status: 500,
193
});
194
};
195
};
196
getBarerResponse(response) {
197
const headers = {};
198
const raw = JSON.parse(response.headers.get('x-bare-headers'));
199
200
for (const key in raw) {
201
headers[key.toLowerCase()] = raw[key];
202
};
203
204
return {
205
headers,
206
status: +response.headers.get('x-bare-status'),
207
statusText: response.headers.get('x-bare-status-text'),
208
body: !this.statusCode.empty.includes(+response.headers.get('x-bare-status')) ? response.body : null,
209
};
210
};
211
get address() {
212
return this.addresses[Math.floor(Math.random() * this.addresses.length)];
213
};
214
static Ultraviolet = Ultraviolet;
215
};
216
217
self.UVServiceWorker = UVServiceWorker;
218
219
220
class ResponseContext {
221
constructor(request, response, worker) {
222
const { headers, status, statusText, body } = !request.blob ? worker.getBarerResponse(response) : {
223
status: response.status,
224
statusText: response.statusText,
225
headers: Object.fromEntries([...response.headers.entries()]),
226
body: response.body,
227
};
228
this.request = request;
229
this.raw = response;
230
this.ultraviolet = request.ultraviolet;
231
this.headers = headers;
232
this.status = status;
233
this.statusText = statusText;
234
this.body = body;
235
};
236
get url() {
237
return this.request.url;
238
}
239
get base() {
240
return this.request.base;
241
};
242
set base(val) {
243
this.request.base = val;
244
};
245
};
246
247
class RequestContext {
248
constructor(request, worker, ultraviolet, body = null) {
249
this.ultraviolet = ultraviolet;
250
this.request = request;
251
this.headers = Object.fromEntries([...request.headers.entries()]);
252
this.method = request.method;
253
this.forward = [...worker.headers.forward];
254
this.address = worker.address;
255
this.body = body || null;
256
this.redirect = request.redirect;
257
this.credentials = 'omit';
258
this.mode = request.mode === 'cors' ? request.mode : 'same-origin';
259
this.blob = false;
260
};
261
get send() {
262
return new Request((!this.blob ? this.address.href + 'v1/' : 'blob:' + location.origin + this.url.pathname), {
263
method: this.method,
264
headers: {
265
'x-bare-protocol': this.url.protocol,
266
'x-bare-host': this.url.hostname,
267
'x-bare-path': this.url.pathname + this.url.search,
268
'x-bare-port': this.url.port || (this.url.protocol === 'https:' ? '443' : '80'),
269
'x-bare-headers': JSON.stringify(this.headers),
270
'x-bare-forward-headers': JSON.stringify(this.forward),
271
},
272
redirect: this.redirect,
273
credentials: this.credentials,
274
mode: location.origin !== this.address.origin ? 'cors' : this.mode,
275
body: this.body
276
});
277
};
278
get url() {
279
return this.ultraviolet.meta.url;
280
};
281
set url(val) {
282
this.ultraviolet.meta.url = val;
283
};
284
get base() {
285
return this.ultraviolet.meta.base;
286
};
287
set base(val) {
288
this.ultraviolet.meta.base = val;
289
};
290
}
291
292
function isHtml(url, contentType = '') {
293
return (Ultraviolet.mime.contentType((contentType || url.pathname)) || 'text/html').split(';')[0] === 'text/html';
294
};
295
296
class HookEvent {
297
#intercepted;
298
#returnValue;
299
constructor(data = {}, target = null, that = null) {
300
this.#intercepted = false;
301
this.#returnValue = null;
302
this.data = data;
303
this.target = target;
304
this.that = that;
305
};
306
get intercepted() {
307
return this.#intercepted;
308
};
309
get returnValue() {
310
return this.#returnValue;
311
};
312
respondWith(input) {
313
this.#returnValue = input;
314
this.#intercepted = true;
315
};
316
};
317
318
var R = typeof Reflect === 'object' ? Reflect : null
319
var ReflectApply = R && typeof R.apply === 'function'
320
? R.apply
321
: function ReflectApply(target, receiver, args) {
322
return Function.prototype.apply.call(target, receiver, args);
323
}
324
325
var ReflectOwnKeys
326
if (R && typeof R.ownKeys === 'function') {
327
ReflectOwnKeys = R.ownKeys
328
} else if (Object.getOwnPropertySymbols) {
329
ReflectOwnKeys = function ReflectOwnKeys(target) {
330
return Object.getOwnPropertyNames(target)
331
.concat(Object.getOwnPropertySymbols(target));
332
};
333
} else {
334
ReflectOwnKeys = function ReflectOwnKeys(target) {
335
return Object.getOwnPropertyNames(target);
336
};
337
}
338
339
function ProcessEmitWarning(warning) {
340
if (console && console.warn) console.warn(warning);
341
}
342
343
var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {
344
return value !== value;
345
}
346
347
function EventEmitter() {
348
EventEmitter.init.call(this);
349
}
350
351
// Backwards-compat with node 0.10.x
352
EventEmitter.EventEmitter = EventEmitter;
353
354
EventEmitter.prototype._events = undefined;
355
EventEmitter.prototype._eventsCount = 0;
356
EventEmitter.prototype._maxListeners = undefined;
357
358
// By default EventEmitters will print a warning if more than 10 listeners are
359
// added to it. This is a useful default which helps finding memory leaks.
360
var defaultMaxListeners = 10;
361
362
function checkListener(listener) {
363
if (typeof listener !== 'function') {
364
throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
365
}
366
}
367
368
Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
369
enumerable: true,
370
get: function() {
371
return defaultMaxListeners;
372
},
373
set: function(arg) {
374
if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {
375
throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.');
376
}
377
defaultMaxListeners = arg;
378
}
379
});
380
381
EventEmitter.init = function() {
382
383
if (this._events === undefined ||
384
this._events === Object.getPrototypeOf(this)._events) {
385
this._events = Object.create(null);
386
this._eventsCount = 0;
387
}
388
389
this._maxListeners = this._maxListeners || undefined;
390
};
391
392
// Obviously not all Emitters should be limited to 10. This function allows
393
// that to be increased. Set to zero for unlimited.
394
EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
395
if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {
396
throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.');
397
}
398
this._maxListeners = n;
399
return this;
400
};
401
402
function _getMaxListeners(that) {
403
if (that._maxListeners === undefined)
404
return EventEmitter.defaultMaxListeners;
405
return that._maxListeners;
406
}
407
408
EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
409
return _getMaxListeners(this);
410
};
411
412
EventEmitter.prototype.emit = function emit(type) {
413
var args = [];
414
for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);
415
var doError = (type === 'error');
416
417
var events = this._events;
418
if (events !== undefined)
419
doError = (doError && events.error === undefined);
420
else if (!doError)
421
return false;
422
423
// If there is no 'error' event listener then throw.
424
if (doError) {
425
var er;
426
if (args.length > 0)
427
er = args[0];
428
if (er instanceof Error) {
429
// Note: The comments on the `throw` lines are intentional, they show
430
// up in Node's output if this results in an unhandled exception.
431
throw er; // Unhandled 'error' event
432
}
433
// At least give some kind of context to the user
434
var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));
435
err.context = er;
436
throw err; // Unhandled 'error' event
437
}
438
439
var handler = events[type];
440
441
if (handler === undefined)
442
return false;
443
444
if (typeof handler === 'function') {
445
ReflectApply(handler, this, args);
446
} else {
447
var len = handler.length;
448
var listeners = arrayClone(handler, len);
449
for (var i = 0; i < len; ++i)
450
ReflectApply(listeners[i], this, args);
451
}
452
453
return true;
454
};
455
456
function _addListener(target, type, listener, prepend) {
457
var m;
458
var events;
459
var existing;
460
461
checkListener(listener);
462
463
events = target._events;
464
if (events === undefined) {
465
events = target._events = Object.create(null);
466
target._eventsCount = 0;
467
} else {
468
// To avoid recursion in the case that type === "newListener"! Before
469
// adding it to the listeners, first emit "newListener".
470
if (events.newListener !== undefined) {
471
target.emit('newListener', type,
472
listener.listener ? listener.listener : listener);
473
474
// Re-assign `events` because a newListener handler could have caused the
475
// this._events to be assigned to a new object
476
events = target._events;
477
}
478
existing = events[type];
479
}
480
481
if (existing === undefined) {
482
// Optimize the case of one listener. Don't need the extra array object.
483
existing = events[type] = listener;
484
++target._eventsCount;
485
} else {
486
if (typeof existing === 'function') {
487
// Adding the second element, need to change to array.
488
existing = events[type] =
489
prepend ? [listener, existing] : [existing, listener];
490
// If we've already got an array, just append.
491
} else if (prepend) {
492
existing.unshift(listener);
493
} else {
494
existing.push(listener);
495
}
496
497
// Check for listener leak
498
m = _getMaxListeners(target);
499
if (m > 0 && existing.length > m && !existing.warned) {
500
existing.warned = true;
501
// No error code for this since it is a Warning
502
// eslint-disable-next-line no-restricted-syntax
503
var w = new Error('Possible EventEmitter memory leak detected. ' +
504
existing.length + ' ' + String(type) + ' listeners ' +
505
'added. Use emitter.setMaxListeners() to ' +
506
'increase limit');
507
w.name = 'MaxListenersExceededWarning';
508
w.emitter = target;
509
w.type = type;
510
w.count = existing.length;
511
ProcessEmitWarning(w);
512
}
513
}
514
515
return target;
516
}
517
518
EventEmitter.prototype.addListener = function addListener(type, listener) {
519
return _addListener(this, type, listener, false);
520
};
521
522
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
523
524
EventEmitter.prototype.prependListener =
525
function prependListener(type, listener) {
526
return _addListener(this, type, listener, true);
527
};
528
529
function onceWrapper() {
530
if (!this.fired) {
531
this.target.removeListener(this.type, this.wrapFn);
532
this.fired = true;
533
if (arguments.length === 0)
534
return this.listener.call(this.target);
535
return this.listener.apply(this.target, arguments);
536
}
537
}
538
539
function _onceWrap(target, type, listener) {
540
var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };
541
var wrapped = onceWrapper.bind(state);
542
wrapped.listener = listener;
543
state.wrapFn = wrapped;
544
return wrapped;
545
}
546
547
EventEmitter.prototype.once = function once(type, listener) {
548
checkListener(listener);
549
this.on(type, _onceWrap(this, type, listener));
550
return this;
551
};
552
553
EventEmitter.prototype.prependOnceListener =
554
function prependOnceListener(type, listener) {
555
checkListener(listener);
556
this.prependListener(type, _onceWrap(this, type, listener));
557
return this;
558
};
559
560
// Emits a 'removeListener' event if and only if the listener was removed.
561
EventEmitter.prototype.removeListener =
562
function removeListener(type, listener) {
563
var list, events, position, i, originalListener;
564
565
checkListener(listener);
566
567
events = this._events;
568
if (events === undefined)
569
return this;
570
571
list = events[type];
572
if (list === undefined)
573
return this;
574
575
if (list === listener || list.listener === listener) {
576
if (--this._eventsCount === 0)
577
this._events = Object.create(null);
578
else {
579
delete events[type];
580
if (events.removeListener)
581
this.emit('removeListener', type, list.listener || listener);
582
}
583
} else if (typeof list !== 'function') {
584
position = -1;
585
586
for (i = list.length - 1; i >= 0; i--) {
587
if (list[i] === listener || list[i].listener === listener) {
588
originalListener = list[i].listener;
589
position = i;
590
break;
591
}
592
}
593
594
if (position < 0)
595
return this;
596
597
if (position === 0)
598
list.shift();
599
else {
600
spliceOne(list, position);
601
}
602
603
if (list.length === 1)
604
events[type] = list[0];
605
606
if (events.removeListener !== undefined)
607
this.emit('removeListener', type, originalListener || listener);
608
}
609
610
return this;
611
};
612
613
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
614
615
EventEmitter.prototype.removeAllListeners =
616
function removeAllListeners(type) {
617
var listeners, events, i;
618
619
events = this._events;
620
if (events === undefined)
621
return this;
622
623
// not listening for removeListener, no need to emit
624
if (events.removeListener === undefined) {
625
if (arguments.length === 0) {
626
this._events = Object.create(null);
627
this._eventsCount = 0;
628
} else if (events[type] !== undefined) {
629
if (--this._eventsCount === 0)
630
this._events = Object.create(null);
631
else
632
delete events[type];
633
}
634
return this;
635
}
636
637
// emit removeListener for all listeners on all events
638
if (arguments.length === 0) {
639
var keys = Object.keys(events);
640
var key;
641
for (i = 0; i < keys.length; ++i) {
642
key = keys[i];
643
if (key === 'removeListener') continue;
644
this.removeAllListeners(key);
645
}
646
this.removeAllListeners('removeListener');
647
this._events = Object.create(null);
648
this._eventsCount = 0;
649
return this;
650
}
651
652
listeners = events[type];
653
654
if (typeof listeners === 'function') {
655
this.removeListener(type, listeners);
656
} else if (listeners !== undefined) {
657
// LIFO order
658
for (i = listeners.length - 1; i >= 0; i--) {
659
this.removeListener(type, listeners[i]);
660
}
661
}
662
663
return this;
664
};
665
666
function _listeners(target, type, unwrap) {
667
var events = target._events;
668
669
if (events === undefined)
670
return [];
671
672
var evlistener = events[type];
673
if (evlistener === undefined)
674
return [];
675
676
if (typeof evlistener === 'function')
677
return unwrap ? [evlistener.listener || evlistener] : [evlistener];
678
679
return unwrap ?
680
unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);
681
}
682
683
EventEmitter.prototype.listeners = function listeners(type) {
684
return _listeners(this, type, true);
685
};
686
687
EventEmitter.prototype.rawListeners = function rawListeners(type) {
688
return _listeners(this, type, false);
689
};
690
691
EventEmitter.listenerCount = function(emitter, type) {
692
if (typeof emitter.listenerCount === 'function') {
693
return emitter.listenerCount(type);
694
} else {
695
return listenerCount.call(emitter, type);
696
}
697
};
698
699
EventEmitter.prototype.listenerCount = listenerCount;
700
function listenerCount(type) {
701
var events = this._events;
702
703
if (events !== undefined) {
704
var evlistener = events[type];
705
706
if (typeof evlistener === 'function') {
707
return 1;
708
} else if (evlistener !== undefined) {
709
return evlistener.length;
710
}
711
}
712
713
return 0;
714
}
715
716
EventEmitter.prototype.eventNames = function eventNames() {
717
return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
718
};
719
720
function arrayClone(arr, n) {
721
var copy = new Array(n);
722
for (var i = 0; i < n; ++i)
723
copy[i] = arr[i];
724
return copy;
725
}
726
727
function spliceOne(list, index) {
728
for (; index + 1 < list.length; index++)
729
list[index] = list[index + 1];
730
list.pop();
731
}
732
733
function unwrapListeners(arr) {
734
var ret = new Array(arr.length);
735
for (var i = 0; i < ret.length; ++i) {
736
ret[i] = arr[i].listener || arr[i];
737
}
738
return ret;
739
}
740
741
function once(emitter, name) {
742
return new Promise(function (resolve, reject) {
743
function errorListener(err) {
744
emitter.removeListener(name, resolver);
745
reject(err);
746
}
747
748
function resolver() {
749
if (typeof emitter.removeListener === 'function') {
750
emitter.removeListener('error', errorListener);
751
}
752
resolve([].slice.call(arguments));
753
};
754
755
eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });
756
if (name !== 'error') {
757
addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });
758
}
759
});
760
}
761
762
function addErrorHandlerIfEventEmitter(emitter, handler, flags) {
763
if (typeof emitter.on === 'function') {
764
eventTargetAgnosticAddListener(emitter, 'error', handler, flags);
765
}
766
}
767
768
function eventTargetAgnosticAddListener(emitter, name, listener, flags) {
769
if (typeof emitter.on === 'function') {
770
if (flags.once) {
771
emitter.once(name, listener);
772
} else {
773
emitter.on(name, listener);
774
}
775
} else if (typeof emitter.addEventListener === 'function') {
776
// EventTarget does not have `error` event semantics like Node
777
// EventEmitters, we do not listen for `error` events here.
778
emitter.addEventListener(name, function wrapListener(arg) {
779
// IE does not have builtin `{ once: true }` support so we
780
// have to do it manually.
781
if (flags.once) {
782
emitter.removeEventListener(name, wrapListener);
783
}
784
listener(arg);
785
});
786
} else {
787
throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type ' + typeof emitter);
788
}
789
}
790
791