Skip to content

Commit ee33432

Browse files
brianwhaleyBrian T. Whaley
andauthored
feat(isCreditCard): enhancements (#2008)
Co-authored-by: Brian T. Whaley <brian.t.whaley@aexp.com>
1 parent c1d1b48 commit ee33432

3 files changed

Lines changed: 296 additions & 7 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ Validator | Description
103103
**isBoolean(str [, options])** | check if a string is a boolean.<br/>`options` is an object which defaults to `{ loose: false }`. If loose is is set to false, the validator will strictly match ['true', 'false', '0', '1']. If loose is set to true, the validator will also match 'yes', 'no', and will match a valid boolean string of any case. (eg: ['true', 'True', 'TRUE']).
104104
**isBtcAddress(str)** | check if the string is a valid BTC address.
105105
**isByteLength(str [, options])** | check if the string's length (in UTF-8 bytes) falls in a range.<br/><br/>`options` is an object which defaults to `{min:0, max: undefined}`.
106-
**isCreditCard(str)** | check if the string is a credit card.
106+
**isCreditCard(card, [, options])** | check if the string is a credit card.<br/><br/> options is an optional object that can be supplied with the following key(s): `provider` is an optional key whose value should be a string, and defines the company issuing the credit card. Valid values include `amex` , `dinersclub` , `discover` , `jcb` , `mastercard` , `unionpay` , `visa` or blank will check for any provider.
107107
**isCurrency(str [, options])** | check if the string is a valid currency amount.<br/><br/>`options` is an object which defaults to `{symbol: '$', require_symbol: false, allow_space_after_symbol: false, symbol_after_digits: false, allow_negatives: true, parens_for_negatives: false, negative_sign_before_digits: false, negative_sign_after_digits: false, allow_negative_sign_placeholder: false, thousands_separator: ',', decimal_separator: '.', allow_decimal: true, require_decimal: false, digits_after_decimal: [2], allow_space_after_digits: false}`.<br/>**Note:** The array `digits_after_decimal` is filled with the exact number of digits allowed not a range, for example a range 1 to 3 will be given as [1, 2, 3].
108108
**isDataURI(str)** | check if the string is a [data uri format](https://developer.mozilla.org/en-US/docs/Web/HTTP/data_URIs).
109109
**isDate(input [, options])** | Check if the input is a valid date. e.g. [`2002-07-15`, new Date()].<br/><br/> `options` is an object which can contain the keys `format`, `strictMode` and/or `delimiters`<br/><br/>`format` is a string and defaults to `YYYY/MM/DD`.<br/><br/>`strictMode` is a boolean and defaults to `false`. If `strictMode` is set to true, the validator will reject inputs different from `format`.<br/><br/> `delimiters` is an array of allowed date delimiters and defaults to `['/', '-']`.

src/lib/isCreditCard.js

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,34 @@
11
import assertString from './util/assertString';
22
import isLuhnValid from './isLuhnValid';
33

4+
const cards = {
5+
amex: /^3[47][0-9]{13}$/,
6+
dinersclub: /^3(?:0[0-5]|[68][0-9])[0-9]{11}$/,
7+
discover: /^6(?:011|5[0-9][0-9])[0-9]{12,15}$/,
8+
jcb: /^(?:2131|1800|35\d{3})\d{11}$/,
9+
mastercard: /^5[1-5][0-9]{2}|(222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}$/, // /^[25][1-7][0-9]{14}$/;
10+
unionpay: /^(6[27][0-9]{14}|^(81[0-9]{14,17}))$/,
11+
visa: /^(?:4[0-9]{12})(?:[0-9]{3,6})?$/,
12+
};
413
/* eslint-disable max-len */
5-
const creditCard = /^(?:4[0-9]{12}(?:[0-9]{3,6})?|5[1-5][0-9]{14}|(222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}|6(?:011|5[0-9][0-9])[0-9]{12,15}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11}|6[27][0-9]{14}|^(81[0-9]{14,17}))$/;
14+
const allCards = /^(?:4[0-9]{12}(?:[0-9]{3,6})?|5[1-5][0-9]{14}|(222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}|6(?:011|5[0-9][0-9])[0-9]{12,15}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11}|6[27][0-9]{14}|^(81[0-9]{14,17}))$/;
615
/* eslint-enable max-len */
716

8-
export default function isCreditCard(str) {
9-
assertString(str);
10-
const sanitized = str.replace(/[- ]+/g, '');
11-
if (!creditCard.test(sanitized)) {
17+
export default function isCreditCard(card, options = {}) {
18+
assertString(card);
19+
const { provider } = options;
20+
const sanitized = card.replace(/[- ]+/g, '');
21+
if (provider && provider.toLowerCase() in cards) {
22+
// specific provider in the list
23+
if (!(cards[provider.toLowerCase()].test(sanitized))) {
24+
return false;
25+
}
26+
} else if (provider && !(provider.toLowerCase() in cards)) {
27+
/* specific provider not in the list */
28+
throw new Error(`${provider} is not a valid credit card provider.`);
29+
} else if (!(allCards.test(sanitized))) {
30+
// no specific provider
1231
return false;
1332
}
14-
return isLuhnValid(str);
33+
return isLuhnValid(card);
1534
}

test/validators.js

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5160,6 +5160,276 @@ describe('Validators', () => {
51605160
});
51615161
});
51625162

5163+
5164+
it('should validate credit cards without a proper provider', () => {
5165+
test({
5166+
validator: 'isCreditCard',
5167+
args: [{ provider: 'Plorf' }],
5168+
error: [
5169+
'foo',
5170+
// valid cc #
5171+
'375556917985515',
5172+
'4716-2210-5188-5662',
5173+
'375556917985515999999993',
5174+
'6234917882863855suffix',
5175+
],
5176+
});
5177+
});
5178+
5179+
5180+
it('should validate AmEx provided credit cards', () => {
5181+
test({
5182+
validator: 'isCreditCard',
5183+
args: [{ provider: 'AmEx' }],
5184+
valid: [
5185+
'375556917985515',
5186+
],
5187+
invalid: [
5188+
'foo',
5189+
'2222155765072228',
5190+
'2225855203075256',
5191+
'2720428011723762',
5192+
'2718760626256570',
5193+
'36050234196908',
5194+
'375556917985515999999993',
5195+
'4716461583322103',
5196+
'4716-2210-5188-5662',
5197+
'4716989580001715211',
5198+
'4929 7226 5379 7141',
5199+
'5398228707871527',
5200+
'6234917882863855suffix',
5201+
'6283875070985593',
5202+
'6263892624162870',
5203+
'6234917882863855',
5204+
'6234698580215388',
5205+
'6226050967750613',
5206+
'6246281879460688',
5207+
'6283875070985593',
5208+
'6765780016990268',
5209+
'8171999927660000',
5210+
'8171999900000000021',
5211+
],
5212+
});
5213+
});
5214+
5215+
5216+
it('should validate Diners Club provided credit cards', () => {
5217+
test({
5218+
validator: 'isCreditCard',
5219+
args: [{ provider: 'DinersClub' }],
5220+
valid: [
5221+
'36050234196908',
5222+
],
5223+
invalid: [
5224+
'foo',
5225+
'2222155765072228',
5226+
'2225855203075256',
5227+
'2720428011723762',
5228+
'2718760626256570',
5229+
'375556917985515',
5230+
'375556917985515999999993',
5231+
'4716461583322103',
5232+
'4716-2210-5188-5662',
5233+
'4716989580001715211',
5234+
'4929 7226 5379 7141',
5235+
'5398228707871527',
5236+
'6234917882863855suffix',
5237+
'6283875070985593',
5238+
'6263892624162870',
5239+
'6234917882863855',
5240+
'6234698580215388',
5241+
'6226050967750613',
5242+
'6246281879460688',
5243+
'6283875070985593',
5244+
'6765780016990268',
5245+
'8171999927660000',
5246+
'8171999900000000021',
5247+
],
5248+
});
5249+
});
5250+
5251+
it('should validate Discover provided credit cards', () => {
5252+
test({
5253+
validator: 'isCreditCard',
5254+
args: [{ provider: 'Discover' }],
5255+
valid: [
5256+
'6011111111111117',
5257+
'6011000990139424',
5258+
],
5259+
invalid: [
5260+
'foo',
5261+
'2222155765072228',
5262+
'2225855203075256',
5263+
'2720428011723762',
5264+
'2718760626256570',
5265+
'36050234196908',
5266+
'375556917985515',
5267+
'375556917985515999999993',
5268+
'4716461583322103',
5269+
'4716-2210-5188-5662',
5270+
'4716989580001715211',
5271+
'4929 7226 5379 7141',
5272+
'5398228707871527',
5273+
'6234917882863855suffix',
5274+
'6283875070985593',
5275+
'6263892624162870',
5276+
'6234917882863855',
5277+
'6234698580215388',
5278+
'6226050967750613',
5279+
'6246281879460688',
5280+
'6283875070985593',
5281+
'6765780016990268',
5282+
'8171999927660000',
5283+
'8171999900000000021',
5284+
],
5285+
});
5286+
});
5287+
5288+
it('should validate JCB provided credit cards', () => {
5289+
test({
5290+
validator: 'isCreditCard',
5291+
args: [{ provider: 'JCB' }],
5292+
valid: [
5293+
'3530111333300000',
5294+
'3566002020360505',
5295+
],
5296+
invalid: [
5297+
'foo',
5298+
'2222155765072228',
5299+
'2225855203075256',
5300+
'2720428011723762',
5301+
'2718760626256570',
5302+
'36050234196908',
5303+
'375556917985515',
5304+
'375556917985515999999993',
5305+
'4716461583322103',
5306+
'4716-2210-5188-5662',
5307+
'4716989580001715211',
5308+
'4929 7226 5379 7141',
5309+
'5398228707871527',
5310+
'6234917882863855suffix',
5311+
'6283875070985593',
5312+
'6263892624162870',
5313+
'6234917882863855',
5314+
'6234698580215388',
5315+
'6226050967750613',
5316+
'6246281879460688',
5317+
'6283875070985593',
5318+
'6765780016990268',
5319+
'8171999927660000',
5320+
'8171999900000000021',
5321+
],
5322+
});
5323+
});
5324+
5325+
5326+
it('should validate Mastercard provided credit cards', () => {
5327+
test({
5328+
validator: 'isCreditCard',
5329+
args: [{ provider: 'Mastercard' }],
5330+
valid: [
5331+
'2222155765072228',
5332+
'2225855203075256',
5333+
'2718760626256570',
5334+
'2720428011723762',
5335+
'5398228707871527',
5336+
],
5337+
invalid: [
5338+
'foo',
5339+
'36050234196908',
5340+
'375556917985515',
5341+
'375556917985515999999993',
5342+
'4716461583322103',
5343+
'4716-2210-5188-5662',
5344+
'4716989580001715211',
5345+
'4929 7226 5379 7141',
5346+
'6234917882863855suffix',
5347+
'6283875070985593',
5348+
'6263892624162870',
5349+
'6234917882863855',
5350+
'6234698580215388',
5351+
'6226050967750613',
5352+
'6246281879460688',
5353+
'6283875070985593',
5354+
'6765780016990268',
5355+
'8171999927660000',
5356+
'8171999900000000021',
5357+
],
5358+
});
5359+
});
5360+
5361+
5362+
it('should validate Union Pay provided credit cards', () => {
5363+
test({
5364+
validator: 'isCreditCard',
5365+
args: [{ provider: 'UnionPay' }],
5366+
valid: [
5367+
'6226050967750613',
5368+
'6234917882863855',
5369+
'6234698580215388',
5370+
'6246281879460688',
5371+
'6263892624162870',
5372+
'6283875070985593',
5373+
'6765780016990268',
5374+
'8171999927660000',
5375+
'8171999900000000021',
5376+
],
5377+
invalid: [
5378+
'foo',
5379+
'2222155765072228',
5380+
'2225855203075256',
5381+
'2720428011723762',
5382+
'2718760626256570',
5383+
'36050234196908',
5384+
'375556917985515',
5385+
'375556917985515999999993',
5386+
'4716461583322103',
5387+
'4716-2210-5188-5662',
5388+
'4716989580001715211',
5389+
'4929 7226 5379 7141',
5390+
'5398228707871527',
5391+
'6234917882863855suffix',
5392+
],
5393+
});
5394+
});
5395+
5396+
5397+
it('should validate Visa provided credit cards', () => {
5398+
test({
5399+
validator: 'isCreditCard',
5400+
args: [{ provider: 'Visa' }],
5401+
valid: [
5402+
'4716-2210-5188-5662',
5403+
'4716461583322103',
5404+
'4716989580001715211',
5405+
'4929 7226 5379 7141',
5406+
],
5407+
invalid: [
5408+
'foo',
5409+
'2222155765072228',
5410+
'2225855203075256',
5411+
'2720428011723762',
5412+
'2718760626256570',
5413+
'36050234196908',
5414+
'375556917985515',
5415+
'375556917985515999999993',
5416+
'5398228707871527',
5417+
'6234917882863855suffix',
5418+
'6283875070985593',
5419+
'6263892624162870',
5420+
'6234917882863855',
5421+
'6234698580215388',
5422+
'6226050967750613',
5423+
'6246281879460688',
5424+
'6283875070985593',
5425+
'6765780016990268',
5426+
'8171999927660000',
5427+
'8171999900000000021',
5428+
],
5429+
});
5430+
});
5431+
5432+
51635433
it('should validate identity cards', () => {
51645434
const fixtures = [
51655435
{

0 commit comments

Comments
 (0)