From 180910fe15c69efd73fa87d01918899e4f676b5f Mon Sep 17 00:00:00 2001 From: willclarktech Date: Fri, 20 Oct 2017 13:12:21 +0200 Subject: [PATCH] :recycle: :white_check_mark: Refactor encrypt passphrase command tests --- src/commands/encryptPassphrase.js | 2 +- test/specs/commands/encryptPassphrase.js | 746 +++++------------------ test/steps/1_given.js | 86 ++- test/steps/2_when.js | 7 + test/steps/3_then.js | 60 +- test/steps/utils.js | 2 + 6 files changed, 287 insertions(+), 616 deletions(-) diff --git a/src/commands/encryptPassphrase.js b/src/commands/encryptPassphrase.js index 8e4a2003..3e96a94d 100644 --- a/src/commands/encryptPassphrase.js +++ b/src/commands/encryptPassphrase.js @@ -43,7 +43,7 @@ const handleInput = outputPublicKey => ([passphrase, password]) => { : cipherAndIv; }; -const actionCreator = vorpal => async ({ options }) => { +export const actionCreator = vorpal => async ({ options }) => { const { passphrase: passphraseSource, password: passwordSource, diff --git a/test/specs/commands/encryptPassphrase.js b/test/specs/commands/encryptPassphrase.js index 9696cea4..80a0a629 100644 --- a/test/specs/commands/encryptPassphrase.js +++ b/test/specs/commands/encryptPassphrase.js @@ -13,614 +13,154 @@ * Removal or modification of this copyright notice is prohibited. * */ -import encryptPassphraseCommand from '../../../src/commands/encryptPassphrase'; -import cryptoModule from '../../../src/utils/cryptoModule'; -import * as input from '../../../src/utils/input'; -import * as print from '../../../src/utils/print'; -import { - getCommands, - getRequiredArgs, - setUpVorpalWithCommand, -} from './utils'; +import { setUpInputStubs } from '../../steps/utils'; +import * as given from '../../steps/1_given'; +import * as when from '../../steps/2_when'; +import * as then from '../../steps/3_then'; describe('encrypt passphrase command', () => { - const command = 'encrypt passphrase'; - let vorpal; - beforeEach(() => { - vorpal = setUpVorpalWithCommand(encryptPassphraseCommand); - }); - - afterEach(() => { - vorpal.ui.removeAllListeners(); - }); - - describe('setup', () => { - it('should be available', () => { - const encryptPassphraseCommands = getCommands(vorpal, command); - (encryptPassphraseCommands).should.have.length(1); - }); - - it('should require 0 inputs', () => { - const requiredArgs = getRequiredArgs(vorpal, command); - (requiredArgs).should.have.length(0); - }); + setUpInputStubs(); }); - - describe('when executed', () => { - const passphrase = 'secret passphrase'; - const privateKey = 'b6a2b12beb4179538bfb42423cce2e98ccdebcc684145ba977f2f80630eb278e7980b6fcc57907cca971b80b764775b37b9278aad348dbbe608a378e899e7978'; - const publicKey = '7980b6fcc57907cca971b80b764775b37b9278aad348dbbe608a378e899e7978'; - const password = 'testing123'; - const passwordDisplayName = 'your password'; - const stdIn = 'stdin'; - const defaultErrorMessage = 'Some error message.'; - const wrappedErrorMessage = `Could not encrypt passphrase: ${defaultErrorMessage}`; - - let cryptoEncryptPassphraseReturnObject; - let stdInResult; - let getStdInStub; - let getPassphraseStub; - let encryptPassphraseStub; - let cryptoGetKeysReturnObject; - let getKeysStub; - let printSpy; - let printResultStub; - - beforeEach(() => { - cryptoEncryptPassphraseReturnObject = { - cipher: 'abcd', - iv: '0123', - }; - cryptoGetKeysReturnObject = { - publicKey, - privateKey, - }; - getStdInStub = sandbox.stub(input, 'getStdIn').resolves({}); - getPassphraseStub = sandbox.stub(input, 'getPassphrase'); - getPassphraseStub.onFirstCall().resolves(passphrase); - getPassphraseStub.onSecondCall().resolves(password); - encryptPassphraseStub = sandbox.stub(cryptoModule, 'encryptPassphrase').returns(cryptoEncryptPassphraseReturnObject); - getKeysStub = sandbox.stub(cryptoModule, 'getKeys').returns(cryptoGetKeysReturnObject); - printSpy = sandbox.spy(); - printResultStub = sandbox.stub(print, 'printResult').returns(printSpy); - }); - - describe('if the stdin cannot be retrieved', () => { - beforeEach(() => { - getStdInStub.rejects(new Error(defaultErrorMessage)); - return vorpal.exec(command); - }); - - it('should inform the user the encryption was not successful', () => { - (printResultStub.calledWithExactly(vorpal, {})).should.be.true(); - (printSpy.calledWithExactly({ error: wrappedErrorMessage })).should.be.true(); - }); - }); - - describe('if an error occurs during encryption', () => { - beforeEach(() => { - encryptPassphraseStub.rejects(new Error(defaultErrorMessage)); - return vorpal.exec(command); - }); - - it('should inform the user the encryption was not successful', () => { - (printResultStub.calledWithExactly(vorpal, {})).should.be.true(); - (printSpy.calledWithExactly({ error: wrappedErrorMessage })).should.be.true(); - }); - }); - - describe('passphrase', () => { - describe('if the passphrase cannot be retrieved', () => { - beforeEach(() => { - getPassphraseStub.onFirstCall().rejects(new Error(defaultErrorMessage)); - return vorpal.exec(command); - }); - - it('should inform the user the encryption was not successful', () => { - (printResultStub.calledWithExactly(vorpal, {})).should.be.true(); - (printSpy.calledWithExactly({ error: wrappedErrorMessage })).should.be.true(); - }); - }); - - describe('with passphrase passed via prompt', () => { - beforeEach(() => { - return vorpal.exec(command); - }); - - it('should call the input util getStdIn with the correct parameters', () => { - (getStdInStub.calledWithExactly({ - passphraseIsRequired: false, - dataIsRequired: false, - })) - .should.be.true(); - }); - - it('should call the input util getPassphrase with the correct parameters for the passphrase', () => { - (getPassphraseStub.firstCall.calledWithExactly( - vorpal, undefined, undefined, { shouldRepeat: true }, - )) - .should.be.true(); - }); - - it('should call the input util getPassphrase with the correct parameters for the password', () => { - (getPassphraseStub.secondCall.calledWithExactly( - vorpal, undefined, null, { displayName: passwordDisplayName, shouldRepeat: true }, - )) - .should.be.true(); - }); - - it('should call the crypto module encryptPassphrase method with correct parameters', () => { - (encryptPassphraseStub.calledWithExactly(passphrase, password)) - .should.be.true(); - }); - - it('should print the result', () => { - (printResultStub.calledWithExactly(vorpal, {})).should.be.true(); - (printSpy.calledWithExactly(cryptoEncryptPassphraseReturnObject)).should.be.true(); - }); - }); - - describe('with plaintext passphrase passed via command line', () => { - const passphraseSource = `pass:${passphrase}`; - const commandWithPlaintextPassphrase = `${command} --passphrase "${passphraseSource}"`; - - beforeEach(() => { - return vorpal.exec(commandWithPlaintextPassphrase); - }); - - it('should call the input util getStdIn with the correct parameters', () => { - (getStdInStub.calledWithExactly({ - passphraseIsRequired: false, - dataIsRequired: false, - })) - .should.be.true(); - }); - - it('should call the input util getPassphrase with the correct parameters for the passphrase', () => { - (getPassphraseStub.firstCall.calledWithExactly( - vorpal, passphraseSource, undefined, { shouldRepeat: true }, - )) - .should.be.true(); - }); - - it('should call the input util getPassphrase with the correct parameters for the password', () => { - (getPassphraseStub.secondCall.calledWithExactly( - vorpal, undefined, null, { displayName: passwordDisplayName, shouldRepeat: true }, - )) - .should.be.true(); + describe('Given a Vorpal instance with a UI and an active command that can prompt', () => { + beforeEach(given.aVorpalInstanceWithAUIAndAnActiveCommandThatCanPrompt); + describe('Given a crypto instance has been initialised', () => { + beforeEach(given.aCryptoInstanceHasBeenInitialised); + describe('Given an action "encrypt passphrase"', () => { + beforeEach(given.anAction); + describe('Given a passphrase "minute omit local rare sword knee banner pair rib museum shadow juice" with public key "7ef45cd525e95b7a86244bbd4eb4550914ad06301013958f4dd64d32ef7bc588"', () => { + beforeEach(given.aPassphraseWithPublicKey); + describe('Given a password "testing123"', () => { + beforeEach(given.aPassword); + describe('Given the passphrase is provided via the prompt', () => { + beforeEach(given.thePassphraseIsProvidedViaThePrompt); + describe('Given the password is provided via the prompt', () => { + beforeEach(given.thePasswordIsProvidedViaThePrompt); + describe('Given an empty options object', () => { + beforeEach(given.anEmptyOptionsObject); + describe('When the action is called with the options', () => { + beforeEach(when.theActionIsCalledWithTheOptions); + it('Then it should not get the passphrase from stdin', then.itShouldNotGetThePassphraseFromStdIn); + it('Then it should not get the password from stdin', then.itShouldNotGetThePasswordFromStdIn); + it('Then it should get the passphrase using the Vorpal instance', then.itShouldGetThePassphraseUsingTheVorpalInstance); + it('Then it should get the passphrase with a repeated prompt', then.itShouldGetThePassphraseWithARepeatedPrompt); + it('Then it should get the password using the Vorpal instance', then.itShouldGetThePasswordUsingTheVorpalInstance); + it('Then it should get the password with a repeated prompt', then.itShouldGetThePasswordWithARepeatedPrompt); + it('Then it should not get the keys for the passphrase', then.itShouldNotGetTheKeysForThePassphrase); + it('Then it should encrypt the passphrase using the password', then.itShouldEncryptThePassphraseUsingThePassword); + it('Then it should resolve to the result of encrypting the passphrase', then.itShouldResolveToTheResultOfEncryptingThePassphrase); + }); + }); + describe('Given an options object with output-public-key set to boolean true', () => { + beforeEach(given.anOptionsObjectWithOutputPublicKeySetToBoolean); + describe('When the action is called with the options', () => { + beforeEach(when.theActionIsCalledWithTheOptions); + it('Then it should not get the passphrase from stdin', then.itShouldNotGetThePassphraseFromStdIn); + it('Then it should not get the password from stdin', then.itShouldNotGetThePasswordFromStdIn); + it('Then it should get the passphrase using the Vorpal instance', then.itShouldGetThePassphraseUsingTheVorpalInstance); + it('Then it should get the passphrase with a repeated prompt', then.itShouldGetThePassphraseWithARepeatedPrompt); + it('Then it should get the password using the Vorpal instance', then.itShouldGetThePasswordUsingTheVorpalInstance); + it('Then it should get the password with a repeated prompt', then.itShouldGetThePasswordWithARepeatedPrompt); + it('Then it should get the keys for the passphrase', then.itShouldGetTheKeysForThePassphrase); + it('Then it should encrypt the passphrase using the password', then.itShouldEncryptThePassphraseUsingThePassword); + it('Then it should resolve to the result of encrypting the passphrase combined with the public key', then.itShouldResolveToTheResultOfEncryptingThePassphraseCombinedWithThePublicKey); + }); + }); + }); + describe('Given an options object with password set to unknown source "xxx"', () => { + beforeEach(given.anOptionsObjectWithPasswordSetToUnknownSource); + describe('When the action is called with the options', () => { + beforeEach(when.theActionIsCalledWithTheOptions); + it('Then it should reject with message "Unknown data source type. Must be one of `file`, or `stdin`."', then.itShouldRejectWithMessage); + }); + }); + describe('Given an options object with password set to "file:/path/to/my/password.txt"', () => { + beforeEach(given.anOptionsObjectWithPasswordSetTo); + describe('When the action is called with the options', () => { + beforeEach(when.theActionIsCalledWithTheOptions); + it('Then it should not get the passphrase from stdin', then.itShouldNotGetThePassphraseFromStdIn); + it('Then it should not get the message from stdin', then.itShouldNotGetTheMessageFromStdIn); + it('Then it should get the passphrase using the vorpal instance', then.itShouldGetThePassphraseUsingTheVorpalInstance); + it('Then it should get the passphrase with a repeated prompt', then.itShouldGetThePassphraseWithARepeatedPrompt); + it('Then it should get the password using the password source', then.itShouldGetThePasswordUsingThePasswordSource); + it('Then it should encrypt the passphrase using the password', then.itShouldEncryptThePassphraseUsingThePassword); + it('Then it should resolve to the result of encrypting the passphrase', then.itShouldResolveToTheResultOfEncryptingThePassphrase); + }); + }); + describe('Given an options object with password set to "stdin"', () => { + beforeEach(given.anOptionsObjectWithPasswordSetTo); + describe('Given the password is provided via stdin', () => { + beforeEach(given.thePasswordIsProvidedViaStdIn); + describe('When the action is called with the options', () => { + beforeEach(when.theActionIsCalledWithTheOptions); + it('Then it should not get the passphrase from stdin', then.itShouldNotGetThePassphraseFromStdIn); + it('Then it should get the password from stdin', then.itShouldGetThePasswordFromStdIn); + it('Then it should get the passphrase using the vorpal instance', then.itShouldGetThePassphraseUsingTheVorpalInstance); + it('Then it should get the passphrase with a repeated prompt', then.itShouldGetThePassphraseWithARepeatedPrompt); + it('Then it should get the password using the password from stdin', then.itShouldGetThePasswordUsingThePasswordFromStdIn); + it('Then it should encrypt the passphrase using the password', then.itShouldEncryptThePassphraseUsingThePassword); + it('Then it should resolve to the result of encrypting the passphrase', then.itShouldResolveToTheResultOfEncryptingThePassphrase); + }); + }); + }); + }); + describe('Given the password is provided via the prompt', () => { + beforeEach(given.thePasswordIsProvidedViaThePrompt); + describe('Given an options object with passphrase set to unknown source "xxx"', () => { + beforeEach(given.anOptionsObjectWithPassphraseSetToUnknownSource); + describe('When the action is called with the options', () => { + beforeEach(when.theActionIsCalledWithTheOptions); + it('Then it should reject with message "Unknown data source type. Must be one of `file`, or `stdin`."', then.itShouldRejectWithMessage); + }); + }); + describe('Given an options object with passphrase set to "file:/path/to/my/message.txt"', () => { + beforeEach(given.anOptionsObjectWithPassphraseSetTo); + describe('When the action is called with the options', () => { + beforeEach(when.theActionIsCalledWithTheOptions); + it('Then it should not get the passphrase from stdin', then.itShouldNotGetThePassphraseFromStdIn); + it('Then it should not get the password from stdin', then.itShouldNotGetThePasswordFromStdIn); + it('Then it should get the passphrase using the vorpal instance', then.itShouldGetThePassphraseUsingTheVorpalInstance); + it('Then it should get the passphrase with a repeated prompt', then.itShouldGetThePassphraseWithARepeatedPrompt); + it('Then it should get the password using the Vorpal instance', then.itShouldGetThePasswordUsingTheVorpalInstance); + it('Then it should get the password with a repeated prompt', then.itShouldGetThePasswordWithARepeatedPrompt); + it('Then it should encrypt the passphrase using the password', then.itShouldEncryptThePassphraseUsingThePassword); + it('Then it should resolve to the result of encrypting the passphrase', then.itShouldResolveToTheResultOfEncryptingThePassphrase); + }); + }); + describe('Given an options object with passphrase set to "stdin"', () => { + beforeEach(given.anOptionsObjectWithPassphraseSetTo); + describe('Given the passphrase is provided via stdin', () => { + beforeEach(given.thePassphraseIsProvidedViaStdIn); + describe('When the action is called with the options', () => { + beforeEach(when.theActionIsCalledWithTheOptions); + it('Then it should get the passphrase from stdin', then.itShouldGetThePassphraseFromStdIn); + it('Then it should not get the password from stdin', then.itShouldNotGetThePasswordFromStdIn); + it('Then it should get the passphrase using the passphrase from stdin', then.itShouldGetThePassphraseUsingThePassphraseFromStdIn); + it('Then it should get the password using the Vorpal instance', then.itShouldGetThePasswordUsingTheVorpalInstance); + it('Then it should get the password with a repeated prompt', then.itShouldGetThePasswordWithARepeatedPrompt); + it('Then it should encrypt the passphrase using the password', then.itShouldEncryptThePassphraseUsingThePassword); + it('Then it should resolve to the result of encrypting the passphrase', then.itShouldResolveToTheResultOfEncryptingThePassphrase); + }); + }); + }); + }); + describe('Given an options object with passphrase set to "stdin" and password set to "stdin"', () => { + beforeEach(given.anOptionsObjectWithPassphraseSetToAndPasswordSetTo); + describe('Given the passphrase and the password are provided via stdin', () => { + beforeEach(given.thePassphraseAndThePasswordAreProvidedViaStdIn); + describe('When the action is called with the options', () => { + beforeEach(when.theActionIsCalledWithTheOptions); + it('Then it should get the passphrase from stdin', then.itShouldGetThePassphraseFromStdIn); + it('Then it should get the password from stdin', then.itShouldGetThePasswordFromStdIn); + it('Then it should get the passphrase using the passphrase from stdin', then.itShouldGetThePassphraseUsingThePassphraseFromStdIn); + it('Then it should get the password using the password from stdin', then.itShouldGetThePasswordUsingThePasswordFromStdIn); + it('Then it should encrypt the passphrase using the password', then.itShouldEncryptThePassphraseUsingThePassword); + it('Then it should resolve to the result of encrypting the passphrase', then.itShouldResolveToTheResultOfEncryptingThePassphrase); + }); + }); + }); + }); }); - - it('should call the crypto module encryptPassphrase method with correct parameters', () => { - (encryptPassphraseStub.calledWithExactly(passphrase, password)) - .should.be.true(); - }); - - it('should print the result', () => { - (printResultStub.calledWithExactly(vorpal, { passphrase: passphraseSource })) - .should.be.true(); - (printSpy.calledWithExactly(cryptoEncryptPassphraseReturnObject)).should.be.true(); - }); - }); - - describe('with passphrase passed via environmental variable', () => { - const envVariable = 'TEST_PASSPHRASE'; - const passphraseSource = `env:${envVariable}`; - const commandWithEnvPassphrase = `${command} --passphrase "${passphraseSource}"`; - - beforeEach(() => { - return vorpal.exec(commandWithEnvPassphrase); - }); - - it('should call the input util getStdIn with the correct parameters', () => { - (getStdInStub.calledWithExactly({ - passphraseIsRequired: false, - dataIsRequired: false, - })) - .should.be.true(); - }); - - it('should call the input util getPassphrase with the correct parameters for the passphrase', () => { - (getPassphraseStub.firstCall.calledWithExactly( - vorpal, passphraseSource, undefined, { shouldRepeat: true }, - )) - .should.be.true(); - }); - - it('should call the input util getPassphrase with the correct parameters for the password', () => { - (getPassphraseStub.secondCall.calledWithExactly( - vorpal, undefined, null, { displayName: passwordDisplayName, shouldRepeat: true }, - )) - .should.be.true(); - }); - - it('should call the crypto module encryptPassphrase method with correct parameters', () => { - (encryptPassphraseStub.calledWithExactly(passphrase, password)) - .should.be.true(); - }); - - it('should print the result', () => { - (printResultStub.calledWithExactly(vorpal, { passphrase: passphraseSource })) - .should.be.true(); - (printSpy.calledWithExactly(cryptoEncryptPassphraseReturnObject)).should.be.true(); - }); - }); - - describe('with passphrase passed via file path', () => { - const passphraseSource = 'file:/path/to/passphrase.txt'; - const commandWithFilePassphrase = `${command} --passphrase "${passphraseSource}"`; - - beforeEach(() => { - return vorpal.exec(commandWithFilePassphrase); - }); - - it('should call the input util getStdIn with the correct parameters', () => { - (getStdInStub.calledWithExactly({ - passphraseIsRequired: false, - dataIsRequired: false, - })) - .should.be.true(); - }); - - it('should call the input util getPassphrase with the correct parameters for the passphrase', () => { - (getPassphraseStub.firstCall.calledWithExactly( - vorpal, passphraseSource, undefined, { shouldRepeat: true }, - )) - .should.be.true(); - }); - - it('should call the input util getPassphrase with the correct parameters for the password', () => { - (getPassphraseStub.secondCall.calledWithExactly( - vorpal, undefined, null, { displayName: passwordDisplayName, shouldRepeat: true }, - )) - .should.be.true(); - }); - - it('should call the crypto module encryptPassphrase method with correct parameters', () => { - (encryptPassphraseStub.calledWithExactly(passphrase, password)) - .should.be.true(); - }); - - it('should print the result', () => { - (printResultStub.calledWithExactly(vorpal, { passphrase: passphraseSource })) - .should.be.true(); - (printSpy.calledWithExactly(cryptoEncryptPassphraseReturnObject)).should.be.true(); - }); - }); - - describe('with passphrase passed via stdin', () => { - const passphraseSource = stdIn; - const commandWithStdInPassphrase = `${command} --passphrase "${passphraseSource}"`; - - beforeEach(() => { - stdInResult = { passphrase }; - getStdInStub.resolves(stdInResult); - return vorpal.exec(commandWithStdInPassphrase); - }); - - it('should call the input util getStdIn with the correct parameters', () => { - (getStdInStub.calledWithExactly({ - passphraseIsRequired: true, - dataIsRequired: false, - })) - .should.be.true(); - }); - - it('should call the input util getPassphrase with the correct parameters for the passphrase', () => { - (getPassphraseStub.firstCall.calledWithExactly( - vorpal, passphraseSource, passphrase, { shouldRepeat: true }, - )) - .should.be.true(); - }); - - it('should call the input util getPassphrase with the correct parameters for the password', () => { - (getPassphraseStub.secondCall.calledWithExactly( - vorpal, undefined, null, { displayName: passwordDisplayName, shouldRepeat: true }, - )) - .should.be.true(); - }); - - it('should call the crypto module encryptPassphrase method with correct parameters', () => { - (encryptPassphraseStub.calledWithExactly(passphrase, password)) - .should.be.true(); - }); - - it('should print the result', () => { - (printResultStub.calledWithExactly(vorpal, { passphrase: passphraseSource })) - .should.be.true(); - (printSpy.calledWithExactly(cryptoEncryptPassphraseReturnObject)).should.be.true(); - }); - }); - }); - - describe('password', () => { - describe('if the password cannot be retrieved', () => { - beforeEach(() => { - getPassphraseStub.onSecondCall().rejects(new Error(defaultErrorMessage)); - return vorpal.exec(command); - }); - - it('should inform the user the encryption was not successful', () => { - (printResultStub.calledWithExactly(vorpal, {})).should.be.true(); - (printSpy.calledWithExactly({ error: wrappedErrorMessage })).should.be.true(); - }); - }); - - describe('with password passed via prompt', () => { - beforeEach(() => { - return vorpal.exec(command); - }); - - it('should call the input util getStdIn with the correct parameters', () => { - (getStdInStub.calledWithExactly({ - passphraseIsRequired: false, - dataIsRequired: false, - })) - .should.be.true(); - }); - - it('should call the input util getPassphrase with the correct parameters for the passphrase', () => { - (getPassphraseStub.firstCall.calledWithExactly( - vorpal, undefined, undefined, { shouldRepeat: true }, - )) - .should.be.true(); - }); - - it('should call the input util getPassphrase with the correct parameters for the password', () => { - (getPassphraseStub.secondCall.calledWithExactly( - vorpal, undefined, null, { displayName: passwordDisplayName, shouldRepeat: true }, - )) - .should.be.true(); - }); - - it('should call the crypto module encryptPassphrase method with correct parameters', () => { - (encryptPassphraseStub.calledWithExactly(passphrase, password)) - .should.be.true(); - }); - - it('should print the result', () => { - (printResultStub.calledWithExactly(vorpal, {})).should.be.true(); - (printSpy.calledWithExactly(cryptoEncryptPassphraseReturnObject)).should.be.true(); - }); - }); - - describe('with plaintext password passed via command line', () => { - const passwordSource = `pass:${password}`; - const commandWithPlaintextPassword = `${command} --password "${passwordSource}"`; - - beforeEach(() => { - return vorpal.exec(commandWithPlaintextPassword); - }); - - it('should call the input util getStdIn with the correct parameters', () => { - (getStdInStub.calledWithExactly({ - passphraseIsRequired: false, - dataIsRequired: false, - })) - .should.be.true(); - }); - - it('should call the input util getPassphrase with the correct parameters for the passphrase', () => { - (getPassphraseStub.firstCall.calledWithExactly( - vorpal, undefined, undefined, { shouldRepeat: true }, - )) - .should.be.true(); - }); - - it('should call the input util getPassphrase with the correct parameters for the password', () => { - (getPassphraseStub.secondCall.calledWithExactly( - vorpal, passwordSource, null, { displayName: passwordDisplayName, shouldRepeat: true }, - )) - .should.be.true(); - }); - - it('should call the crypto module encryptPassphrase method with correct parameters', () => { - (encryptPassphraseStub.calledWithExactly(passphrase, password)) - .should.be.true(); - }); - - it('should print the result', () => { - (printResultStub.calledWithExactly(vorpal, { password: passwordSource })) - .should.be.true(); - (printSpy.calledWithExactly(cryptoEncryptPassphraseReturnObject)).should.be.true(); - }); - }); - - describe('with password passed via environmental variable', () => { - const envVariable = 'TEST_PASSWORD'; - const passwordSource = `env:${envVariable}`; - const commandWithEnvPassword = `${command} --password "${passwordSource}"`; - - beforeEach(() => { - return vorpal.exec(commandWithEnvPassword); - }); - - it('should call the input util getStdIn with the correct parameters', () => { - (getStdInStub.calledWithExactly({ - passphraseIsRequired: false, - dataIsRequired: false, - })) - .should.be.true(); - }); - - it('should call the input util getPassphrase with the correct parameters for the passphrase', () => { - (getPassphraseStub.firstCall.calledWithExactly( - vorpal, undefined, undefined, { shouldRepeat: true }, - )) - .should.be.true(); - }); - - it('should call the input util getPassphrase with the correct parameters for the password', () => { - (getPassphraseStub.secondCall.calledWithExactly( - vorpal, passwordSource, null, { displayName: passwordDisplayName, shouldRepeat: true }, - )) - .should.be.true(); - }); - - it('should call the crypto module encryptPassphrase method with correct parameters', () => { - (encryptPassphraseStub.calledWithExactly(passphrase, password)) - .should.be.true(); - }); - - it('should print the result', () => { - (printResultStub.calledWithExactly(vorpal, { password: passwordSource })) - .should.be.true(); - (printSpy.calledWithExactly(cryptoEncryptPassphraseReturnObject)).should.be.true(); - }); - }); - - describe('with password passed via file path', () => { - const passwordSource = 'file:/path/to/password.txt'; - const commandWithFilePassword = `${command} --password "${passwordSource}"`; - - beforeEach(() => { - return vorpal.exec(commandWithFilePassword); - }); - - it('should call the input util getStdIn with the correct parameters', () => { - (getStdInStub.calledWithExactly({ - passphraseIsRequired: false, - dataIsRequired: false, - })) - .should.be.true(); - }); - - it('should call the input util getPassphrase with the correct parameters for the passphrase', () => { - (getPassphraseStub.firstCall.calledWithExactly( - vorpal, undefined, undefined, { shouldRepeat: true }, - )) - .should.be.true(); - }); - - it('should call the input util getPassphrase with the correct parameters for the password', () => { - (getPassphraseStub.secondCall.calledWithExactly( - vorpal, passwordSource, null, { displayName: passwordDisplayName, shouldRepeat: true }, - )) - .should.be.true(); - }); - - it('should call the crypto module encryptPassphrase method with correct parameters', () => { - (encryptPassphraseStub.calledWithExactly(passphrase, password)) - .should.be.true(); - }); - - it('should print the result', () => { - (printResultStub.calledWithExactly(vorpal, { password: passwordSource })) - .should.be.true(); - (printSpy.calledWithExactly(cryptoEncryptPassphraseReturnObject)).should.be.true(); - }); - }); - - describe('with password passed via stdin', () => { - const passwordSource = stdIn; - const commandWithStdInPassword = `${command} --password "${passwordSource}"`; - - beforeEach(() => { - stdInResult = { data: `${password}\nSome irrelevant data` }; - getStdInStub.resolves(stdInResult); - return vorpal.exec(commandWithStdInPassword); - }); - - it('should call the input util getStdIn with the correct parameters', () => { - (getStdInStub.calledWithExactly({ - passphraseIsRequired: false, - dataIsRequired: true, - })) - .should.be.true(); - }); - - it('should call the input util getPassphrase with the correct parameters for the passphrase', () => { - (getPassphraseStub.firstCall.calledWithExactly( - vorpal, undefined, undefined, { shouldRepeat: true }, - )) - .should.be.true(); - }); - - it('should call the input util getPassphrase with the correct parameters for the password', () => { - (getPassphraseStub.secondCall.calledWithExactly( - vorpal, passwordSource, password, { - displayName: passwordDisplayName, - shouldRepeat: true, - }, - )) - .should.be.true(); - }); - - it('should call the crypto module encryptPassphrase method with correct parameters', () => { - (encryptPassphraseStub.calledWithExactly(passphrase, password)) - .should.be.true(); - }); - - it('should print the result', () => { - (printResultStub.calledWithExactly(vorpal, { password: passwordSource })) - .should.be.true(); - (printSpy.calledWithExactly(cryptoEncryptPassphraseReturnObject)).should.be.true(); - }); - }); - }); - - describe('with passphrase and password passed via stdin', () => { - const commandWithStdInPassphraseAndStdInPassword = `${command} --passphrase ${stdIn} --password ${stdIn}`; - - beforeEach(() => { - stdInResult = { passphrase, data: `${password}\nSome irrelevant data` }; - getStdInStub.resolves(stdInResult); - return vorpal.exec(commandWithStdInPassphraseAndStdInPassword); - }); - - it('should call the input util getStdIn with the correct parameters', () => { - (getStdInStub.calledWithExactly({ - passphraseIsRequired: true, - dataIsRequired: true, - })) - .should.be.true(); - }); - - it('should call the input util getPassphrase with the correct parameters for the passphrase', () => { - (getPassphraseStub.firstCall.calledWithExactly( - vorpal, stdIn, passphrase, { shouldRepeat: true }, - )) - .should.be.true(); - }); - - it('should call the input util getPassphrase with the correct parameters for the password', () => { - (getPassphraseStub.secondCall.calledWithExactly( - vorpal, stdIn, password, { displayName: passwordDisplayName, shouldRepeat: true }, - )) - .should.be.true(); - }); - - it('should call the crypto module encryptPassphrase method with correct parameters', () => { - (encryptPassphraseStub.calledWithExactly(passphrase, password)) - .should.be.true(); - }); - - it('should print the result', () => { - (printResultStub.calledWithExactly(vorpal, { passphrase: stdIn, password: stdIn })) - .should.be.true(); - (printSpy.calledWithExactly(cryptoEncryptPassphraseReturnObject)).should.be.true(); - }); - }); - - describe('with public key option', () => { - const passphraseSource = `pass:${passphrase}`; - const passwordSource = `pass:${password}`; - const commandWithPublicKeyOption = `${command} --passphrase "${passphraseSource}" --password "${passwordSource}" --output-public-key`; - - beforeEach(() => { - return vorpal.exec(commandWithPublicKeyOption); - }); - - it('should call the crypto module getKeys method', () => { - (getKeysStub.calledWithExactly(passphrase)).should.be.true(); - }); - - it('should print the result', () => { - (printResultStub.calledWithExactly(vorpal, { passphrase: passphraseSource, password: passwordSource, 'output-public-key': true })).should.be.true(); - (printSpy.calledWithExactly( - Object.assign({}, cryptoEncryptPassphraseReturnObject, { publicKey }), - )) - .should.be.true(); }); }); }); diff --git a/test/steps/1_given.js b/test/steps/1_given.js index a2b9be27..2e4c3b85 100644 --- a/test/steps/1_given.js +++ b/test/steps/1_given.js @@ -57,6 +57,18 @@ export function anEncryptedMessage() { this.test.ctx.message = message; } +export function thePassphraseAndThePasswordAreProvidedViaStdIn() { + const { passphrase, password } = this.test.ctx; + inputUtils.getStdIn.resolves({ passphrase, data: password }); + inputUtils.getPassphrase.onFirstCall().resolves(passphrase); + inputUtils.getPassphrase.onSecondCall().resolves(password); +} + +export function thePasswordIsProvidedViaStdIn() { + const { password } = this.test.ctx; + inputUtils.getStdIn.resolves({ data: password }); +} + export function thePassphraseAndTheMessageAreProvidedViaStdIn() { const { passphrase, message } = this.test.ctx; inputUtils.getStdIn.resolves({ passphrase, data: message }); @@ -373,12 +385,17 @@ export function aCryptoInstance() { export function aPassphrase() { const passphrase = getFirstQuotedString(this.test.parent.title); - if (typeof inputUtils.getPassphrase.resolves === 'function') { - inputUtils.getPassphrase.resolves(passphrase); - } this.test.ctx.passphrase = passphrase; } +export function aPassphraseWithPublicKey() { + const [passphrase, publicKey] = getQuotedStrings(this.test.parent.title); + cryptoInstance.getKeys.returns({ publicKey }); + + this.test.ctx.passphrase = passphrase; + this.test.ctx.publicKey = publicKey; +} + export function aPassphraseWithPrivateKeyAndPublicKeyAndAddress() { const [passphrase, privateKey, publicKey, address] = getQuotedStrings(this.test.parent.title); const keys = { @@ -396,7 +413,8 @@ export function aPassphraseWithPrivateKeyAndPublicKeyAndAddress() { } export function aPassword() { - this.test.ctx.password = getFirstQuotedString(this.test.parent.title); + const password = getFirstQuotedString(this.test.parent.title); + this.test.ctx.password = password; } export function anEncryptedPassphraseWithAnIV() { @@ -586,8 +604,21 @@ export function aPromptDisplayName() { } export function thePassphraseIsProvidedViaThePrompt() { - const { passphrase } = this.test.ctx; - this.test.ctx.vorpal.activeCommand.prompt.resolves({ passphrase }); + const { passphrase, promptInputs = [] } = this.test.ctx; + this.test.ctx.vorpal.activeCommand.prompt.onCall(promptInputs.length).resolves({ passphrase }); + if (typeof inputUtils.getPassphrase.resolves === 'function') { + inputUtils.getPassphrase.onFirstCall().resolves(passphrase); + } + promptInputs.push(passphrase); +} + +export function thePasswordIsProvidedViaThePrompt() { + const { password, promptInputs = [] } = this.test.ctx; + this.test.ctx.vorpal.activeCommand.prompt.onCall(promptInputs.length).resolves({ password }); + if (typeof inputUtils.getPassphrase.resolves === 'function') { + inputUtils.getPassphrase.onSecondCall().resolves(password); + } + promptInputs.push(password); } export function thePassphraseShouldNotBeRepeated() { @@ -751,9 +782,40 @@ export function aConfigWithJsonSetTo() { this.test.ctx.config = config; } +export function anOptionsObjectWithOutputPublicKeySetToBoolean() { + const outputPublicKey = getFirstBoolean(this.test.parent.title); + this.test.ctx.options = { 'output-public-key': outputPublicKey }; +} + +export function anOptionsObjectWithPassphraseSetToAndPasswordSetTo() { + const [passphrase, password] = getQuotedStrings(this.test.parent.title); + this.test.ctx.options = { passphrase, password }; +} + +export function anOptionsObjectWithPasswordSetTo() { + const { password } = this.test.ctx; + const passwordSource = getFirstQuotedString(this.test.parent.title); + if (typeof inputUtils.getPassphrase.resolves === 'function') { + inputUtils.getPassphrase.onSecondCall().resolves(password); + } + this.test.ctx.options = { password: passwordSource }; +} + +export function anOptionsObjectWithPasswordSetToUnknownSource() { + const password = getFirstQuotedString(this.test.parent.title); + if (typeof inputUtils.getPassphrase.resolves === 'function') { + inputUtils.getPassphrase.onSecondCall().rejects(new Error('Unknown data source type. Must be one of `file`, or `stdin`.')); + } + this.test.ctx.options = { password }; +} + export function anOptionsObjectWithPassphraseSetToAndMessageSetTo() { - const [passphrase, message] = getQuotedStrings(this.test.parent.title); - this.test.ctx.options = { passphrase, message }; + const { passphrase } = this.test.ctx; + const [passphraseSource, messageSource] = getQuotedStrings(this.test.parent.title); + if (typeof inputUtils.getPassphrase.resolves === 'function') { + inputUtils.getPassphrase.resolves(passphrase); + } + this.test.ctx.options = { passphrase: passphraseSource, message: messageSource }; } export function anOptionsObjectWithMessageSetTo() { @@ -763,18 +825,22 @@ export function anOptionsObjectWithMessageSetTo() { export function anOptionsObjectWithMessageSetToUnknownSource() { const message = getFirstQuotedString(this.test.parent.title); - this.test.ctx.options = { message }; inputUtils.getData.rejects(new Error('Unknown data source type. Must be one of `file`, or `stdin`.')); + this.test.ctx.options = { message }; } export function anOptionsObjectWithPassphraseSetTo() { + const { passphrase } = this.test.ctx; const passphraseSource = getFirstQuotedString(this.test.parent.title); + if (typeof inputUtils.getPassphrase.resolves === 'function') { + inputUtils.getPassphrase.resolves(passphrase); + } this.test.ctx.options = { passphrase: passphraseSource }; } export function anOptionsObjectWithPassphraseSetToUnknownSource() { const passphrase = getFirstQuotedString(this.test.parent.title); - inputUtils.getData.rejects(new Error('Unknown data source type. Must be one of `file`, or `stdin`.')); + inputUtils.getPassphrase.onFirstCall().rejects(new Error('Unknown data source type. Must be one of `file`, or `stdin`.')); this.test.ctx.options = { passphrase }; } diff --git a/test/steps/2_when.js b/test/steps/2_when.js index 14d107d1..fe3c7044 100644 --- a/test/steps/2_when.js +++ b/test/steps/2_when.js @@ -102,6 +102,13 @@ export function theActionIsCalledWithTheVariableAndTheValue() { return returnValue.catch(e => e); } +export function theActionIsCalledWithTheOptions() { + const { action, options } = this.test.ctx; + const returnValue = action({ options }); + this.test.ctx.returnValue = returnValue; + return returnValue.catch(e => e); +} + export function theActionIsCalled() { const { action } = this.test.ctx; const returnValue = action(); diff --git a/test/steps/3_then.js b/test/steps/3_then.js index 32eea8ad..de7caa6f 100644 --- a/test/steps/3_then.js +++ b/test/steps/3_then.js @@ -27,6 +27,32 @@ import { getFirstBoolean, } from './utils'; +export function itShouldNotGetTheKeysForThePassphrase() { + return (cryptoInstance.getKeys).should.not.be.called(); +} + +export function itShouldGetTheKeysForThePassphrase() { + const { passphrase } = this.test.ctx; + return (cryptoInstance.getKeys).should.be.calledWithExactly(passphrase); +} + +export function itShouldGetThePasswordFromStdIn() { + const firstCallArgs = input.getStdIn.firstCall.args; + return (firstCallArgs[0]).should.have.property('dataIsRequired').equal(true); +} + +export function itShouldGetThePasswordUsingThePasswordFromStdIn() { + const { password } = this.test.ctx; + const secondCallArgs = input.getPassphrase.secondCall.args; + return (secondCallArgs[2]).should.equal(password); +} + +export function itShouldGetThePasswordUsingThePasswordSource() { + const { options } = this.test.ctx; + const secondCallArgs = input.getPassphrase.secondCall.args; + return (secondCallArgs[1]).should.equal(options.password); +} + export function itShouldGetTheDataUsingTheMessageFromStdIn() { const { message } = this.test.ctx; const firstCallArgs = input.getData.firstCall.args; @@ -63,12 +89,22 @@ export function itShouldGetThePassphraseWithASinglePrompt() { export function itShouldGetThePassphraseWithARepeatedPrompt() { const firstCallArgs = input.getPassphrase.firstCall.args; - return (firstCallArgs[3]).should.eql({ shouldRepeat: true }); + return (firstCallArgs[3]).should.have.property('shouldRepeat').be.true(); +} + +export function itShouldGetThePasswordWithARepeatedPrompt() { + const secondCallArgs = input.getPassphrase.secondCall.args; + return (secondCallArgs[3]).should.have.property('shouldRepeat').be.true(); } export function itShouldGetThePassphraseUsingTheVorpalInstance() { const { vorpal } = this.test.ctx; - return (input.getPassphrase).should.be.calledWith(vorpal); + return (input.getPassphrase.firstCall).should.be.calledWith(vorpal); +} + +export function itShouldGetThePasswordUsingTheVorpalInstance() { + const { vorpal } = this.test.ctx; + return (input.getPassphrase.secondCall).should.be.calledWith(vorpal); } export function itShouldNotGetThePassphraseFromStdIn() { @@ -76,6 +112,11 @@ export function itShouldNotGetThePassphraseFromStdIn() { return (firstCallArgs[0]).should.have.property('passphraseIsRequired').equal(false); } +export function itShouldNotGetThePasswordFromStdIn() { + const firstCallArgs = input.getStdIn.firstCall.args; + return (firstCallArgs[0]).should.have.property('dataIsRequired').equal(false); +} + export function itShouldGetThePassphraseFromStdIn() { const firstCallArgs = input.getStdIn.firstCall.args; return (firstCallArgs[0]).should.have.property('passphraseIsRequired').equal(true); @@ -91,6 +132,21 @@ export function itShouldGetTheMessageFromStdIn() { return (firstCallArgs[0]).should.have.property('dataIsRequired').equal(true); } +export function itShouldResolveToTheResultOfEncryptingThePassphraseCombinedWithThePublicKey() { + const { returnValue, cryptoResult, publicKey } = this.test.ctx; + return (returnValue).should.be.fulfilledWith(Object.assign({}, cryptoResult, { publicKey })); +} + +export function itShouldEncryptThePassphraseUsingThePassword() { + const { passphrase, password } = this.test.ctx; + return (cryptoInstance.encryptPassphrase).should.be.calledWithExactly(passphrase, password); +} + +export function itShouldResolveToTheResultOfEncryptingThePassphrase() { + const { returnValue, cryptoResult } = this.test.ctx; + return (returnValue).should.be.fulfilledWith(cryptoResult); +} + export function itShouldDecryptTheMessageUsingTheNonceThePassphraseAndTheSenderPublicKey() { const { message, nonce, passphrase, senderPublicKey } = this.test.ctx; return (cryptoInstance.decryptMessage).should.be.calledWithExactly(message, nonce, passphrase, senderPublicKey); diff --git a/test/steps/utils.js b/test/steps/utils.js index 10da1d80..4765cee7 100644 --- a/test/steps/utils.js +++ b/test/steps/utils.js @@ -17,6 +17,7 @@ import fs from 'fs'; import * as createAccount from '../../src/commands/createAccount'; import * as decryptMessage from '../../src/commands/decryptMessage'; import * as encryptMessage from '../../src/commands/encryptMessage'; +import * as encryptPassphrase from '../../src/commands/encryptPassphrase'; import * as env from '../../src/commands/env'; import * as get from '../../src/commands/get'; import * as list from '../../src/commands/list'; @@ -61,6 +62,7 @@ export const getActionCreator = actionName => ({ 'create account': createAccount.actionCreator, 'decrypt message': decryptMessage.actionCreator, 'encrypt message': encryptMessage.actionCreator, + 'encrypt passphrase': encryptPassphrase.actionCreator, env: env.actionCreator, get: get.actionCreator, list: list.actionCreator,