Socket
Socket
Sign inDemoInstall

crx

Package Overview
Dependencies
Maintainers
3
Versions
32
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

crx - npm Package Compare versions

Comparing version 3.2.1 to 4.0.0

.eslintrc.js

154

bin/crx.js

@@ -5,8 +5,10 @@ #!/usr/bin/env node

var fs = require("fs");
var rsa = require('node-rsa');
var Promise = require('es6-promise').Promise;
var rsa = require("node-rsa");
var {promisify} = require("util");
var writeFile = promisify(fs.writeFile);
var readFile = promisify(fs.readFile);
var program = require("commander");
var ChromeExtension = require("..");
var pkg = require('../package.json');
var pkg = require("../package.json");

@@ -31,6 +33,12 @@ var resolve = path.resolve;

.description("pack [directory] into a .crx extension")
.option("-o, --output <file>", "write the crx content to <file> instead of stdout")
.option(
"-o, --output <file>",
"write the crx content to <file> instead of stdout"
)
.option("--zip-output <file>", "write the zip content to <file>")
.option("-p, --private-key <file>", "relative path to private key [key.pem]")
.option("-b, --max-buffer <total>", "max amount of memory allowed to generate the crx, in byte")
.option(
"-b, --max-buffer <total>",
"max amount of memory allowed to generate the crx, in byte"
)
.action(pack);

@@ -40,18 +48,2 @@

/**
* Read a specified key file from disk
* @param {String} keyPath path to the key to read
* @returns {Promise}
*/
function readKeyFile(keyPath) {
return new Promise(function (resolve, reject) {
fs.readFile(keyPath, function (err, data) {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}

@@ -64,19 +56,8 @@ /**

function generateKeyFile(keyPath) {
return new Promise(function(resolve, reject) {
var key = new rsa({b: 2048}),
keyVal = key.exportKey('pkcs1-private-pem');
fs.writeFile(keyPath, keyVal, function(err){
if (err) {
throw err;
}
console.log('Key file has been generated at %s', keyPath);
resolve(keyVal);
});
});
return Promise.resolve(new rsa({ b: 2048 }))
.then(key => key.exportKey("pkcs1-private-pem"))
.then(keyVal => writeFile(keyPath, keyVal));
}
function keygen (dir, program) {
function keygen(dir, program) {
dir = dir ? resolve(cwd, dir) : cwd;

@@ -86,5 +67,5 @@

fs.exists(keyPath, function (exists) {
fs.exists(keyPath, function(exists) {
if (exists && !program.force) {
throw new Error('key.pem already exists in the given location.');
throw new Error("key.pem already exists in the given location.");
}

@@ -96,10 +77,16 @@

function pack (dir, program) {
function pack(dir, program) {
var input = dir ? resolve(cwd, dir) : cwd;
var keyPath = program.privateKey ? resolve(cwd, program.privateKey) : join(input, "key.pem");
var keyPath = program.privateKey
? resolve(cwd, program.privateKey)
: join(input, "key.pem");
var output;
if (program.output) {
if (path.extname(program.output) !== '.crx') {
throw new Error('-o file is expected to have a `.crx` suffix: [' + program.output + '] was given.');
if (path.extname(program.output) !== ".crx") {
throw new Error(
"-o file is expected to have a `.crx` suffix: [" +
program.output +
"] was given."
);
}

@@ -109,4 +96,8 @@ }

if (program.zipOutput) {
if (path.extname(program.zipOutput) !== '.zip') {
throw new Error('--zip-output file is expected to have a `.zip` suffix: [' + program.zipOutput + '] was given.');
if (path.extname(program.zipOutput) !== ".zip") {
throw new Error(
"--zip-output file is expected to have a `.zip` suffix: [" +
program.zipOutput +
"] was given."
);
}

@@ -117,42 +108,53 @@ }

rootDirectory: input,
maxBuffer: program.maxBuffer
maxBuffer: program.maxBuffer
});
readKeyFile(keyPath).then(null, function (err) {
// If the key file doesn't exist, create one
if (err.code === 'ENOENT') {
return generateKeyFile(keyPath);
} else {
throw err;
}
}).then(function (key) {
crx.privateKey = key;
}).then(function () {
crx.load().then(function () {
return crx.loadContents();
}).then(function (zipBuffer) {
if (program.zipOutput) {
var outFile = resolve(cwd, program.zipOutput);
fs.createWriteStream(outFile).end(zipBuffer);
readFile(keyPath)
.then(null, function(err) {
// If the key file doesn't exist, create one
if (err.code === "ENOENT") {
return generateKeyFile(keyPath);
} else {
throw err;
}
})
.then(function(key) {
crx.privateKey = key;
})
.then(function() {
crx
.load()
.then(() => crx.loadContents())
.then(function(fileBuffer) {
if (program.zipOutput) {
var outFile = resolve(cwd, program.zipOutput);
return crx.pack(zipBuffer);
}).then(function (crxBuffer) {
fs.createWriteStream(outFile).end(fileBuffer);
}
else {
return crx.pack(fileBuffer);
}
})
.then(function(crxBuffer) {
if (program.zipOutput) {
return;
}
else if (program.output) {
output = program.output;
}
else {
output = path.basename(cwd) + ".crx";
}
if (program.output) {
output = program.output;
} else {
output = path.basename(cwd) + '.crx';
}
var outFile = resolve(cwd, output);
(outFile ? fs.createWriteStream(outFile) : process.stdout).end(crxBuffer);
}).then(function () {
console.log('%s has been generated in %s', output, cwd);
var outFile = resolve(cwd, output);
if (outFile) {
fs.createWriteStream(outFile).end(crxBuffer);
}
else {
process.stdout.end(crxBuffer);
}
});
});
});
}
module.exports = program;
## Change Log
### 3.2.1 (2016/10/13 13:13 +00:00)
### 4.0.0 (2019/02/03 15:57 +00:00)
- [#95](https://github.com/oncletom/crx/pull/95) Release crx@4 (@oncletom)
- [#93](https://github.com/oncletom/crx/pull/93) fix demo code (@g8up)
- [#88](https://github.com/oncletom/crx/pull/88) Bump Node.js version requirement (@oncletom)
- [#90](https://github.com/oncletom/crx/pull/90) Fix syntax in module usage (@blimmer)
- [#83](https://github.com/oncletom/crx/pull/83) Update dependencies (@oncletom)
- [#81](https://github.com/oncletom/crx/pull/81) Fix extension ID calculation from path (@oncletom, @conioh)
- [#76](https://github.com/oncletom/crx/pull/76) Add Appveyor configuration to test build on Windows (@oncletom)
- [#71](https://github.com/oncletom/crx/pull/71) Remove the manifest data from cache on crx.load() (@binhqx)
- [#75](https://github.com/oncletom/crx/pull/75) [Snyk Update] New fixes for 1 vulnerable dependency path (@snyk-bot)
### v3.2.1 (2016/10/13 13:13 +00:00)
- [#67](https://github.com/oncletom/crx/pull/67) Drop iojs from package.engines (@dsblv)

@@ -5,0 +16,0 @@

@@ -5,3 +5,3 @@ {

"description": "crx is a utility to package Google Chrome extensions via a Node API and the command line",
"version": "3.2.1",
"version": "4.0.0",
"license": "MIT",

@@ -18,6 +18,7 @@ "homepage": "https://github.com/oncletom/crx",

"engines": {
"node": ">=0.10"
"node": ">=10"
},
"scripts": {
"test": "nyc tape ./test/*.js",
"posttest": "eslint src/*.js bin/crx.js",
"version": "npm run changelog && git add CHANGELOG.md",

@@ -37,13 +38,13 @@ "changelog": "github-changes -o oncletom -r crx -n ${npm_package_version} --only-pulls --use-commit-body"

"dependencies": {
"archiver": "^1.1.0",
"commander": "^2.5.0",
"es6-promise": "^3.0.0",
"node-rsa": "^0.2.10"
"archiver": "^3.0.0",
"commander": "^2.19.0",
"node-rsa": "^1.0.3"
},
"devDependencies": {
"adm-zip": "^0.4.7",
"adm-zip": "^0.4.13",
"eslint": "^5.13.0",
"github-changes": "^1.0.0",
"nyc": "^8.3.0",
"tape": "^4.6.0"
"nyc": "^13.1.0",
"tape": "^4.9.2"
}
}

@@ -1,2 +0,2 @@

# crx [![Build Status](https://secure.travis-ci.org/oncletom/crx.svg)](http://travis-ci.org/oncletom/crx)
# crx [![Build Status](https://secure.travis-ci.org/oncletom/crx.svg)](http://travis-ci.org/oncletom/crx) [![Build status](https://ci.appveyor.com/api/projects/status/i8v95qmgwwxic5wn?svg=true)](https://ci.appveyor.com/project/oncletom/crx)

@@ -13,3 +13,3 @@ > crx is a utility to **package Google Chrome extensions** via a *Node API* and the *command line*. It is written **purely in JavaScript** and **does not require OpenSSL**!

**Compatibility**: this extension is compatible with `node>=0.10`.
**Compatibility**: this extension is compatible with `node>=10`.

@@ -24,13 +24,16 @@ ## Install

Asynchronous functions returns an [ES6 Promise](https://github.com/jakearchibald/es6-promise).
Asynchronous functions returns a native ECMAScript Promise.
```js
const fs = require("fs");
const ChromeExtension = require("crx");
const crx = new ChromeExtension(
codebase: "http://localhost:8000/myFirstExtension.crx",
privateKey: fs.readFileSync("./key.pem"))
const fs = require('fs');
const path = require('path');
const ChromeExtension = require('crx');
const crx = new ChromeExtension({
codebase: 'http://localhost:8000/myExtension.crx',
privateKey: fs.readFileSync('./key.pem')
});
crx.load("./myFirstExtension"))
crx.load( path.resolve(__dirname, './myExtension') )
.then(crx => crx.pack())

@@ -40,4 +43,7 @@ .then(crxBuffer => {

fs.writeFile("../update.xml"), updateXML);
fs.writeFile("../myFirstExtension.crx"), crxBuffer);
fs.writeFile('../update.xml', updateXML);
fs.writeFile('../myExtension.crx', crxBuffer);
})
.catch(err=>{
console.error( err );
});

@@ -117,3 +123,3 @@ ```

### crx -h
### crx --help

@@ -180,24 +186,4 @@ Show information about using this utility, generated by [commander](https://github.com/visionmedia/commander.js).

Copyright
---------
# License
Copyright (c) 2016 Jed Schmidt, Thomas Parisot and collaborators
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
[MIT License](LICENSE).

@@ -1,3 +0,2 @@

/* global require, process, Buffer, module */
'use strict';
"use strict";

@@ -10,39 +9,22 @@ var fs = require("fs");

var archiver = require("archiver");
var Promise = require("es6-promise").Promise;
var resolve = require("./resolver.js");
function ChromeExtension(attrs) {
if ((this instanceof ChromeExtension) !== true) {
return new ChromeExtension(attrs);
}
const DEFAULTS = {
appId: null,
rootDirectory: "",
publicKey: null,
privateKey: null,
codebase: null,
path: null,
src: "**",
};
/*
Defaults
*/
this.appId = null;
class ChromeExtension {
constructor(attrs) {
// Setup defaults
Object.assign(this, DEFAULTS, attrs);
this.rootDirectory = '';
this.publicKey = null;
this.privateKey = null;
this.codebase = null;
this.path = null;
this.src = '**';
/*
Copying attributes
*/
for (var name in attrs) {
this[name] = attrs[name];
this.loaded = false;
}
this.loaded = false;
}
ChromeExtension.prototype = {
/**

@@ -60,3 +42,3 @@ * Packs the content of the extension in a crx file.

*/
pack: function (contentsBuffer) {
pack (contentsBuffer) {
if (!this.loaded) {

@@ -72,3 +54,3 @@ return this.load().then(this.pack.bind(this, contentsBuffer));

return Promise.all(packP).then(function(outputs){
return Promise.all(packP).then(function(outputs) {
var publicKey = outputs[0];

@@ -83,3 +65,3 @@ var contents = outputs[1];

});
},
}

@@ -92,17 +74,19 @@ /**

*/
load: function (path) {
load (path) {
var selfie = this;
return resolve(path || selfie.rootDirectory)
.then(function(metadata){
selfie.path = metadata.path;
selfie.src = metadata.src;
return resolve(path || selfie.rootDirectory).then(function(metadata) {
selfie.path = metadata.path;
selfie.src = metadata.src;
selfie.manifest = require(join(selfie.path, "manifest.json"));
selfie.loaded = true;
var manifestPath = join(selfie.path, "manifest.json");
delete require.cache[manifestPath];
return selfie;
});
},
selfie.manifest = require(manifestPath);
selfie.loaded = true;
return selfie;
});
}
/**

@@ -116,8 +100,8 @@ * Writes data into the extension workable directory.

*/
writeFile: function (path, data) {
writeFile (path, data) {
var absPath = join(this.path, path);
/* istanbul ignore next */
return new Promise(function(resolve, reject){
fs.writeFile(absPath, data, function (err) {
return new Promise(function(resolve, reject) {
fs.writeFile(absPath, data, function(err) {
if (err) {

@@ -130,3 +114,3 @@ return reject(err);

});
},
}

@@ -146,8 +130,10 @@ /**

*/
generatePublicKey: function () {
generatePublicKey () {
var privateKey = this.privateKey;
return new Promise(function(resolve, reject){
return new Promise(function(resolve, reject) {
if (!privateKey) {
return reject('Impossible to generate a public key: privateKey option has not been defined or is empty.');
return reject(
"Impossible to generate a public key: privateKey option has not been defined or is empty."
);
}

@@ -157,5 +143,5 @@

resolve(key.exportKey('pkcs8-public-der'));
resolve(key.exportKey("pkcs8-public-der"));
});
},
}

@@ -170,4 +156,4 @@ /**

*/
generateSignature: function (contents) {
return new Buffer(
generateSignature (contents) {
return Buffer.from(
crypto

@@ -179,3 +165,3 @@ .createSign("sha1")

);
},
}

@@ -188,14 +174,16 @@ /**

*/
loadContents: function () {
loadContents () {
var selfie = this;
return new Promise(function(resolve, reject){
var archive = archiver('zip');
var contents = new Buffer('');
return new Promise(function(resolve, reject) {
var archive = archiver("zip");
var contents = Buffer.from("");
if (!selfie.loaded) {
throw new Error('crx.load needs to be called first in order to prepare the workspace.');
throw new Error(
"crx.load needs to be called first in order to prepare the workspace."
);
}
archive.on('error', reject);
archive.on("error", reject);

@@ -209,7 +197,7 @@ /*

*/
archive.on('data', function (buf) {
archive.on("data", function(buf) {
contents = Buffer.concat([contents, buf]);
});
archive.on('finish', function () {
archive.on("finish", function() {
resolve(contents);

@@ -222,7 +210,7 @@ });

matchBase: true,
ignore: ['*.pem', '.git', '*.crx']
ignore: ["*.pem", ".git", "*.crx"]
})
.finalize();
});
},
}

@@ -239,3 +227,3 @@ /**

*/
generatePackage: function (signature, publicKey, contents) {
generatePackage (signature, publicKey, contents) {
var keyLength = publicKey.length;

@@ -246,3 +234,3 @@ var sigLength = signature.length;

var crx = new Buffer(length);
var crx = Buffer.alloc(length);

@@ -260,3 +248,3 @@ crx.write("Cr24" + new Array(13).join("\x00"), "binary");

return crx;
},
}

@@ -273,16 +261,32 @@ /**

*/
generateAppId: function (publicKey) {
publicKey = publicKey || this.publicKey;
if (typeof publicKey !== 'string' && !(publicKey instanceof Buffer)) {
throw new Error('Public key is neither set, nor given');
generateAppId (keyOrPath) {
keyOrPath = keyOrPath || this.publicKey;
if (typeof keyOrPath !== "string" && !(keyOrPath instanceof Buffer)) {
throw new Error("Public key is neither set, nor given");
}
// Handling Windows Path
// Possibly to be moved in a different method
if (typeof keyOrPath === "string") {
var charCode = keyOrPath.charCodeAt(0);
// 65 (A) < charCode < 122 (z)
if (charCode >= 65 && charCode <= 122 && keyOrPath[1] === ":") {
keyOrPath = keyOrPath[0].toUpperCase() + keyOrPath.slice(1);
keyOrPath = Buffer.from(keyOrPath, "utf-16le");
}
}
return crypto
.createHash("sha256")
.update(publicKey)
.digest("hex")
.slice(0, 32)
.replace(/./g, function (x) {
return (parseInt(x, 16) + 10).toString(26);
});
},
.update(keyOrPath)
.digest()
.toString("hex")
.split("")
.map(x => (parseInt(x, 16) + 0x0a).toString(26))
.join("")
.slice(0, 32);
}

@@ -296,3 +300,3 @@ /**

*/
generateUpdateXML: function () {
generateUpdateXML () {
if (!this.codebase) {

@@ -302,13 +306,11 @@ throw new Error("No URL provided for update.xml.");

return new Buffer(
"<?xml version='1.0' encoding='UTF-8'?>\n" +
"<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>\n" +
" <app appid='" + (this.appId || this.generateAppId()) + "'>\n" +
" <updatecheck codebase='" + this.codebase + "' version='" + this.manifest.version + "' />\n" +
" </app>\n" +
"</gupdate>"
);
return Buffer.from(`<?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
<app appid='${this.appId || this.generateAppId()}'>
<updatecheck codebase='${this.codebase}' version='${this.manifest.version}' />
</app>
</gupdate>`);
}
};
}
module.exports = ChromeExtension;

@@ -1,14 +0,12 @@

'use strict';
"use strict";
var path = require("path");
var join = path.join;
var Promise = require("es6-promise").Promise;
module.exports = function resolve(pathOrFiles) {
return new Promise(function(resolve, reject){
return new Promise(function(resolve, reject) {
// legacy and original mode
if (typeof pathOrFiles === 'string') {
if (typeof pathOrFiles === "string") {
return resolve({
path: pathOrFiles,
src: '**',
src: "**"
});

@@ -19,5 +17,5 @@ }

else if (Array.isArray(pathOrFiles)) {
var manifestFile = '';
var manifestFile = "";
pathOrFiles.some(function(f){
pathOrFiles.some(function(f) {
if (/(^|\/)manifest.json$/.test(f)) {

@@ -30,3 +28,5 @@ manifestFile = f;

if (!manifestFile) {
return reject(new Error('Unable to locate a manifest file in your list of files.'))
return reject(
new Error("Unable to locate a manifest file in your list of files.")
);
}

@@ -38,6 +38,11 @@

path: path.resolve(manifestDir),
src: '{' + pathOrFiles.map(function(f){
return path.relative(manifestDir, f);
}).join(',') + '}'
})
src:
"{" +
pathOrFiles
.map(function(f) {
return path.relative(manifestDir, f);
})
.join(",") +
"}"
});
}

@@ -47,5 +52,9 @@

else {
reject(new Error('load path is none of a folder location nor a list of files to pack'))
reject(
new Error(
"load path is none of a folder location nor a list of files to pack"
)
);
}
});
}
};
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc