Skip to content

Commit

Permalink
Merge pull request #590 from recurly/adds-union-pay
Browse files Browse the repository at this point in the history
Adds union pay
  • Loading branch information
chrissrogers authored Mar 21, 2020
2 parents 279aa17 + 44da9c8 commit bca67e3
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 25 deletions.
63 changes: 59 additions & 4 deletions lib/recurly/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,49 @@ const debug = require('debug')('recurly:validate');
const TYPES = [
{
type: 'discover',
pattern: /^(3[0689]|6011|621094|62[24568]|64[4-9]|65|81[0-7])/,
lengths: [14, 15, 16, 17, 18, 19]
pattern: {
test: (n) => {
const firstEight = parseInt(n.substr(0, 8), 10);
const acceptedRanges = [
[60110000, 60110399],
[60110500, 60110999],
[60112000, 60114999],
[60117400, 60117499],
[60117700, 60117999],
[60118600, 60119999],
[64400000, 65059999],
[65060100, 65060999],
[65061100, 65999999]
];

if (!(/^6[045]/.test(firstEight))) return false;
return validBinRange(acceptedRanges, firstEight);
}
},
lengths: [16, 17, 18, 19]
},
{
type: 'union_pay',
pattern: {
test: (n) => {
const firstEight = parseInt(n.substr(0, 8), 10);
const acceptedRanges = [
[62109400, 62109499],
[62212600, 62292599],
[62400000, 62699999],
[62820000, 62889999],
[81000000, 81099999],
[81100000, 81319999],
[81320000, 81519999],
[81520000, 81639999],
[81640000, 81719999]
];

if (!(/^6[2]/.test(firstEight)) && !(/^8[1]/.test(firstEight))) return false;
return validBinRange(acceptedRanges, firstEight);
}
},
lengths: [16, 17, 18, 19]
},
{
type: 'master',
Expand Down Expand Up @@ -52,6 +93,19 @@ const TYPES = [
}
];

/**
* Validates bin ranges for supported card types
*
* @private
*/
function validBinRange (acceptedRanges, firstEight) {
for (let index = 0; index < acceptedRanges.length; index++) {
const [min, max] = acceptedRanges[index];
if (firstEight <= max && firstEight >= min) return true;
}
return false;
}

/**
* Validation error messages
* @type {String}
Expand Down Expand Up @@ -121,14 +175,15 @@ export function cardType (number, partial = false) {
const str = parseCard(number);
const len = str.length;
const card = find(TYPES, card => card.pattern.test(str) && (partial || ~card.lengths.indexOf(len)));

return card && card.type || 'unknown';
}

/**
* Validates whether an expiry month is present or future.
*
* @param {Numer|String} month The 2 digit month
* @param {Numer|String} year The 2 or 4 digit year
* @param {Number|String} month The 2 digit month
* @param {Number|String} year The 2 or 4 digit year
* @return {Boolean}
*/

Expand Down
5 changes: 4 additions & 1 deletion lib/util/deep-assign.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,8 @@ export default function deepAssign (target, ...sources) {
}

function isAssignableObject (item) {
return typeof item === 'object' && !Array.isArray(item) && !(item instanceof Node);
return item
&& typeof item === 'object'
&& !Array.isArray(item)
&& !(item instanceof Node);
}
47 changes: 27 additions & 20 deletions test/unit/validate.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,40 +39,47 @@ describe('Recurly.validate', function () {
});

it('should parse discover', function () {
assert(recurly.validate.cardType('3050990900242198') === 'discover');
assert(recurly.validate.cardType('36003010814263') === 'discover');
assert(recurly.validate.cardType('6011111111111117') === 'discover');
assert(recurly.validate.cardType('6011000990139424') === 'discover');
assert(recurly.validate.cardType('6229252986142899') === 'discover');
assert(recurly.validate.cardType('8131917256371926354') === 'discover');
assert.strictEqual(recurly.validate.cardType('601099999013942'), 'unknown');
assert.strictEqual(recurly.validate.cardType('6010999990139424'), 'unknown');
assert.strictEqual(recurly.validate.cardType('6011040090139424'), 'unknown');
assert.strictEqual(recurly.validate.cardType('6011000090139424'), 'discover');
assert.strictEqual(recurly.validate.cardType('6011039990139424'), 'discover');
});

it('should parse union_pay', function () {
assert.strictEqual(recurly.validate.cardType('621093991111324'), 'unknown');
assert.strictEqual(recurly.validate.cardType('6210939911113245'), 'unknown');
assert.strictEqual(recurly.validate.cardType('6210950011113245'), 'unknown');
assert.strictEqual(recurly.validate.cardType('6210940011113245'), 'union_pay');
assert.strictEqual(recurly.validate.cardType('6210949911113245'), 'union_pay');
assert.strictEqual(recurly.validate.cardType('8171999927660000'), 'union_pay');
assert.strictEqual(recurly.validate.cardType('8171999900000000021'), 'union_pay');
});

it('should parse mastercard', function () {
assert(recurly.validate.cardType('5454545454545454') === 'master');
assert(recurly.validate.cardType('5555555555554444') === 'master');
assert(recurly.validate.cardType('5555555555554444') === 'master');
assert(recurly.validate.cardType('2222000222222224') === 'master');
assert(recurly.validate.cardType('2720989999999955') === 'master');
assert.strictEqual(recurly.validate.cardType('5454545454545454'), 'master');
assert.strictEqual(recurly.validate.cardType('5555555555554444'), 'master');
assert.strictEqual(recurly.validate.cardType('5555555555554444'), 'master');
assert.strictEqual(recurly.validate.cardType('2222000222222224'), 'master');
assert.strictEqual(recurly.validate.cardType('2720989999999955'), 'master');
});

it('should parse american_express', function () {
var type = recurly.validate.cardType('372546612345678');
assert(type === 'american_express');
assert.strictEqual(recurly.validate.cardType('372546612345678'), 'american_express');
});

it('should parse unknown', function () {
var type = recurly.validate.cardType('867-5309-jenny');
assert(type === 'unknown');
assert.strictEqual(recurly.validate.cardType('867-5309-jenny'), 'unknown');
});

it('should not parse partial numbers', function () {
var type = recurly.validate.cardType('3725');
assert(type === 'unknown');
assert.strictEqual(recurly.validate.cardType('3725'), 'unknown');
assert.strictEqual(recurly.validate.cardType('62109400'), 'unknown');
});

it('should parse partial numbers if instructed', function () {
var type = recurly.validate.cardType('3725', true);
assert(type === 'american_express');
assert.strictEqual(recurly.validate.cardType('3725', true), 'american_express');
assert.strictEqual(recurly.validate.cardType('62109400', true), 'union_pay');
});
});

Expand Down Expand Up @@ -123,5 +130,5 @@ describe('Recurly.validate', function () {
assert(false === recurly.validate.cvv('123f'));
assert(false === recurly.validate.cvv('123456'));
});
})
});
});

0 comments on commit bca67e3

Please sign in to comment.