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