409 lines
16 KiB
JavaScript
409 lines
16 KiB
JavaScript
|
/* 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);
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
});
|