bridge-node-server/node_server/utils/specs/encryption.spec.js

409 lines
16 KiB
JavaScript
Raw Normal View History

2018-06-24 20:15:03 +00:00
/* eslint-disable no-empty */
/**
* Unit testing file for encryption
*/
'use strict';
/* eslint max-nested-callbacks: ["error", 7] */
// eslint-disable-next-line no-unused-vars
const testGlobals = require('../../tools/test/testGlobals.js');
const _ = require('lodash');
const chai = require('chai');
const sinon = require('sinon');
const sinonChai = require('sinon-chai');
const rewire = require('rewire');
/**
* Use `rewire` instead of require so that we can access private functions for test
*/
const encryption = rewire('../encryption.js');
const utilsStub = encryption.__get__('utils');
const expect = chai.expect;
const sandbox = sinon.createSandbox();
chai.use(sinonChai);
const ENCRYPTION_KEY = 'go3rn2ofno2';
const USER_ID = 'o5oij5oioj23oij';
const FAKE_ENCRYPTED_DETAILS = '4j3nrkj23b4rk';
const FAKE_ERROR = {error: 'This is an error'};
const CARD_PAN = '0000000000000000';
const CARD_EXPIRY = '01-20';
const CARD_VALID_FROM = '01-15';
const CARD_ISSUE_NO = '00';
const UNENCRYPTED_DETAILS = {
FirstName: 'Joe',
LastName: 'Bloggs'
};
const MIN_ACCOUNT = {
CreditDebitCardInfo: _.defaults(
{
CardPanToBeEncrypted: CARD_PAN,
CardExpiryToBeEncrypted: CARD_EXPIRY,
CardPANEncrypted: '',
CardExpiryEncrypted: '',
CardValidFromEncrypted: '',
IssueNumberEncrypted: ''
},
UNENCRYPTED_DETAILS
)
};
const MAX_ACCOUNT = _.defaultsDeep(
{
CreditDebitCardInfo: {
CardValidFromToBeEncrypted: CARD_VALID_FROM,
IssueNumberToBeEncrypted: CARD_ISSUE_NO
}
},
MIN_ACCOUNT
);
const MIN_DATA = {
Account: MIN_ACCOUNT
};
const MAX_DATA = {
Account: MAX_ACCOUNT
};
const MIN_ENCRYPTED_ACCOUNT = {
CreditDebitCardInfo: _.defaultsDeep(
{
CardExpiryEncrypted: FAKE_ENCRYPTED_DETAILS,
CardPANEncrypted: FAKE_ENCRYPTED_DETAILS
},
UNENCRYPTED_DETAILS
)
};
const MAX_ENCRYPTED_ACCOUNT = _.defaultsDeep(
{
CreditDebitCardInfo: {
CardValidFromEncrypted: FAKE_ENCRYPTED_DETAILS,
IssueNumberEncrypted: FAKE_ENCRYPTED_DETAILS
}
},
MIN_ENCRYPTED_ACCOUNT
);
const MIN_DECRYPTED_RETURN_OBJECT = {
expiryMonth: '01',
expiryYear: '2020',
cardNumber: CARD_PAN
};
const MAX_DECRYPTED_RETURN_OBJECT = _.defaultsDeep(
{
IssueNumber: 0,
startMonth: '01',
startYear: '2015'
},
MIN_DECRYPTED_RETURN_OBJECT
);
const MIN_DECRYPTED_FULL_ACCOUNT = {
CreditDebitCardInfo: _.defaultsDeep(
{},
UNENCRYPTED_DETAILS,
MIN_DECRYPTED_RETURN_OBJECT
)
};
const MAX_DECRYPTED_FULL_ACCOUNT = {
CreditDebitCardInfo: _.defaultsDeep(
{},
UNENCRYPTED_DETAILS,
MAX_DECRYPTED_RETURN_OBJECT
)
};
const MIN_ENCRYPTED_RETURN_OBJECT = {
CardPANEncrypted: FAKE_ENCRYPTED_DETAILS,
CardExpiryEncrypted: FAKE_ENCRYPTED_DETAILS
};
const MAX_ENCRYPTED_RETURN_OBJECT = _.defaultsDeep(
{
CardValidFromEncrypted: FAKE_ENCRYPTED_DETAILS,
IssueNumberEncrypted: FAKE_ENCRYPTED_DETAILS
},
MIN_ENCRYPTED_RETURN_OBJECT
);
const MIN_ENCRYPTED_FULL_ACCOUNT = {
Account: {
CreditDebitCardInfo: _.defaultsDeep(
{
CardValidFromEncrypted: '',
IssueNumberEncrypted: ''
},
MIN_ENCRYPTED_RETURN_OBJECT,
UNENCRYPTED_DETAILS
)
}
};
const MAX_ENCRYPTED_FULL_ACCOUNT = {
Account: {
CreditDebitCardInfo: _.defaultsDeep(
{},
MAX_ENCRYPTED_RETURN_OBJECT,
UNENCRYPTED_DETAILS
)
}
};
const INVALID_ACCOUNT = {};
describe('encryption function', () => {
/**
* Stub the functions that will be used for the "happy path"
* The responses are specifically overriden below for testing the error cases
*/
beforeEach(() => {
sandbox.spy(encryption, 'encryptCard');
sandbox.spy(encryption, 'decryptCard');
sandbox.spy(encryption, 'encryptCardMaintainingAccount');
sandbox.spy(encryption, 'decryptCardMaintainingAccount');
sandbox.stub(utilsStub, 'decryptDataV3')
.onCall(0).returns(CARD_EXPIRY)
.onCall(1).returns(CARD_PAN)
.onCall(2).returns(CARD_ISSUE_NO)
.onCall(3).returns(CARD_VALID_FROM);
sandbox.stub(utilsStub, 'encryptDataV3')
.onCall(0).returns(FAKE_ENCRYPTED_DETAILS)
.onCall(1).returns(FAKE_ENCRYPTED_DETAILS)
.onCall(2).returns(FAKE_ENCRYPTED_DETAILS)
.onCall(3).returns(FAKE_ENCRYPTED_DETAILS);
});
afterEach(() => {
sandbox.restore();
});
describe('calls encryptCard', () => {
describe('successfully', () => {
describe('with required card fields set', () => {
beforeEach(() => {
encryption.encryptCard(MIN_ACCOUNT.CreditDebitCardInfo, ENCRYPTION_KEY, USER_ID);
});
it('encrypting cardPAN and expiry date', () => {
return expect(utilsStub.encryptDataV3).to.have.been
.calledTwice
.calledWith(CARD_PAN, ENCRYPTION_KEY, USER_ID)
.calledWith(CARD_EXPIRY, ENCRYPTION_KEY, USER_ID);
});
it('returning encrypted details ', () => {
return expect(encryption.encryptCard).to.have.returned(MIN_ENCRYPTED_RETURN_OBJECT);
});
});
describe('with all fields set', () => {
beforeEach(() => {
encryption.encryptCard(MAX_ACCOUNT.CreditDebitCardInfo, ENCRYPTION_KEY, USER_ID);
});
it('encrypting valid from, issue no., cardPAN and expiry date', () => {
return expect(utilsStub.encryptDataV3).to.have.been
.callCount(4)
.calledWith(CARD_PAN, ENCRYPTION_KEY, USER_ID)
.calledWith(CARD_EXPIRY, ENCRYPTION_KEY, USER_ID)
.calledWith(CARD_VALID_FROM, ENCRYPTION_KEY, USER_ID)
.calledWith(CARD_ISSUE_NO, ENCRYPTION_KEY, USER_ID);
});
it('returning encrypted details ', () => {
return expect(encryption.encryptCard).to.have.returned(MAX_ENCRYPTED_RETURN_OBJECT);
});
});
});
describe('with a failure', () => {
describe('to encrypt the data', () => {
beforeEach(() => {
utilsStub.encryptDataV3
.onCall(0).returns(FAKE_ERROR);
try {
encryption.encryptCard(MIN_ACCOUNT.CreditDebitCardInfo, ENCRYPTION_KEY, USER_ID);
} catch (error) {}
});
it('fails to encrypt cardPAN', () => {
return expect(utilsStub.encryptDataV3).to.have.been
.calledOnce
.calledWith(CARD_PAN, ENCRYPTION_KEY, USER_ID);
});
it('throwing an error', () => {
return expect(encryption.encryptCard).to.have.thrown();
});
});
describe('to send invalid data to encrypt', () => {
beforeEach(() => {
try {
encryption.encryptCard(INVALID_ACCOUNT.CreditDebitCardInfo, ENCRYPTION_KEY, USER_ID);
} catch (error) {}
});
it('does not try to encrypt anything', () => {
return expect(utilsStub.encryptDataV3).to.not.have.been.called;
});
it('throwing an error', () => {
return expect(encryption.encryptCard).to.have.thrown();
});
});
});
});
describe('calls decryptCard', () => {
describe('successfully', () => {
describe('with required card fields set', () => {
beforeEach(() => {
encryption.decryptCard(MIN_ENCRYPTED_ACCOUNT.CreditDebitCardInfo, ENCRYPTION_KEY, USER_ID);
});
it('decrypting cardPAN and expiry date', () => {
return expect(utilsStub.decryptDataV3).to.have.been
.calledTwice
.calledWith(FAKE_ENCRYPTED_DETAILS, ENCRYPTION_KEY, USER_ID)
.calledWith(FAKE_ENCRYPTED_DETAILS, ENCRYPTION_KEY, USER_ID);
});
it('returning decrypted details ', () => {
return expect(encryption.decryptCard).to.have.returned(MIN_DECRYPTED_RETURN_OBJECT);
});
});
describe('with all fields set', () => {
beforeEach(() => {
encryption.decryptCard(MAX_ENCRYPTED_ACCOUNT.CreditDebitCardInfo, ENCRYPTION_KEY, USER_ID);
});
it('decrypting valid from, issue no., cardPAN and expiry date', () => {
return expect(utilsStub.decryptDataV3).to.have.been
.callCount(4)
.calledWith(FAKE_ENCRYPTED_DETAILS, ENCRYPTION_KEY, USER_ID)
.calledWith(FAKE_ENCRYPTED_DETAILS, ENCRYPTION_KEY, USER_ID)
.calledWith(FAKE_ENCRYPTED_DETAILS, ENCRYPTION_KEY, USER_ID)
.calledWith(FAKE_ENCRYPTED_DETAILS, ENCRYPTION_KEY, USER_ID);
});
it('returning decrypted details ', () => {
return expect(encryption.decryptCard).to.have.returned(MAX_DECRYPTED_RETURN_OBJECT);
});
});
});
describe('with a failure', () => {
describe('to decrypt the data', () => {
beforeEach(() => {
utilsStub.decryptDataV3
.onCall(0).returns(FAKE_ERROR);
try {
encryption.decryptCard(MIN_ENCRYPTED_ACCOUNT.CreditDebitCardInfo, ENCRYPTION_KEY, USER_ID);
} catch (error) {}
});
it('fails to decrypt cardPAN', () => {
return expect(utilsStub.decryptDataV3).to.have.been
.calledOnce
.calledWith(FAKE_ENCRYPTED_DETAILS, ENCRYPTION_KEY, USER_ID);
});
it('throwing an error', () => {
return expect(encryption.decryptCard).to.have.thrown();
});
});
describe('with an invalid encryption key', () => {
beforeEach(() => {
utilsStub.decryptDataV3
.onCall(0).returns({
info: 'invalid encryption key.',
code: 9});
try {
encryption.decryptCard(MIN_ENCRYPTED_ACCOUNT.CreditDebitCardInfo, ENCRYPTION_KEY, USER_ID);
} catch (error) {}
});
it('fails to decrypt cardPAN', () => {
return expect(utilsStub.decryptDataV3).to.have.been
.calledOnce
.calledWith(FAKE_ENCRYPTED_DETAILS, ENCRYPTION_KEY, USER_ID);
});
it('throwing an error', () => {
return expect(encryption.decryptCard).to.have.returned(null);
});
});
describe('to send invalid data to decrypt', () => {
beforeEach(() => {
try {
encryption.decryptCard(INVALID_ACCOUNT.CreditDebitCardInfo, ENCRYPTION_KEY, USER_ID);
} catch (error) {}
});
it('does not try to decrypt anything', () => {
return expect(utilsStub.decryptDataV3).to.not.have.been.called;
});
it('throwing an error', () => {
return expect(encryption.decryptCard).to.have.thrown();
});
});
});
});
describe('calls decryptCardMaintainingAccount', () => {
describe('successfully', () => {
describe('with required card fields set', () => {
beforeEach(() => {
encryption.decryptCardMaintainingAccount(MIN_ENCRYPTED_ACCOUNT, ENCRYPTION_KEY, USER_ID);
});
it('decrypting cardPAN and expiry date', () => {
return expect(utilsStub.decryptDataV3).to.have.been
.calledTwice
.calledWith(FAKE_ENCRYPTED_DETAILS, ENCRYPTION_KEY, USER_ID)
.calledWith(FAKE_ENCRYPTED_DETAILS, ENCRYPTION_KEY, USER_ID);
});
it('returning decrypted details ', () => {
return expect(encryption.decryptCardMaintainingAccount).to.have.returned(MIN_DECRYPTED_FULL_ACCOUNT);
});
});
describe('with all fields set', () => {
beforeEach(() => {
encryption.decryptCardMaintainingAccount(MAX_ENCRYPTED_ACCOUNT, ENCRYPTION_KEY, USER_ID);
});
it('decrypting valid from, issue no., cardPAN and expiry date', () => {
return expect(utilsStub.decryptDataV3).to.have.been
.callCount(4)
.calledWith(FAKE_ENCRYPTED_DETAILS, ENCRYPTION_KEY, USER_ID)
.calledWith(FAKE_ENCRYPTED_DETAILS, ENCRYPTION_KEY, USER_ID)
.calledWith(FAKE_ENCRYPTED_DETAILS, ENCRYPTION_KEY, USER_ID)
.calledWith(FAKE_ENCRYPTED_DETAILS, ENCRYPTION_KEY, USER_ID);
});
it('returning decrypted details ', () => {
return expect(encryption.decryptCardMaintainingAccount).to.have.returned(MAX_DECRYPTED_FULL_ACCOUNT);
});
});
});
describe('with wrong key', () => {
it('returns null', () => {
utilsStub.decryptDataV3.onCall(0).returns(
utilsStub.createError(9, 'Decryption error.')
);
return expect(encryption.decryptCardMaintainingAccount(
MIN_ENCRYPTED_ACCOUNT,
'WRONG KEY',
USER_ID
)).to.be.null;
});
});
});
describe('calls encryptCardMaintainingAccount', () => {
describe('successfully', () => {
describe('with required card fields set', () => {
beforeEach(() => {
encryption.encryptCardMaintainingAccount(_.clone(MIN_DATA), ENCRYPTION_KEY, USER_ID);
});
it('encrypting cardPAN and expiry date', () => {
return expect(utilsStub.encryptDataV3).to.have.been
.calledTwice
.calledWith(CARD_PAN, ENCRYPTION_KEY, USER_ID)
.calledWith(CARD_EXPIRY, ENCRYPTION_KEY, USER_ID);
});
it('returning encrypted details ', () => {
return expect(encryption.encryptCardMaintainingAccount).to.have.returned(MIN_ENCRYPTED_FULL_ACCOUNT);
});
});
describe('with all fields set', () => {
beforeEach(() => {
encryption.encryptCardMaintainingAccount(_.clone(MAX_DATA), ENCRYPTION_KEY, USER_ID);
});
it('encrypting valid from, issue no., cardPAN and expiry date', () => {
return expect(utilsStub.encryptDataV3).to.have.been
.callCount(4)
.calledWith(CARD_PAN, ENCRYPTION_KEY, USER_ID)
.calledWith(CARD_EXPIRY, ENCRYPTION_KEY, USER_ID)
.calledWith(CARD_VALID_FROM, ENCRYPTION_KEY, USER_ID)
.calledWith(CARD_ISSUE_NO, ENCRYPTION_KEY, USER_ID);
});
it('returning encrypted details ', () => {
return expect(encryption.encryptCardMaintainingAccount).to.have.returned(MAX_ENCRYPTED_FULL_ACCOUNT);
});
});
});
});
});