node-cipher
Advanced tools
Comparing version 4.0.1 to 4.1.0
@@ -15,11 +15,18 @@ /** | ||
let crypto = require('crypto'); | ||
let fs = require('fs'); | ||
let debug = require('debug'); | ||
let fse = require('fs-extra'); | ||
let validate = require('validate'); | ||
/** | ||
* Helper function that performs no operation. | ||
* Configure debuggers. | ||
*/ | ||
function noop() {} | ||
let debugEncrypt = require('debug')('nodecipher:encrypt'); | ||
let debugDecrypt = require('debug')('nodecipher:decrypt'); | ||
/** | ||
* Get all valid ciphers. | ||
*/ | ||
let ciphers = crypto.getCiphers(); | ||
/** | ||
* @class NodeCipher | ||
@@ -34,67 +41,39 @@ */ | ||
*/ | ||
constructor() { | ||
constructor() {} | ||
/** | ||
* @prop {Array} _algorithms | ||
* @private | ||
*/ | ||
this._algorithms = crypto.getCiphers(); | ||
} | ||
/** | ||
* Parse the options provided and fill in any missing options with default | ||
* values. | ||
* Encrypt a file using the options provided. | ||
* | ||
* @see _encryptOrDecrypt | ||
* @param {Object} options | ||
* @returns {Object} opts | ||
* @param {Function} [callback] | ||
* @param {Object} [scope] | ||
* @private | ||
*/ | ||
_parseOptions(options) { | ||
return _.defaults(options, NodeCipher.Defaults); | ||
} | ||
_encrypt(options, callback, scope) { | ||
debugEncrypt('encrypt with options ' + JSON.stringify(options)); | ||
/** | ||
* Validates that all NodeCipher options follow the proper schema. | ||
* | ||
* @param {Object} options | ||
* @returns {Array} errors | ||
* @private | ||
*/ | ||
_validateOptions(options) { | ||
let errors = NodeCipher.OptionsSchema.validate(options); | ||
// Verify that the chosen algorithm is valid. | ||
if (!_.includes(this._algorithms, options.algorithm)) { | ||
errors.push({ | ||
path: 'algorithm', | ||
message: `"${options.algorithm}" is not a valid cipher algorithm.` | ||
}); | ||
} | ||
return errors; | ||
this._encryptOrDecrypt(options, crypto.createCipher, err => { | ||
if (_.isFunction(callback)) { | ||
callback.call(scope, err); | ||
} | ||
}); | ||
} | ||
/** | ||
* Encrypt using the options provided. | ||
* Decrypt a file using the options provided. | ||
* | ||
* @see _xcrypt | ||
* @see _encryptOrDecrypt | ||
* @param {Object} options | ||
* @param {Function} [callback=noop] | ||
* @param {Object} [scope=null] | ||
* @param {Function} [callback] | ||
* @param {Object} [scope] | ||
* @private | ||
*/ | ||
_encrypt(options, callback, scope) { | ||
callback = !_.isUndefined(callback) ? callback : noop; | ||
scope = !_.isUndefined(scope) ? scope : null; | ||
_decrypt(options, callback, scope) { | ||
debugDecrypt('decrypt with options ' + JSON.stringify(options)); | ||
let opts = this._parseOptions(options); | ||
let errors = this._validateOptions(opts); | ||
// Return errors back to the user and exit early. | ||
if (errors.length) { | ||
return callback.call(scope, new Error(errors[0].message)); | ||
} | ||
this._xcrypt(options, NodeCipher.Methods.CIPHER, err => { | ||
callback.call(scope, err); | ||
this._encryptOrDecrypt(options, crypto.createDecipher, err => { | ||
if (_.isFunction(callback)) { | ||
callback.call(scope, err); | ||
} | ||
}); | ||
@@ -104,30 +83,26 @@ } | ||
/** | ||
* Decrypt using the options provided. | ||
* Parses the encryption or decryption request to verify that all the options | ||
* are valid and there are no errors. | ||
* | ||
* @see _xcrypt | ||
* @see _cipher | ||
* @param {Object} options | ||
* @param {Function} [callback=noop] | ||
* @param {Object} [scope=null] | ||
* @param {Crypto.<Cipher|Decipher>} method | ||
* @param {Function} [done] | ||
* @private | ||
*/ | ||
_decrypt(options, callback, scope) { | ||
callback = !_.isUndefined(callback) ? callback : noop; | ||
scope = !_.isUndefined(scope) ? scope : null; | ||
_encryptOrDecrypt(options, method, done) { | ||
let opts = this._parseOptions(options); | ||
let errors = this._validateOptions(opts); | ||
// Return errors back to the user and exit early. | ||
if (errors.length) { | ||
return callback.call(scope, new Error(errors[0].message)); | ||
let err = new Error(errors[0].message); | ||
done(err); | ||
} else { | ||
this._cipher(options, method, done); | ||
} | ||
this._xcrypt(options, NodeCipher.Methods.DECIPHER, err => { | ||
callback.call(scope, err); | ||
}); | ||
} | ||
/** | ||
* Perfom the appropriate encryption or decryption method with the given | ||
* options. We define this ambiguity as "xcryption". | ||
* Cipher the file using the options provided with the given cipher method. | ||
* | ||
@@ -139,5 +114,6 @@ * @param {Object} options | ||
*/ | ||
_xcrypt(options, method, done) { | ||
let readStream = fs.createReadStream(options.input); | ||
let writeStream = fs.createWriteStream(options.output); | ||
_cipher(options, method, done) { | ||
let readStream = fse.createReadStream(options.input); | ||
let writeStream = fse.createOutputStream(options.output); | ||
let handleError = this._handleStreamError(readStream, done); | ||
let cipher = method(options.algorithm, options.password); | ||
@@ -153,12 +129,8 @@ | ||
// our writable output stream. | ||
readStream.on('error', err => { | ||
readStream.unpipe(); | ||
done(err); | ||
}).pipe(cipher).on('error', err => { | ||
readStream.unpipe(); | ||
done(err); | ||
}).pipe(writeStream).on('error', err => { | ||
readStream.unpipe(); | ||
done(err); | ||
}); | ||
readStream | ||
.on('error', handleError) | ||
.pipe(cipher) | ||
.on('error', handleError) | ||
.pipe(writeStream) | ||
.on('error', handleError); | ||
} | ||
@@ -169,3 +141,3 @@ | ||
* | ||
* @see _xcryptSync | ||
* @see _encryptOrDecryptSync | ||
* @param {Object} options | ||
@@ -175,11 +147,5 @@ * @private | ||
_encryptSync(options) { | ||
let opts = this._parseOptions(options); | ||
let errors = this._validateOptions(opts); | ||
debugEncrypt('synch encrypt with options ' + JSON.stringify(options)); | ||
// Handle errors. | ||
if (errors.length) { | ||
throw new Error(errors[0].message); | ||
} | ||
this._xcryptSync(opts, NodeCipher.Methods.CIPHER); | ||
this._encryptOrDecryptSync(options, crypto.createCipher); | ||
} | ||
@@ -190,3 +156,3 @@ | ||
* | ||
* @see _xcryptSync | ||
* @see _encryptOrDecryptSync | ||
* @param {Object} options | ||
@@ -196,15 +162,28 @@ * @private | ||
_decryptSync(options) { | ||
debugDecrypt('synch decrypt with options ' + JSON.stringify(options)); | ||
this._encryptOrDecryptSync(options, crypto.createDecipher); | ||
} | ||
/** | ||
* The synchronous version of _encryptOrDecrypt(). | ||
* | ||
* @see _cipherSync | ||
* @param {Object} options | ||
* @param {Crypto.<Cipher|Decipher>} method | ||
* @private | ||
*/ | ||
_encryptOrDecryptSync(options, method) { | ||
let opts = this._parseOptions(options); | ||
let errors = this._validateOptions(opts); | ||
// Handle errors. | ||
if (errors.length) { | ||
throw new Error(errors[0].message); | ||
} else { | ||
this._cipherSync(opts, method); | ||
} | ||
this._xcryptSync(opts, NodeCipher.Methods.DECIPHER); | ||
} | ||
/** | ||
* The synchronous version of _xcrypt(). | ||
* The synchronous version of _cipher(). | ||
* | ||
@@ -215,9 +194,9 @@ * @param {Object} options | ||
*/ | ||
_xcryptSync(options, method) { | ||
_cipherSync(options, method) { | ||
try { | ||
let inputBuffer = fs.readFileSync(options.input); | ||
let inputBuffer = fse.readFileSync(options.input); | ||
let cipher = method(options.algorithm, options.password); | ||
// Write the ciphered buffer to our output file. | ||
fs.writeFileSync(options.output, Buffer.concat([ | ||
fse.writeFileSync(options.output, Buffer.concat([ | ||
cipher.update(inputBuffer), | ||
@@ -232,4 +211,53 @@ cipher.final() | ||
/** | ||
* Public method for encrypting using the options provided. | ||
* Parse the options provided and fill in any missing options with default | ||
* values. | ||
* | ||
* @param {Object} options | ||
* @returns {Object} opts | ||
* @private | ||
*/ | ||
_parseOptions(options) { | ||
return _.defaults(options, NodeCipher.Defaults); | ||
} | ||
/** | ||
* Validates that all NodeCipher options follow the proper schema. | ||
* | ||
* @param {Object} options | ||
* @returns {Array} errors | ||
* @private | ||
*/ | ||
_validateOptions(options) { | ||
let errors = NodeCipher.OptionsSchema.validate(options); | ||
// Verify that the chosen algorithm is valid. | ||
if (!_.includes(ciphers, options.algorithm)) { | ||
errors.push({ | ||
path: 'algorithm', | ||
message: `"${options.algorithm}" is not a valid cipher algorithm.` | ||
}); | ||
} | ||
return errors; | ||
} | ||
/** | ||
* Handles read stream errors. The returned closure unpipes the stream then | ||
* calls the callback with the error. | ||
* | ||
* @param {Stream} stream | ||
* @param {Function} callback | ||
* @returns {Function} | ||
* @private | ||
*/ | ||
_handleStreamError(stream, callback) { | ||
return function (err) { | ||
stream.unpipe(); | ||
callback(err); | ||
}; | ||
} | ||
/** | ||
* Public method for encrypting a file using the options provided. | ||
* | ||
* @see _encrypt | ||
@@ -242,7 +270,7 @@ * @param {Object} options | ||
encrypt(options, callback, scope) { | ||
this._encrypt(options, callback, scope); | ||
this._encrypt.apply(this, arguments); | ||
} | ||
/** | ||
* Public method for decrypting using the options provided. | ||
* Public method for decrypting a file using the options provided. | ||
* | ||
@@ -256,3 +284,3 @@ * @see _decrypt | ||
decrypt(options, callback, scope) { | ||
this._decrypt(options, callback, scope); | ||
this._decrypt.apply(this, arguments); | ||
} | ||
@@ -268,3 +296,3 @@ | ||
encryptSync(options) { | ||
this._encryptSync(options); | ||
this._encryptSync.apply(this, arguments); | ||
} | ||
@@ -280,3 +308,3 @@ | ||
decryptSync(options) { | ||
this._decryptSync(options); | ||
this._decryptSync.apply(this, arguments); | ||
} | ||
@@ -291,3 +319,3 @@ | ||
list() { | ||
return this._algorithms; | ||
return ciphers; | ||
} | ||
@@ -317,10 +345,2 @@ | ||
/** | ||
* @enum {Object} Methods | ||
*/ | ||
NodeCipher.Methods = { | ||
CIPHER: crypto.createCipher, | ||
DECIPHER: crypto.createDecipher | ||
}; | ||
/** | ||
* @enum {Object} OptionsSchema | ||
@@ -327,0 +347,0 @@ */ |
{ | ||
"name": "node-cipher", | ||
"version": "4.0.1", | ||
"version": "4.1.0", | ||
"description": "Securely encrypt sensitive files for use in public source control.", | ||
@@ -31,2 +31,4 @@ "main": "index.js", | ||
"dependencies": { | ||
"debug": "^2.2.0", | ||
"fs-extra": "^0.26.4", | ||
"lodash": "^4.0.0", | ||
@@ -38,4 +40,5 @@ "validate": "^3.0.1" | ||
"mocha": "^2.3.4", | ||
"randomstring": "^1.1.3", | ||
"tmp": "0.0.28" | ||
} | ||
} |
126
README.md
@@ -1,2 +0,2 @@ | ||
node-cipher | ||
node-cipher [![Build Status](https://travis-ci.org/nathanbuchar/node-cipher.svg?branch=master)](https://travis-ci.org/nathanbuchar/node-cipher) | ||
=========== | ||
@@ -6,13 +6,14 @@ | ||
Looking for the command line tool? [Click here](http://github.com/nathanbuchar/node-cipher-cli). | ||
**Why should I use node-cipher?** | ||
Let's say you have a file in your project name `config.json` which contains sensitive information like private keys and database passwords. What should you do if you need to publicly host a repository containing this file? Certainly you wouldn't want to make the contents of `config.json` visible to the outside world. | ||
**Why would I want to encrypt my files?** | ||
You *could* remove the file from source control, and send the file to everyone in your team every time you update the file. But this is pretty cumbersome. Or, you can use node-cipher to encrypt the file and add the encrypted version to source control. This can later be decrypted by each team member independently with a password that you provide. Every time you or one of your team members makes a change to `config.json`, just re-encrypt the file and commit. It's that easy! | ||
Let's say you have a file in your project name `config.json` which contains sensitive information like private keys and database passwords. | ||
Don't forget to add the original `config.json` file to `.gitignore`! | ||
What happens if you want to publicly host a repository containing this file? Certainly you wouldn't want to make the contents of `config.json` visible to the outside world, so instead you can use **node-cipher** to encrypt the file and add its encrypted counterpart to source control, which can later be decrypted using the encryption key when the repository is cloned. | ||
Just don't forget to add the original `config.json` file to `.gitignore`! | ||
*** | ||
**:exclamation: If you're looking for the node-cipher command line tool, it has moved to [node-cipher-cli](http://github.com/nathanbuchar/node-cipher-cli).** | ||
@@ -35,4 +36,4 @@ *** | ||
|:---|:--:|:----------|:------:|:-----:| | ||
|`input`|`string`|The input file.|✓|| | ||
|`output`|`string`|The output file.|✓|| | ||
|`input`|`string`|The file that you wish to encrypt or decrypt.|✓|| | ||
|`output`|`string`|The file that you wish to save the encrypted or decrypted contents to. This file does not necessarily need to exist.|✓|| | ||
|`password`|`string`|The key that you will use to encrypt or decrypt your input file. If you are decrypting a file, the password must be the same as the one specified during encryption, or else the decryption will fail.|✓|| | ||
@@ -45,24 +46,26 @@ |`algorithm`|`string`|The cipher algorithm to use. Use [`list()`](#listarray) to see a list of available cipher algorithms.||`"cast5-cbc"`| | ||
* [`encrypt()`](#encryptoptions-callback-scope) | ||
* [`encryptSync()`](#encryptsyncoptions-callback-scope) | ||
* [`decrypt()`](#decryptoptions-callback-scope) | ||
* [`decryptSync()`](#decryptsyncoptions-callback-scope) | ||
* [`list()`](#listarray) | ||
* [`encrypt()`](#encrypt) | ||
* [`encryptSync()`](#encryptsync) | ||
* [`decrypt()`](#decrypt) | ||
* [`decryptSync()`](#decryptsync) | ||
* [`list()`](#list) | ||
*** | ||
### `encrypt(options[, callback[, scope]])` | ||
### encrypt() | ||
Encrypts a file using the [options](#options) provided. | ||
##### `encrypt(options[, callback[, scope]])` | ||
Encrypts a file using the [options](#options) provided. Returns `undefined`. | ||
#### Parameters | ||
|Parameter|Type|Description|Required|Default| | ||
|--------:|:--:|:----------|:------:|:-----:| | ||
|`options`|`Object`|See [options](#options).|✓|| | ||
|`callback`|`Function`|The function to call when the encryption has completed.||| | ||
|`scope`|`Object`|The Function scope for the `callback` parameter, if provided.||`null`| | ||
|Parameter|Type|Description|Required| | ||
|--------:|:--:|:----------|:------:| | ||
|`options`|`Object`|See [options](#options).|✓| | ||
|`callback`|`Function`|The function to call when the encryption has completed.|| | ||
|`scope`|`Object`|The Function scope for the `callback` parameter, if provided.|| | ||
#### Example | ||
Encrypts `config.json` into `config.encrypted.json` using the password `"b0sco"`. | ||
Encrypts `config.json` into `config.json.cast5` using the password `"passw0rd"`. | ||
@@ -74,4 +77,4 @@ ```js | ||
input: 'config.json', | ||
output: 'config.encrypted.json', | ||
password: 'b0sco' | ||
output: 'config.json.cast5', | ||
password: 'passw0rd' | ||
}, function (err) { | ||
@@ -86,14 +89,16 @@ if (err) throw err; | ||
### `encryptSync(options)` | ||
### encryptSync() | ||
The synchronous version of [`encrypt()`](#encryptoptions-callback-scope). | ||
##### `encryptSync(options)` | ||
The synchronous version of [`encrypt()`](#encrypt). Returns `undefined`. | ||
#### Parameters | ||
|Parameter|Type|Description|Required|Default| | ||
|--------:|:--:|:----------|:------:|:-----:| | ||
|`options`|`Object`|See [options](#options).|✓|| | ||
|Parameter|Type|Description|Required| | ||
|--------:|:--:|:----------|:------:| | ||
|`options`|`Object`|See [options](#options).|✓| | ||
#### Example | ||
Synchronously encrypts `config.json` into `config.encrypted.json` using the password `"b0sco"`. | ||
Synchronously encrypts `config.json` into `config.json.cast5` using the password `"passw0rd"`. | ||
@@ -105,4 +110,4 @@ ```js | ||
input: 'config.json', | ||
output: 'config.encrypted.json', | ||
password: 'b0sco' | ||
output: 'config.json.cast5', | ||
password: 'passw0rd' | ||
}); | ||
@@ -113,6 +118,8 @@ ``` | ||
### `decrypt(options[, callback[, scope]])` | ||
### decrypt() | ||
Decrypts a file using the [options](#options) provided. | ||
##### `decrypt(options[, callback[, scope]])` | ||
Decrypts a file using the [options](#options) provided. Returns `undefined`. | ||
#### Parameters | ||
@@ -123,7 +130,7 @@ |Parameter|Type|Description|Required| | ||
|`callback`|`Function`|The function to call when the decryption has completed.|| | ||
|`scope`|`Object`|The Function scope for the `callback` parameter, if provided.||`null`| | ||
|`scope`|`Object`|The Function scope for the `callback` parameter, if provided.|| | ||
#### Example | ||
Decrypts `config.encrypted.json` back into `config.json` using the password `"b0sco"`. | ||
Decrypts `config.json.cast5` back into `config.json` using the password `"passw0rd"`. | ||
@@ -134,9 +141,9 @@ ```js | ||
nodecipher.decrypt({ | ||
input: 'config.encrypted.json', | ||
input: 'config.json.cast5', | ||
output: 'config.json', | ||
password: 'b0sco' | ||
password: 'passw0rd' | ||
}, function (err) { | ||
if (err) throw err; | ||
console.log('config.encrypted.json decrypted.'); | ||
console.log('config.json.cast5 decrypted.'); | ||
}); | ||
@@ -147,14 +154,16 @@ ``` | ||
### `decryptSync(options)` | ||
### decryptSync() | ||
The synchronous version of [`decrypt()`](#decryptoptions-callback-scope). | ||
##### `decryptSync(options)` | ||
The synchronous version of [`decrypt()`](#decrypt). Returns `undefined`. | ||
#### Parameters | ||
|Parameter|Type|Description|Required|Default| | ||
|--------:|:--:|:----------|:------:|:-----:| | ||
|`options`|`Object`|See [options](#options).|✓|| | ||
|Parameter|Type|Description|Required| | ||
|--------:|:--:|:----------|:------:| | ||
|`options`|`Object`|See [options](#options).|✓| | ||
#### Example | ||
Synchronously decrypts `config.encrypted.json` back into `config.json` using the password `"b0sco"`. | ||
Synchronously decrypts `config.json.cast5` back into `config.json` using the password `"passw0rd"`. | ||
@@ -165,5 +174,5 @@ ```js | ||
nodecipher.decryptSync({ | ||
input: 'config.encrypted.json', | ||
input: 'config.json.cast5', | ||
output: 'config.json', | ||
password: 'b0sco' | ||
password: 'passw0rd' | ||
}); | ||
@@ -174,6 +183,8 @@ ``` | ||
### `list():Array` | ||
### list() | ||
Lists all available cipher algorithms as an Array. | ||
##### `list():Array` | ||
Lists all available cipher algorithms as an Array. Returns `Array`. | ||
#### Example | ||
@@ -192,2 +203,21 @@ | ||
Debug | ||
----- | ||
Node-cipher implements [debug](https://github.com/visionmedia/debug) for development logging. To set up node-cipher with debug, set the following environment variables: | ||
**Mac OS:** | ||
```bash | ||
$ export DEBUG=nodecipher:* | ||
``` | ||
**Windows:** | ||
```bash | ||
$ set DEBUG=nodecipher:* | ||
``` | ||
*** | ||
Authors | ||
@@ -194,0 +224,0 @@ ------- |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
15673
317
218
4
4
+ Addeddebug@^2.2.0
+ Addedfs-extra@^0.26.4
+ Addedbalanced-match@1.0.2(transitive)
+ Addedbrace-expansion@1.1.11(transitive)
+ Addedconcat-map@0.0.1(transitive)
+ Addeddebug@2.6.9(transitive)
+ Addedfs-extra@0.26.7(transitive)
+ Addedfs.realpath@1.0.0(transitive)
+ Addedglob@7.2.3(transitive)
+ Addedgraceful-fs@4.2.11(transitive)
+ Addedinflight@1.0.6(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedjsonfile@2.4.0(transitive)
+ Addedklaw@1.3.1(transitive)
+ Addedminimatch@3.1.2(transitive)
+ Addedms@2.0.0(transitive)
+ Addedonce@1.4.0(transitive)
+ Addedpath-is-absolute@1.0.1(transitive)
+ Addedrimraf@2.7.1(transitive)
+ Addedwrappy@1.0.2(transitive)