Socket
Socket
Sign inDemoInstall

yaml-crypt

Package Overview
Dependencies
Maintainers
1
Versions
37
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

yaml-crypt - npm Package Compare versions

Comparing version 0.2.0 to 0.3.0

433

bin/yaml-crypt-cli.js

@@ -119,12 +119,15 @@ #!/usr/bin/env node

});
parser.addArgument(['-k', '--key'], {
action: 'append',
metavar: '<key-file>',
help: 'Read a key from the given file path. Can be given multiple times to automatically select a matching decryption key'
parser.addArgument(['--generate-key'], {
action: 'storeTrue',
help: 'Generate a new random key. Use -a to specify the algorithm'
});
parser.addArgument(['--key-fd'], {
parser.addArgument(['-k'], {
action: 'append',
metavar: '<key-fd>',
help: 'Read a key from the given file descriptor. Can be given multiple times'
metavar: '<key>',
help: 'Use the given key to decrypt data. Can be given multiple times. See section "Key sources" for details'
});
parser.addArgument(['-K'], {
metavar: '<key>',
help: 'Use the given key to encrypt data. See section "Key sources" for details'
});
parser.addArgument(['-a', '--algorithm'], {

@@ -154,5 +157,5 @@ metavar: '<algorithm>',

});
parser.addArgument(['--rm'], {
parser.addArgument(['--keep'], {
action: 'storeTrue',
help: 'Delete original files after encryption/decryption. Use with caution!'
help: 'Keep the original files after encryption/decryption'
});

@@ -164,2 +167,38 @@ parser.addArgument(['file'], {

});
if (process.argv && process.argv.includes('--help')) {
parser.addArgumentGroup({
title: 'Configuration file',
description: 'During startup, yaml-crypt will look for a configuration file '
+ '"config.yaml" or "config.yml" in the folder "$HOME/.yaml-crypt" and read keys from '
+ 'the array "keys". Each key is expected to be an object with the required '
+ 'attribute "key" which contains the raw key data and an optional attribute '
+ '"name" with a custom name for that key.'
});
parser.addArgumentGroup({
title: 'Key sources',
description: 'Keys can be provided from multiple sources: configuration file, environment variables, key files and file descriptors. '
+ 'When no explicit specifier is given, any arguments will be treated as key files. To select a specific source, '
+ 'specify "c:" or "config:" for configuration file, "e:" or "env:" for environment variables, "fd:" for file descriptors and "f:" for files. '
+ 'For example, "yaml-crypt -k c:my-key -k e:MY_KEY -k fd:0 -k f:my.key" will read the key named "my-key" from '
+ 'the configuration file, read a key from the environment variable "MY_KEY", read another key from file descriptor 0 (stdin) and another key from '
+ 'the local file "my.key".'
});
parser.addArgumentGroup({
title: 'Decryption keys',
description: 'When no keys are given, decryption keys are read from the configuration file. '
+ 'When no decryption keys are given, but an encryption key is given, that key will also be '
+ 'used for decryption. '
+ 'All provided decryption keys are tried, in order, until the data can be successfully decrypted. '
+ 'If none of the available keys matches, the operation fails.'
});
parser.addArgumentGroup({
title: 'Encryption keys',
description: 'When no encryption key is given and only one decryption key is available, that '
+ 'key will be used for encryption. When editing a file and no encryption key is given, '
+ 'the matching decryption key will be used to encrypt the modified data. '
+ 'In all other cases, an encryption key must be explicitly selected using "-K".'
});
} else {
parser.epilog = 'For more details, specify --help';
}
const args = parser.parseArgs(argv);

@@ -170,3 +209,3 @@ if (args.encrypt && args.decrypt) {

if (args.raw && args.path) {
throw new UsageError('options --raw and --path cannot be combined!');
throw new UsageError('cannot combine --raw and --path!');
}

@@ -177,16 +216,34 @@ if (args.raw && args.file.length) {

if (args.edit && args.path) {
throw new UsageError('options --edit and --path cannot be combined!');
throw new UsageError('cannot combine --edit and --path!');
}
if (args.edit && args.raw) {
throw new UsageError('options --edit and --raw cannot be combined!');
throw new UsageError('cannot combine --edit and --raw!');
}
if (args.edit && args.keep) {
throw new UsageError('cannot combine --edit and --keep!');
}
if (args.edit && args.encrypt) {
throw new UsageError('cannot combine --edit and --encrypt!');
}
if (args.edit && args.decrypt) {
throw new UsageError('cannot combine --edit and --decrypt!');
}
if (args.edit && !args.file.length) {
throw new UsageError('option --edit used, but no files given!');
}
if (!args.key && !args.key_fd && (!config.keys || !config.keys.length)) {
if (!args.generate_key && !args.k && (!config.keys || !config.keys.length)) {
throw new UsageError('no keys given and no default keys configured!');
}
if (args.rm && !args.file.length) {
throw new UsageError('option --rm used, but no files given!');
if (args.keep && !args.file.length) {
throw new UsageError('option --keep used, but no files given!');
}
if (args.generate_key && args.encrypt) {
throw new UsageError('cannot combine --generate-key and --encrypt!');
}
if (args.generate_key && args.decrypt) {
throw new UsageError('cannot combine --generate-key and --decrypt!');
}
if (args.generate_key && args.file && args.file.length) {
throw new UsageError('option --generate-key used, but files given!');
}
try {

@@ -214,45 +271,42 @@ _run(args, config, options);

}
const keys = [];
if (args.key || args.key_fd) {
if (args.key) {
keys.push(...args.key.map(key => readKey(key)));
}
if (args.key_fd) {
for (const key of args.key_fd) {
const fd = parseInt(key);
if (fd || fd === 0) {
const str = readFd(fd);
keys.push(str.trim());
} else {
throw new UsageError(`not a file descriptor: ${key}`);
}
}
}
} else if (config.keys) {
for (const obj of config.keys) {
if (obj.file && obj.key) {
throw new ConfigurationError('either file or key must be set, not both!');
} else if (obj.file) {
keys.push(readKey(obj.file));
} else if (obj.key) {
const type = typeof (obj.key);
if (type === 'string') {
keys.push(obj.key.trim());
} else if (Buffer.isBuffer(obj.key)) {
keys.push(obj.key.toString('utf8').trim());
} else {
throw new ConfigurationError(`key entry is not a string: ${type}`);
}
let input;
if (options.stdin) {
input = options.stdin;
} else {
input = process.stdin;
}
let output;
if (options.stdout) {
output = options.stdout;
} else {
output = process.stdout;
output.on('error', err => {
if (err && err.code === 'EPIPE') {
console.error('broken pipe');
} else {
throw new ConfigurationError('neither file nor key given for key entry!');
console.error('unknown I/O error!');
}
}
});
}
if (args.edit) {
const configKeys = readConfigKeys(config);
const keys = [];
if (args.k) {
keys.push(...args.k.map(k => readKey(configKeys, k)));
} else {
configKeys.forEach(k => keys.push(k.key));
}
const encryptionKey = (args.K
? readKey(configKeys, args.K)
: (keys.length === 1 ? keys[0] : null));
if (args.generate_key) {
const key = yamlcrypt.generateKey(algorithm);
output.write(key);
output.write('\n');
} else if (args.edit) {
for (const file of args.file) {
editFile(file, keys, algorithm, args, config);
editFile(file, keys, encryptionKey, algorithm, args, config);
}
} else if (args.file.length) {
for (const file of args.file) {
processFileArg(file, keys, algorithm, args);
processFileArg(file, keys, encryptionKey, algorithm, args);
}

@@ -268,51 +322,154 @@ } else {

}
if (encrypt && keys.length > 1) {
throw new UsageError(`encrypting, but more than one key given!`);
if (encrypt) {
checkEncryptionKey(keys, encryptionKey);
}
let input;
if (options.stdin) {
input = options.stdin;
} else {
input = readFd(process.stdin.fd);
}
let output;
if (options.stdout) {
output = options.stdout;
} else {
output = process.stdout;
}
const opts = { 'base64': args.base64, 'algorithm': algorithm };
if (args.raw) {
if (encrypt) {
const crypt = yamlcrypt.encrypt(keys[0], opts);
output.write(crypt.encryptRaw(input));
output.write('\n');
readInput(input, buf => {
if (args.raw) {
if (encrypt) {
const crypt = yamlcrypt.encrypt(encryptionKey, opts);
output.write(crypt.encryptRaw(buf));
output.write('\n');
} else {
const result = tryDecrypt(opts, keys, crypt => crypt.decryptRaw(buf));
output.write(result);
}
} else {
const crypt = yamlcrypt.decrypt(keys[0], opts);
let result = crypt.decryptRaw(input);
output.write(result);
let strs = [];
if (encrypt) {
const crypt = yamlcrypt.encrypt(encryptionKey, opts);
yaml.safeLoadAll(buf, obj => {
yamlcryptHelper.processStrings(obj, args.path, str => new yamlcrypt.Plaintext(str));
const encrypted = crypt.safeDump(obj);
strs.push(encrypted);
});
} else {
strs = tryDecrypt(opts, keys, crypt => {
const result = [];
crypt.safeLoadAll(buf, obj => result.push(yaml.safeDump(obj)));
return result;
});
}
for (let idx = 0; idx < strs.length; idx++) {
if (idx > 0) {
output.write('---\n');
}
output.write(strs[idx]);
}
}
});
}
}
function readInput(input, callback) {
if (typeof input === 'string' || input instanceof String || Buffer.isBuffer(input)) {
callback(input);
} else {
const ret = [];
let len = 0;
input.on('readable', () => {
let chunk;
while ((chunk = input.read())) {
ret.push(chunk);
len += chunk.length;
}
});
input.on('end', () => {
callback(Buffer.concat(ret, len));
});
}
}
function checkEncryptionKey(keys, encryptionKey) {
if (!encryptionKey) {
if (keys.length) {
throw new UsageError('encrypting, but multiple keys given! '
+ 'Use -K to explicitly specify an encryption key.');
} else {
const strs = [];
if (encrypt) {
const crypt = yamlcrypt.encrypt(keys[0], opts);
yaml.safeLoadAll(input, obj => {
yamlcryptHelper.processStrings(obj, args.path, str => new yamlcrypt.Plaintext(str));
const encrypted = crypt.safeDump(obj);
strs.push(encrypted);
});
throw new UsageError('encrypting, but no keys given!');
}
}
}
function readConfigKeys(config) {
const keys = [];
if (Array.isArray(config.keys)) {
for (const obj of config.keys) {
if (obj.key) {
let key;
const type = typeof (obj.key);
if (type === 'string') {
key = obj.key.trim();
} else if (Buffer.isBuffer(obj.key)) {
key = obj.key.toString('utf8').trim();
} else {
throw new ConfigurationError(`key entry is not a string: ${type}`);
}
const name = obj.name || '';
keys.push({ key, name });
} else {
const crypt = yamlcrypt.decrypt(keys[0], opts);
crypt.safeLoadAll(input, obj => strs.push(yaml.safeDump(obj)));
throw new ConfigurationError('attribute key missing for key entry!');
}
for (let idx = 0; idx < strs.length; idx++) {
if (idx > 0) {
output.write('---\n');
}
}
for (let i = 0; i < keys.length; i++) {
for (let j = 0; j < keys.length; j++) {
if (i !== j) {
if (keys[i].name && keys[i].name === keys[j].name) {
throw new ConfigurationError(`non-unique key name: ${keys[i].name}`);
}
output.write(strs[idx]);
}
}
}
return keys;
}
function readKey(configKeys, key) {
let prefix;
let arg;
if (key.includes(':')) {
const idx = key.indexOf(':');
prefix = key.substring(0, idx);
arg = key.substring(idx + 1);
} else {
prefix = 'f';
arg = key;
}
if (prefix === 'c' || prefix === 'config') {
for (const k of configKeys) {
if (k.name === arg) {
return k.key;
}
}
throw new UsageError(`key not found in configuration file: ${arg}`);
} else if (prefix === 'e' || prefix === 'env') {
const str = process.env[arg];
if (!str || !str.trim()) {
throw new UsageError(`no such environment variable: ${arg}`);
}
return str.trim();
} else if (prefix === 'fd') {
const fd = parseInt(arg);
if (fd || fd === 0) {
return readFd(fd).trim();
} else {
throw new UsageError(`not a file descriptor: ${arg}`);
}
} else if (prefix === 'f' || prefix === 'file') {
let raw;
try {
raw = fs.readFileSync(arg);
} catch (e) {
if (e.code === 'ENOENT') {
throw new UsageError(`key file does not exist: ${arg}`);
} else {
throw e;
}
}
return raw.toString('utf8').trim();
} else {
throw new UsageError(`unknown key argument: ${key}`);
}
}
function readFd(fd) {

@@ -331,16 +488,2 @@ var buf = Buffer.alloc(1024);

function readKey(keyFile) {
let raw;
try {
raw = fs.readFileSync(keyFile);
} catch (e) {
if (e.code === 'ENOENT') {
throw new UsageError(`key file does not exist: ${keyFile}`);
} else {
throw e;
}
}
return raw.toString('utf8').trim();
}
function plaintextFile(file) {

@@ -354,3 +497,3 @@ return file.endsWith('.yaml') || file.endsWith('.yml');

function processFileArg(file, keys, algorithm, args) {
function processFileArg(file, keys, encryptionKey, algorithm, args) {
const stat = fs.statSync(file);

@@ -369,3 +512,3 @@ if (stat.isDirectory()) {

})
.forEach(f => processFile(file + '/' + f, keys, algorithm, args));
.forEach(f => processFile(file + '/' + f, keys, encryptionKey, algorithm, args));
} else {

@@ -375,7 +518,7 @@ throw new UsageError(`directories will be skipped unless --dir given: ${file}`);

} else {
processFile(file, keys, algorithm, args);
processFile(file, keys, encryptionKey, algorithm, args);
}
}
function processFile(file, keys, algorithm, args) {
function processFile(file, keys, encryptionKey, algorithm, args) {
let encrypt;

@@ -394,4 +537,4 @@ if (plaintextFile(file)) {

}
if (encrypt && keys.length != 1) {
throw new UsageError(`encrypting file, but more than one key given!`);
if (encrypt) {
checkEncryptionKey(keys, encryptionKey);
}

@@ -415,3 +558,3 @@ let content;

if (encrypt) {
const crypt = yamlcrypt.encrypt(keys[0], opts);
const crypt = yamlcrypt.encrypt(encryptionKey, opts);
yaml.safeLoadAll(content, obj => {

@@ -423,25 +566,35 @@ yamlcryptHelper.processStrings(obj, args.path, str => new yamlcrypt.Plaintext(str));

} else {
let success = false;
for (const key of keys) {
try {
strs = [];
const crypt = yamlcrypt.decrypt(key, opts);
crypt.safeLoadAll(content, obj => strs.push(yaml.safeDump(obj)));
success = true;
break;
} catch (e) {
continue;
}
}
if (!success) {
throw new Error('No matching key to decrypt the given data!');
}
strs = tryDecrypt(opts, keys, crypt => {
const result = [];
crypt.safeLoadAll(content, obj => result.push(yaml.safeDump(obj)));
return result;
});
}
if (!args.keep) {
fs.renameSync(file, output);
}
writeYaml(strs, output);
if (args.rm) {
fs.unlinkSync(file);
}
function tryDecrypt(opts, keys, callback) {
let result = null;
let success = false;
for (const key of keys) {
try {
const crypt = yamlcrypt.decrypt(key, opts);
result = callback(crypt);
success = true;
break;
} catch (e) {
continue;
}
}
if (success) {
return result;
} else {
throw new Error('no matching key to decrypt the given data!');
}
}
function editFile(file, keys, algorithm, args, config) {
function editFile(file, keys, encryptionKey, algorithm, args, config) {
let content;

@@ -462,18 +615,24 @@ try {

const opts = { 'base64': args.base64, 'algorithm': algorithm };
const transformed = yamlcryptHelper.transform(content, keys, opts, str => {
const tmpFile = tmp.fileSync({ 'dir': dir, 'postfix': '.yaml' });
fs.writeSync(tmpFile.fd, str);
fs.closeSync(tmpFile.fd);
const tmpFile = tmp.fileSync({ 'dir': dir, 'postfix': '.yaml', 'keep': true });
try {
const opts = { 'base64': args.base64, 'algorithm': algorithm };
const transformed = yamlcryptHelper.transform(content, keys, encryptionKey, opts, str => {
fs.writeSync(tmpFile.fd, str);
fs.closeSync(tmpFile.fd);
childProcess.spawnSync(editor, [tmpFile.name], { 'stdio': 'inherit' });
childProcess.spawnSync(editor, [tmpFile.name], { 'stdio': 'inherit' });
return fs.readFileSync(tmpFile.name);
});
fs.writeFileSync(file, transformed);
return fs.readFileSync(tmpFile.name);
});
fs.writeFileSync(tmpFile.name, transformed);
fs.renameSync(tmpFile.name, file);
} finally {
if (fs.existsSync(tmpFile.name)) {
fs.unlinkSync(tmpFile.name);
}
}
}
function writeYaml(strs, file) {
const fd = fs.openSync(file, 'wx');
const fd = fs.openSync(file, 'w');
try {

@@ -480,0 +639,0 @@ for (let idx = 0; idx < strs.length; idx++) {

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

const crypto = require('crypto');
const URLSafeBase64 = require('urlsafe-base64');

@@ -11,2 +13,10 @@ const fernet = require('fernet');

/**
* Generate a new key that can be used for Fernet cryptography.
* @returns {string} Randomly generated key
*/
function fernetGenerateKey() {
return generateKey(32);
}
/**
* Encrypts the message with the given key.

@@ -41,2 +51,10 @@ * @param {string} key Key to use for encryption, must be exactly 32 bytes when encoded in UTF-8

/**
* Generates a new key that can be used for Branca cryptography.
* @returns {string} Randomly generated key
*/
function brancaGenerateKey() {
return generateKey(32);
}
/**
* Encrypts the message with the given key.

@@ -62,2 +80,8 @@ * @param {string} key Key to use for encryption, must be exactly 32 bytes when encoded in UTF-8

function generateKey(length) {
const buf = crypto.randomBytes(length);
return buf.toString('base64').substring(0, length);
}
module.exports.fernetGenerateKey = fernetGenerateKey;
module.exports.fernetEncrypt = fernetEncrypt;

@@ -67,3 +91,4 @@ module.exports.fernetDecrypt = fernetDecrypt;

module.exports.brancaDefaults = brancaDefaults;
module.exports.brancaGenerateKey = brancaGenerateKey;
module.exports.brancaEncrypt = brancaEncrypt;
module.exports.brancaDecrypt = brancaDecrypt;

@@ -46,17 +46,17 @@ const yaml = require('js-yaml');

function transform(content, keys, opts, callback) {
function transform(content, keys, encryptionKey, opts, callback) {
let key = null;
const objs = [];
let objs = [];
for (const k of keys) {
const tmp = [];
try {
const tmp = [];
const opts_ = Object.assign({ 'objects': true }, opts);
const crypt = yamlcrypt.decrypt(k, opts_);
crypt.safeLoadAll(content, obj => tmp.push(obj));
tmp.forEach(obj => objs.push(obj));
key = k;
break;
} catch (e) {
continue;
}
key = k;
objs = tmp;
break;
}

@@ -68,2 +68,4 @@

const reencrypt = (key !== encryptionKey);
let index = 0;

@@ -74,3 +76,3 @@ const types = [];

const knownText = new _KnownText(t, index++, t.algorithm);
types.push(_knownTextType(key, knownText));
types.push(_knownTextType(key, knownText, reencrypt));
return knownText;

@@ -88,3 +90,3 @@ });

const crypt = yamlcrypt.encrypt(key, opts);
const crypt = yamlcrypt.encrypt(encryptionKey, opts);
return crypt.safeDumpAll(result);

@@ -101,3 +103,3 @@ }

function _knownTextType(key, knownText) {
function _knownTextType(key, knownText, reencrypt) {
return new yaml.Type('!yaml-crypt/:' + knownText.index, {

@@ -109,3 +111,3 @@ kind: 'scalar',

construct: data => {
if (data === knownText.plaintext.plaintext) {
if (!reencrypt && data === knownText.plaintext.plaintext) {
return knownText.plaintext;

@@ -112,0 +114,0 @@ } else {

@@ -15,2 +15,15 @@ const yaml = require('js-yaml');

/**
* Generate a new key
*/
function generateKey(algorithm) {
if (!algorithm || algorithm === ALGORITHM_FERNET) {
return crypto.fernetGenerateKey();
} else if (algorithm === ALGORITHM_BRANCA) {
return crypto.brancaGenerateKey();
} else {
throw new Error(`unsupported algorithm: ${algorithm}`);
}
}
/**
* Plain text, unencrypted

@@ -163,3 +176,3 @@ */

const decrypted = decrypt(key, data);
const decoded = (base64 ? new Buffer(decrypted, 'base64').toString() : decrypted);
const decoded = (base64 ? Buffer.from(decrypted, 'base64').toString() : decrypted);
return (objects ? new Plaintext(decoded, data, algorithm) : decoded);

@@ -176,3 +189,3 @@ },

const str = data.toString();
const encoded = (base64 ? new Buffer(str).toString('base64') : str);
const encoded = (base64 ? Buffer.from(str).toString('base64') : str);
encrypted = encrypt(key, encoded);

@@ -188,2 +201,3 @@ }

module.exports.algorithms = algorithms;
module.exports.generateKey = generateKey;
module.exports.Plaintext = Plaintext;

@@ -190,0 +204,0 @@ module.exports.Ciphertext = Ciphertext;

{
"name": "yaml-crypt",
"version": "0.2.0",
"version": "0.3.0",
"description": "Encrypt and decrypt YAML documents",
"license": "MIT",
"author": "Pascal",
"homepage": "https://github.com/pascalgn/yaml-crypt",
"homepage": "https://github.com/autoapply/yaml-crypt",
"repository": {
"type": "git",
"url": "https://github.com/pascalgn/yaml-crypt.git"
"url": "https://github.com/autoapply/yaml-crypt.git"
},

@@ -20,3 +20,3 @@ "main": "./lib/yaml-crypt.js",

"fernet": "^0.3.1",
"js-yaml": "^3.11.0",
"js-yaml": "^3.12.0",
"pkginfo": "^0.4.1",

@@ -34,6 +34,6 @@ "tmp": "^0.0.33",

"coveralls": "^3.0.0",
"eslint": "^4.10.0",
"eslint": "^5.5.0",
"mocha": "^5.1.0",
"nyc": "^11.6.0"
"nyc": "^13.0.1"
}
}
# yaml-crypt
[![Build Status](https://img.shields.io/travis/pascalgn/yaml-crypt.svg?style=flat-square)](https://travis-ci.org/pascalgn/yaml-crypt)
[![Coverage status](https://img.shields.io/coveralls/github/pascalgn/yaml-crypt.svg?style=flat-square)](https://coveralls.io/github/pascalgn/yaml-crypt)
[![Build Status](https://img.shields.io/travis/autoapply/yaml-crypt.svg?style=flat-square)](https://travis-ci.org/autoapply/yaml-crypt)
[![Coverage status](https://img.shields.io/coveralls/github/autoapply/yaml-crypt.svg?style=flat-square)](https://coveralls.io/github/autoapply/yaml-crypt)
[![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](LICENSE)

@@ -27,12 +27,8 @@

both [Fernet](https://github.com/fernet/spec/blob/master/Spec.md)
and [Branca](https://branca.io/) encryption schemes are supported,
so you will need a key with exactly 32 bytes.
The easiest way is to use the [pwgen](https://linux.die.net/man/1/pwgen) command:
and [Branca](https://branca.io/) encryption schemes are supported.
$ pwgen 32 1 > my-key
To generate a new random key, run
Another way would be to use the `urandom` device file:
$ yaml-crypt --generate-key > my-key
$ cat /dev/urandom | LC_ALL=C tr -dc A-Za-z0-9 | head -c 32 > my-key
To encrypt all values in a YAML file, run

@@ -42,8 +38,4 @@

This will generate the file `my-file.yaml-crypt`, while leaving `my-file.yaml` intact.
If you want to delete the original file after encryption, use the `--rm` option.
This will generate the file `my-file.yaml-crypt`.
> Files will be deleted using [unlink](https://linux.die.net/man/2/unlink).
> If this does not meet your security needs, consider removing the file manually instead!
The operation will be performed based on the file extension, so to decrypt a file,

@@ -74,8 +66,7 @@ just use

The yaml-crypt command looks in `~/.yaml-crypt` for a file `config.yaml` or `config.yml`.
Currently, only the `keys` property is supported. These keys will be used when no key
files are given on the command line:
Currently, only the `keys` property is supported. These keys will be used when no keys
are given on the command line:
$ cat ~/.yaml-crypt/config.yaml
keys:
- file: /home/user/.my-key-file
- key: my-raw-key-data

@@ -82,0 +73,0 @@ - key: !!binary my-base64-key-data

@@ -43,3 +43,3 @@ const fs = require('fs');

expect(() => runWithKeyFile(['--path', 'x', '--raw'], {}, { 'stdout': new Out() }))
.to.throw(/cannot be combined/);
.to.throw(/cannot combine/);
});

@@ -61,5 +61,24 @@

expect(() => runWithKeyFile(['-k', secondKeyFile.name, '-e'], {}, { 'stdout': new Out() }))
.to.throw(/more than one key/);
.to.throw(/encrypting, but multiple keys given/);
});
it('should throw an error when trying to read a nonexisting environment variable', () => {
expect(() => yamlcryptcli.run(['-k', 'env:YAML_CRYPT_321'], {}, { 'stdout': new Out() }))
.to.throw(/no such environment variable/);
});
it('should throw an error when passing an invalid file descriptor', () => {
expect(() => yamlcryptcli.run(['-k', 'fd:x'], {}, { 'stdout': new Out() }))
.to.throw(/not a file descriptor/);
});
it('should generate a key', () => {
const options = {
'stdin': '',
'stdout': new Out()
};
yamlcryptcli.run(['--debug', '--generate-key'], {}, options);
expect(options.stdout.str.trimRight()).to.have.lengthOf(32);
});
it('should encrypt the given YAML file (fernet)', () => {

@@ -101,13 +120,20 @@ const input = tmp.fileSync({ 'postfix': '.yaml' });

it('should remove the old files when using --rm', () => {
it('should remove the old files', () => {
const input = tmp.fileSync({ 'postfix': '.yaml' });
fs.copyFileSync('./test/test-2.yaml', input.name);
runWithKeyFile(['--rm', input.name], {}, { 'stdout': new Out() });
runWithKeyFile([input.name], {}, { 'stdout': new Out() });
expect(fs.existsSync(input.name)).to.equal(false);
});
it('should not remove the old files when using --keep', () => {
const input = tmp.fileSync({ 'postfix': '.yaml' });
fs.copyFileSync('./test/test-2.yaml', input.name);
runWithKeyFile(['--keep', input.name], {}, { 'stdout': new Out() });
expect(fs.existsSync(input.name)).to.equal(true);
});
function runWithKeyFile(argv, config, options) {
const keyFile = tmp.fileSync();
fs.writeSync(keyFile.fd, 'aehae5Ui0Eechaeghau9Yoh9jufiep7H');
return yamlcryptcli.run(['-k', keyFile.name].concat(argv), config, options);
return yamlcryptcli.run(['--debug', '-k', keyFile.name].concat(argv), config, options);
}

@@ -121,8 +147,36 @@

expect(() => yamlcryptcli.run(['-k', keyFile.name, input.name], {}, { 'stdout': new Out() }))
.to.throw(/No matching key/);
.to.throw(/no matching key/);
});
it('should throw an error when no named key is available in the config file', () => {
const config = {
'keys': []
};
const options = {
'stdin': '',
'stdout': new Out()
};
expect(() => yamlcryptcli.run(['-k', 'config:name1', '-d'], config, options))
.to.throw(/key not found in configuration file/);
});
it('should throw an error when the key names are not unique in the config file', () => {
const config = {
'keys': [
{ 'key': 'a', 'name': 'key1' },
{ 'key': 'b', 'name': 'key1' }
]
};
const options = {
'stdin': '',
'stdout': new Out()
};
expect(() => yamlcryptcli.run(['-d'], config, options))
.to.throw(/non-unique key name/);
});
it('should decrypt the given input', () => {
const config = {
'keys': [
{ 'key': 'INVALID_KEY____________________X' },
{ 'key': 'aehae5Ui0Eechaeghau9Yoh9jufiep7H' }

@@ -140,8 +194,24 @@ ]

it('should decrypt the given input when using --raw', () => {
const config = {
'keys': [
{ 'key': 'INVALID_KEY_123________________X' },
{ 'key': 'aehae5Ui0Eechaeghau9Yoh9jufiep7H' },
{ 'key': 'INVALID_KEY_345________________X' }
]
};
const input = 'gAAAAAAAAAABAAECAwQFBgcICQoLDA0OD7nQ_JQsjDx78n7mQ9bW3T-rgiTN7WX3Uq66EDA0qxZDNQppXL6WaOAIW4x8ElmcRg==';
const options = {
'stdin': input,
'stdout': new Out()
};
yamlcryptcli.run(['-d', '--raw'], config, options);
expect(options.stdout.str).to.equal('Hello, world!');
});
it('should encrypt the whole input when using --raw', () => {
const keyFile = tmp.fileSync();
fs.writeSync(keyFile.fd, 'aehae5Ui0Eechaeghau9Yoh9jufiep7H');
const config = {
'keys': [
{ 'file': keyFile.name }
{ 'key': 'KEY_THAT_SHOULD_NOT_BE_USED_____', 'name': 'key1' },
{ 'key': 'aehae5Ui0Eechaeghau9Yoh9jufiep7H', 'name': 'key2' }
]

@@ -153,3 +223,3 @@ };

};
yamlcryptcli.run(['-e', '--raw'], config, options);
yamlcryptcli.run(['-e', '--raw', '-K', 'c:key2'], config, options);
const expected = 'gAAAAAAAAAABAAECAwQFBgcICQoLDA0OD7nQ_JQsjDx78n7mQ9bW3T-rgiTN7WX3Uq66EDA0qxZDNQppXL6WaOAIW4x8ElmcRg==\n';

@@ -166,3 +236,3 @@ expect(options.stdout.str).to.equal(expected);

yamlcryptcli.run(['-k', keyFile.name, '--edit', input.name], { 'editor': 'touch' }, {});
yamlcryptcli.run(['--debug', '-k', keyFile.name, '--edit', input.name], { 'editor': 'touch' }, {});

@@ -169,0 +239,0 @@ const output = fs.readFileSync(input.name);

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