@equicord/unzip-crx
Version:
unzip chrome extension files (*.crx)
69 lines (65 loc) • 2.66 kB
JavaScript
;Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }// src/index.ts
var _promises = require('fs/promises'); var _promises2 = _interopRequireDefault(_promises);
var _path = require('path'); var _path2 = _interopRequireDefault(_path);
var _jszip = require('jszip'); var _jszip2 = _interopRequireDefault(_jszip);
function mkdirp(path2) {
return _promises2.default.mkdir(path2, { recursive: true });
}
function crxToZip(buf) {
function calcLength(a, b, c, d) {
let length = 0;
length += a << 0;
length += b << 8;
length += c << 16;
length += d << 24 >>> 0;
return length;
}
if (buf[0] === 80 && buf[1] === 75 && buf[2] === 3 && buf[3] === 4) {
return buf;
}
if (buf[0] !== 67 || buf[1] !== 114 || buf[2] !== 50 || buf[3] !== 52) {
throw new Error("Invalid header: Does not start with Cr24");
}
const isV3 = buf[4] === 3;
const isV2 = buf[4] === 2;
if (!isV2 && !isV3 || buf[5] || buf[6] || buf[7]) {
throw new Error("Unexpected crx format version number.");
}
if (isV2) {
const publicKeyLength = calcLength(buf[8], buf[9], buf[10], buf[11]);
const signatureLength = calcLength(buf[12], buf[13], buf[14], buf[15]);
const zipStartOffset2 = 16 + publicKeyLength + signatureLength;
return buf.slice(zipStartOffset2, buf.length);
}
const headerSize = calcLength(buf[8], buf[9], buf[10], buf[11]);
const zipStartOffset = 12 + headerSize;
return buf.slice(zipStartOffset, buf.length);
}
async function unzip(crxFilePath, destination) {
const filePath = _path2.default.resolve(crxFilePath);
let dest;
if (destination) {
dest = destination;
} else {
const extname = _path2.default.extname(crxFilePath);
const basename = _path2.default.basename(crxFilePath, extname);
const dirname = _path2.default.dirname(crxFilePath);
dest = _path2.default.resolve(dirname, basename);
}
const buf = await _promises2.default.readFile(filePath);
const { files } = await _jszip2.default.loadAsync(crxToZip(buf));
return Promise.all(
Object.keys(files).map(async (filename) => {
const isFile = !files[filename].dir;
const fullPath = _path2.default.join(dest, filename);
const directory = isFile && _path2.default.dirname(fullPath) || fullPath;
await mkdirp(directory);
if (isFile) {
const content = await files[filename].async("nodebuffer");
await _promises2.default.writeFile(fullPath, content);
}
})
);
}
var src_default = unzip;
exports.default = src_default; exports.unzip = unzip;