Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
RishiRecon
GitHub Repository: RishiRecon/exploits
Path: blob/main/misc/burgeria/js/loader.js
36008 views
1
const supportDecoderApi = ('DecompressionStream' in self);
2
const isSWC = (head) => (head[0] === 0x43 && head[1] === 0x57 && head[2] === 0x53);
3
const outputSize = (head) => new DataView(head.buffer).getUint32(4, true);
4
5
function Decoder(size, offset = 8) {
6
if(!supportDecoderApi) {
7
throw 'Your browser not support DecompressionStream =(';
8
}
9
10
const decoder = new self.DecompressionStream('deflate');
11
const decoderW = decoder.writable.getWriter();
12
const decoderR = decoder.readable.getReader();
13
const buffer = new Uint8Array(size);
14
15
let isRunned = false;
16
let isDone = false;
17
18
let donableCallback;
19
20
function run() {
21
decoderR.read().then(function next(state) {
22
const done = state.done;
23
const value = state.value;
24
25
if (value) {
26
buffer.set(value, offset);
27
//console.debug("[Loader] Decoded chunk:", offset);
28
29
offset += value.length;
30
}
31
32
if (done || offset >= size) {
33
isDone = true;
34
35
if(donableCallback) {
36
donableCallback();
37
}
38
39
console.debug("[Loader] Decoder closed:", offset);
40
return;
41
}
42
43
return decoderR.read().then(next);
44
});
45
}
46
47
return {
48
get buffer() {
49
return buffer;
50
},
51
52
write(buffer) {
53
decoderW.ready.then(()=>{
54
decoderW.write(buffer);
55
56
if(!isRunned) {
57
isRunned = true;
58
run();
59
}
60
});
61
},
62
63
readAll() {
64
if(isDone) {
65
return Promise.resolve(buffer);
66
}
67
68
return new Promise((res)=>{
69
donableCallback = () => {
70
res(buffer);
71
}
72
})
73
}
74
}
75
}
76
77
function Fetcher(url = '', progress = f => f) {
78
let total = 0;
79
let reader;
80
let chunks = [];
81
82
progress && progress(0);
83
84
return fetch(url)
85
.then((request) => {
86
total = +request.headers.get('Content-Length');
87
reader = request.body.getReader();
88
89
return reader.read();
90
})
91
.then( (data) => {
92
const firstChunk = data.value;
93
94
console.debug("[Loader] Header:", String.fromCharCode.apply(null,firstChunk.slice(0, 3).reverse()));
95
96
let loaded = 0;
97
let decoder;
98
99
if (supportDecoderApi && isSWC(firstChunk)) {
100
const totalDecodedSize = outputSize(firstChunk);
101
const swcHeader = firstChunk.slice(0, 8);
102
103
swcHeader[0] = 70; // SWC => SWF
104
105
console.debug("[Loader] SWC size:", outputSize(firstChunk));
106
107
decoder = Decoder(totalDecodedSize, 8);
108
decoder.buffer.set(swcHeader);
109
110
// push witout header
111
decoder.write(firstChunk.slice(8));
112
113
} else {
114
chunks.push(firstChunk);
115
}
116
117
loaded += firstChunk.length;
118
119
progress && progress( Math.min(1, loaded / total));
120
121
// update all other chunks reqursive while !done
122
return reader.read().then( function moveNext(state) {
123
124
if (state.done) {
125
if(!decoder) {
126
let buffer = new Uint8Array(loaded);
127
let offset = 0;
128
129
chunks.forEach((e) => {
130
buffer.set(e, offset);
131
offset += e.length;
132
});
133
134
return buffer;
135
}else {
136
return decoder.readAll();
137
}
138
}
139
140
const value = state.value;
141
142
loaded += value.length;
143
progress && progress( Math.min(1, loaded / total));
144
145
if (!decoder) {
146
chunks.push(value);
147
} else {
148
decoder.write(value);
149
}
150
151
return reader.read().then(moveNext);
152
});
153
})
154
}
155
156
var Loader = (function () {
157
function loadBinary(file, progressEvent = f => f) {
158
const isScript = file.path.indexOf(".js") > -1;
159
160
if (!isScript && supportDecoderApi ) {
161
return Fetcher(file.path, progressEvent)
162
.then((buffer)=>({
163
meta: file.meta || {},
164
name: file.name,
165
path: file.path,
166
resourceType: file.resourceType,
167
data: buffer.buffer,
168
type: "swf",
169
}));
170
}
171
172
const req = new XMLHttpRequest();
173
174
req.addEventListener("progress", e => {
175
const gzip = req.getAllResponseHeaders('content-encoding') === 'gzip';
176
177
// get from progress, then from request, and if not valid - from file
178
const total = e.total || (+req.getAllResponseHeaders('content-length')) || (file.size * (gzip ? 0.25 : 1));
179
180
if(!total) {
181
progressEvent(1);
182
return;
183
}
184
185
progressEvent(Math.min(1, e.loaded / total) );
186
});
187
188
req.open("GET", file.path, true);
189
req.responseType = isScript ? "text" : "arraybuffer";
190
191
return new Promise((res, rej) => {
192
req.addEventListener("error", rej);
193
req.addEventListener("load", () => {
194
progressEvent(1);
195
196
if (isScript) {
197
// unsafe
198
//eval(req.response);
199
200
const b = new Blob([req.response], { type: "text/javascript" });
201
// use blob
202
loadScript(URL.createObjectURL(b)).then(() => res(undefined));
203
204
return;
205
}
206
res({
207
meta: file.meta || {},
208
name: file.name,
209
path: file.path,
210
resourceType: file.resourceType,
211
data: req.response,
212
type: isScript ? "js" : "swf",
213
});
214
});
215
216
req.send();
217
});
218
}
219
220
function loadScript(file, progress) {
221
const head = document.querySelector("head");
222
const script = document.createElement("script");
223
224
return new Promise((res, rej) => {
225
Object.assign(script, {
226
type: "text/javascript",
227
async: true,
228
src: file.path || file,
229
onload: () => {
230
progress && progress(1);
231
res(script);
232
},
233
onerror: rej,
234
onreadystatechange: s => {
235
if (script.readyState == "complete") { }
236
},
237
});
238
239
head.appendChild(script);
240
});
241
}
242
243
function createReporter(callback, childs, weight) {
244
const reporter = {
245
callback: callback,
246
childs: childs ? childs.slice() : undefined,
247
value: 0,
248
weight: weight || 1,
249
250
get report() {
251
return function (v) {
252
if (!this.childs) {
253
this.value = v * this.weight;
254
} else {
255
let summ = 0;
256
let v = 0;
257
258
this.childs.forEach((e) => {
259
summ += e.weight || 1;
260
v += (e.value || 0);
261
});
262
263
this.value = v / summ;
264
}
265
266
this.callback && this.callback(this.value);
267
}.bind(this);
268
},
269
};
270
271
if (childs) {
272
childs.forEach(e => {
273
e.callback = reporter.report;
274
});
275
}
276
277
return reporter;
278
}
279
280
function runLoadingProcess(jsFiles, binaryFiles, progressEvent = f => f, _debugScripts) {
281
const jsCount = jsFiles.length;
282
const binCount = binaryFiles.length;
283
284
const all = jsFiles.concat(binaryFiles);
285
286
const reporters = Array.from({ length: jsCount + binCount }, () => createReporter());
287
createReporter(progressEvent, reporters);
288
289
let pendings;
290
291
if (!_debugScripts) {
292
pendings = all.map((e, i) => loadBinary(e, reporters[i].report));
293
} else {
294
pendings = binaryFiles.map((e, i) => loadBinary(e, reporters[i].report))
295
pendings = pendings.concat(jsFiles.map((e, i) => loadScript(e, reporters[i + binCount].report)))
296
}
297
298
return Promise.all(pendings).then(data => {
299
return data.filter(e => e && e.type === 'swf');
300
});
301
}
302
303
let fillLine = undefined;
304
let __config = undefined;
305
let __splash = undefined;
306
let __pr__root = undefined;
307
let handleResize = undefined;
308
309
window["setStageDimensions"]=function(x, y, w, h){
310
__config.x=x;
311
__config.y=y;
312
__config.w=w;
313
__config.h=h;
314
if(window["AVMPlayerPoki"]){
315
window["AVMPlayerPoki"].setStageDimensions(x, y, w, h);
316
}
317
if(handleResize){
318
handleResize();
319
}
320
}
321
322
function runGame(progressEvent = f => f, completeEvent = f => f) {
323
324
if (!__config) {
325
init();
326
}
327
328
let jss = Array.isArray(__config.runtime) ? jss : [__config.runtime];
329
jss = jss.map(e => ({ path: e.path || e, size: e.size || 0 }));
330
331
const bins = __config.binary;
332
333
const loadReporter = createReporter(null, null, 4);
334
const avmReporter = createReporter((f) => {
335
console.log('AVM Load', f);
336
}, null, __config.progressParserWeigth ? __config.progressParserWeigth : 0.001);
337
338
createReporter(function (fill) {
339
fillLine(fill);
340
// rereport
341
progressEvent(fill);
342
}, [loadReporter, avmReporter])
343
344
const complete = f => {
345
// rereport
346
completeEvent(f);
347
348
if (__config.start) {
349
350
// start image exists.
351
// hide progressbar, show startimage and wait for user-input to start the game
352
353
Object.assign(__pr__root.style, {
354
visibility: "hidden",
355
opacity: 0,
356
});
357
Object.assign(__splash.style, {
358
backgroundImage: `url(${__config.start})`,
359
});
360
let onCLick = (e) => {
361
window.removeEventListener("click", onCLick);
362
Object.assign(__splash.style, {
363
visibility: "hidden",
364
opacity: 0,
365
});
366
if (!f)
367
throw ("PokiPlayer did not send a callback for starting game");
368
f();
369
window.setTimeout(()=>{
370
window.removeEventListener("resize", handleResize);
371
handleResize=null;
372
}, 500)
373
};
374
window.addEventListener("click", onCLick);
375
}
376
else {
377
// no start image.
378
// game will be started automatically
379
Object.assign(__splash.style, {
380
visibility: "hidden",
381
opacity: 0,
382
});
383
// use Timeout, so css transition can complete first
384
window.setTimeout(()=>{
385
window.removeEventListener("resize", handleResize);
386
handleResize=null;
387
}, 500)
388
}
389
};
390
391
runLoadingProcess(jss, bins, loadReporter.report, __config.debug).then(data => {
392
const runner = window["startPokiGame"];
393
if (!runner) {
394
throw "Could not find a 'startPokiGame' method";
395
}
396
397
__config.files = data;
398
399
runner(__config);
400
401
// now poki player is available at window["AVMPlayerPoki"]
402
// can be used to update the stageDimensions:
403
// window["AVMPlayerPoki"].setStageDimensions(x, y, w, h);
404
// values can be
405
// numbers (absolute pixel values)
406
// strings (percentage of window.innerHeight/innerWidth in 0-100)
407
});
408
409
// make functions avilailable on window, so the loaded js-code can access and execute them
410
Object.assign(window, {
411
updatePokiProgressBar: avmReporter.report,
412
pokiGameParseComplete: complete,
413
});
414
}
415
416
function init(config) {
417
if (!config) {
418
throw new Error("Config is required");
419
}
420
421
__config = config;
422
423
const splash = document.querySelector("#splash__image");
424
const pr__root = document.querySelector("#progress__root");
425
const pr__line = document.querySelector("#progress__line");
426
427
__splash = splash;
428
__pr__root = pr__root;
429
430
const pr_conf = config.progress;
431
pr_conf.rect = pr_conf.rect || [0, 0.9, 1, 0.2];
432
433
Object.assign(splash.style, {
434
backgroundImage: `url(${config.splash})`,
435
visibility: "visible",
436
});
437
438
Object.assign(pr__root.style, {
439
background: pr_conf.back,
440
left: `${100 * pr_conf.rect[0]}%`,
441
top: `${100 * pr_conf.rect[1]}%`,
442
width: `${100 * pr_conf.rect[2]}%`,
443
height: `${100 * pr_conf.rect[3]}%`,
444
});
445
446
Object.assign(pr__line.style, {
447
background: pr_conf.line,
448
});
449
450
fillLine = fill => {
451
switch (pr_conf.direction) {
452
case "tb": {
453
Object.assign(pr__line.style, {
454
height: `${fill * 100}%`,
455
width: "100%",
456
});
457
break;
458
}
459
case "lr":
460
default: {
461
Object.assign(pr__line.style, {
462
height: "100%",
463
width: `${fill * 100}%`,
464
});
465
}
466
}
467
};
468
469
handleResize = () => {
470
let x=(typeof config.x==="string")?parseFloat(config.x.replace("%", ""))/100*window.innerWidth:config.x;
471
let y=(typeof config.y==="string")?parseFloat(config.y.replace("%", ""))/100*window.innerHeight:config.y;
472
let w=(typeof config.w==="string")?parseFloat(config.w.replace("%", ""))/100*window.innerWidth:config.w;
473
let h=(typeof config.h==="string")?parseFloat(config.h.replace("%", ""))/100*window.innerHeight:config.h;
474
475
if(!x) x=0;
476
if(!y) y=0;
477
if(!w) w=window.innerWidth;
478
if(!h) h=window.innerHeight;
479
480
const minMax = Math.min(h / config.height, w / config.width);
481
const rw = Math.ceil(config.width * minMax);
482
const rh = Math.ceil(config.height * minMax);
483
const rx = x+(w - rw) / 2;
484
const ry = y+(h - rh) / 2;
485
486
Object.assign(splash.style, {
487
width: `${rw}px`,
488
height: `${rh}px`,
489
left: `${rx}px`,
490
top: `${ry}px`,
491
});
492
};
493
494
window.addEventListener("resize", handleResize);
495
handleResize();
496
}
497
498
return {
499
init,
500
runGame,
501
};
502
})();
503
504