···11+// https://github.com/electron/asar
22+// http://formats.kaitai.io/python_pickle/
33+import { BinaryReader } from "./util/binary";
44+55+/*
66+ The asar format is kinda bad, especially because it uses multiple pickle
77+ entries. It spams sizes, expecting us to read small buffers and parse those,
88+ but we can just take it all through at once without having to create multiple
99+ BinaryReaders. This implementation might be wrong, though.
1010+1111+ This either has size/offset or files but I can't get the type to cooperate,
1212+ so pretend this is a union.
1313+*/
1414+1515+type AsarEntry = {
1616+ size: number;
1717+ offset: `${number}`; // who designed this
1818+1919+ files?: Record<string, AsarEntry>;
2020+};
2121+2222+export default function extractAsar(file: ArrayBuffer) {
2323+ const array = new Uint8Array(file);
2424+ const br = new BinaryReader(array);
2525+2626+ // two uints, one containing the number '4', to signify that the other uint takes up 4 bytes
2727+ // bravo, electron, bravo
2828+ const _payloadSize = br.readUInt32();
2929+ const _headerSize = br.readInt32();
3030+3131+ const headerStringStart = br.position;
3232+ const headerStringSize = br.readUInt32(); // How big the block is
3333+ const actualStringSize = br.readUInt32(); // How big the string in that block is
3434+3535+ const base = headerStringStart + headerStringSize + 4;
3636+3737+ const string = br.readString(actualStringSize);
3838+ const header: AsarEntry = JSON.parse(string);
3939+4040+ const ret: Record<string, Uint8Array> = {};
4141+ function addDirectory(dir: AsarEntry, path: string) {
4242+ for (const [name, data] of Object.entries(dir.files!)) {
4343+ const fullName = path + "/" + name;
4444+ if (data.files != null) {
4545+ addDirectory(data, fullName);
4646+ } else {
4747+ br.position = base + parseInt(data.offset);
4848+ const file = br.read(data.size);
4949+ ret[fullName] = file;
5050+ }
5151+ }
5252+ }
5353+5454+ addDirectory(header, "");
5555+5656+ return ret;
5757+}