Skip to content

Commit 192f225

Browse files
authored
Add CRX file viewer with JSZip integration
Signed-off-by: canvrs <ngde@web.de>
1 parent fc5e76a commit 192f225

File tree

1 file changed

+65
-0
lines changed

1 file changed

+65
-0
lines changed

viewer.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// viewer.js
2+
// Requires JSZip to handle CRX extraction
3+
// Include JSZip via CDN
4+
const script = document.createElement('script');
5+
script.src = "https://cdnjs.cloudflare.com/ajax/libs/jszip/3.11.0/jszip.min.js";
6+
document.head.appendChild(script);
7+
8+
script.onload = () => {
9+
const crxInput = document.getElementById('crxInput');
10+
const fileList = document.getElementById('fileList');
11+
const fileContent = document.getElementById('fileContent');
12+
13+
crxInput.addEventListener('change', async (e) => {
14+
const file = e.target.files[0];
15+
if (!file) return;
16+
17+
fileList.innerHTML = "Loading CRX...";
18+
19+
const buffer = await file.arrayBuffer();
20+
21+
// CRX Header parsing (CRXv2/v3)
22+
// Skip the header and extract zip portion
23+
let zipStart = 0;
24+
const magic = new Uint8Array(buffer.slice(0, 4));
25+
if (magic[0] !== 67 || magic[1] !== 82 || magic[2] !== 67 || magic[3] !== 0x21) {
26+
alert("Not a valid CRX file");
27+
return;
28+
}
29+
30+
// CRX v2 header size: 16 + public key length + signature length
31+
const dv = new DataView(buffer);
32+
const version = dv.getUint32(4, true);
33+
if (version === 2) {
34+
const publicKeyLength = dv.getUint32(8, true);
35+
const signatureLength = dv.getUint32(12, true);
36+
zipStart = 16 + publicKeyLength + signatureLength;
37+
} else if (version === 3) {
38+
// CRXv3 uses a header size field at 8
39+
const headerSize = dv.getUint32(8, true);
40+
zipStart = 12 + headerSize;
41+
} else {
42+
alert("Unsupported CRX version: " + version);
43+
return;
44+
}
45+
46+
const zipData = buffer.slice(zipStart);
47+
48+
const zip = await JSZip.loadAsync(zipData);
49+
fileList.innerHTML = "";
50+
51+
// Populate file list
52+
Object.keys(zip.files).forEach(filename => {
53+
const item = document.createElement('div');
54+
item.textContent = filename;
55+
item.className = 'file-item';
56+
item.addEventListener('click', async () => {
57+
const content = await zip.files[filename].async('string');
58+
fileContent.textContent = content;
59+
});
60+
fileList.appendChild(item);
61+
});
62+
63+
fileContent.textContent = "Select a file to view its content...";
64+
});
65+
};

0 commit comments

Comments
 (0)