| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788 |
- "use strict";
- var fs = require("fs");
- var path = require("path");
- var jszip = require("jszip");
- var mkdirp = require("mkdirp");
- var promisify = require("yaku/lib/promisify");
- var writeFile = promisify(fs.writeFile);
- var readFile = promisify(fs.readFile);
- var mkdir = promisify(mkdirp);
- function crxToZip(buf) {
- function calcLength(a, b, c, d) {
- var length = 0;
- length += a;
- length += b << 8;
- length += c << 16;
- length += d << 24;
- return length;
- }
- // 50 4b 03 04
- // This is actually a zip file
- if (buf[0] === 80 && buf[1] === 75 && buf[2] === 3 && buf[3] === 4) {
- return buf;
- }
- // 43 72 32 34 (Cr24)
- if (buf[0] !== 67 || buf[1] !== 114 || buf[2] !== 50 || buf[3] !== 52) {
- throw new Error("Invalid header: Does not start with Cr24");
- }
- // 02 00 00 00
- // or
- // 03 00 00 00
- var isV3 = buf[4] === 3;
- var isV2 = buf[4] === 2;
- if (!isV2 && !isV3 || buf[5] || buf[6] || buf[7]) {
- throw new Error("Unexpected crx format version number.");
- }
- if (isV2) {
- var publicKeyLength = calcLength(buf[8], buf[9], buf[10], buf[11]);
- var signatureLength = calcLength(buf[12], buf[13], buf[14], buf[15]);
- // 16 = Magic number (4), CRX format version (4), lengths (2x4)
- var _zipStartOffset = 16 + publicKeyLength + signatureLength;
- return buf.slice(_zipStartOffset, buf.length);
- }
- // v3 format has header size and then header
- var headerSize = calcLength(buf[8], buf[9], buf[10], buf[11]);
- var zipStartOffset = 12 + headerSize;
- return buf.slice(zipStartOffset, buf.length);
- }
- function unzip(crxFilePath, destination) {
- var filePath = path.resolve(crxFilePath);
- var extname = path.extname(crxFilePath);
- var basename = path.basename(crxFilePath, extname);
- var dirname = path.dirname(crxFilePath);
- destination = destination || path.resolve(dirname, basename);
- return readFile(filePath).then(function (buf) {
- return jszip.loadAsync(crxToZip(buf));
- }).then(function (zip) {
- var zipFileKeys = Object.keys(zip.files);
- return Promise.all(zipFileKeys.map(function (filename) {
- var isFile = !zip.files[filename].dir;
- var fullPath = path.join(destination, filename);
- var directory = isFile && path.dirname(fullPath) || fullPath;
- var content = zip.files[filename].async("nodebuffer");
- return mkdir(directory).then(function () {
- return isFile ? content : false;
- }).then(function (data) {
- return data ? writeFile(fullPath, data) : true;
- });
- }));
- });
- }
- module.exports = unzip;
|