Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

credit-card-type

Package Overview
Dependencies
Maintainers
1
Versions
31
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

credit-card-type - npm Package Compare versions

Comparing version 7.1.0 to 8.0.0

9

CHANGELOG.md

@@ -0,1 +1,10 @@

8.0.0
=====
- Improve pattern recognition for card types
*Breaking Changes*
- When adding or updating cards, this module no longer uses an `exactPattern` and `prefixPattern` model. Instead, it takes an array of patterns. See https://github.com/braintree/credit-card-type#pattern-detection for details.
7.1.0

@@ -2,0 +11,0 @@ =====

425

dist/js/app.built.js

@@ -36,19 +36,9 @@ !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.creditCardType=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){

function clone(originalObject, persistPatterns) {
var dupe, prefixPattern, exactPattern;
function clone(originalObject) {
var dupe;
if (!originalObject) { return null; }
prefixPattern = originalObject.prefixPattern;
exactPattern = originalObject.exactPattern;
dupe = JSON.parse(JSON.stringify(originalObject));
if (persistPatterns) {
dupe.prefixPattern = prefixPattern;
dupe.exactPattern = exactPattern;
} else {
delete dupe.prefixPattern;
delete dupe.exactPattern;
}
return dupe;

@@ -62,9 +52,5 @@ }

type: VISA,
prefixPattern: /^4/,
exactPattern: new RegExp('^' +
'4' +
'(?!' +
'31274|51416|57393|0117[89]|38935|5763[12]' + // Elo cards
')\\d{5,}' +
'$'),
patterns: [
4
],
gaps: [4, 8, 12],

@@ -81,4 +67,10 @@ lengths: [16, 18, 19],

type: MASTERCARD,
prefixPattern: /^(5|5[1-5]|2|22|222|222[1-9]|2[3-6]|27|27[0-2]|2720)$/,
exactPattern: /^(5[1-5]|222[1-9]|22[3-9]|2[3-6]|27[0-1]|2720)\d*$/,
patterns: [
[51, 55],
[2221, 2229],
[223, 229],
[23, 26],
[270, 271],
2720
],
gaps: [4, 8, 12],

@@ -95,5 +87,6 @@ lengths: [16],

type: AMERICAN_EXPRESS,
prefixPattern: /^(3|34|37)$/,
exactPattern: /^3[47]\d*$/,
isAmex: true,
patterns: [
34,
37
],
gaps: [4, 10],

@@ -110,4 +103,8 @@ lengths: [15],

type: DINERS_CLUB,
prefixPattern: /^(3|3[0689]|30[0-5])$/,
exactPattern: /^3(0[0-5]|[689])\d*$/,
patterns: [
[300, 305],
36,
38,
39
],
gaps: [4, 10],

@@ -124,33 +121,7 @@ lengths: [14, 16, 19],

type: DISCOVER,
prefixPattern: /^(6|60|601|6011|65|65\d{1,4}|64|64[4-9])$/,
exactPattern: new RegExp('^(' +
'6011' +
'|' +
'65' +
'(?!' + // Elo cards
'003[1-3]' +
'|' +
'003[5-9]|004\\d|005[0-1]' +
'|' +
'040[5-9]|04[1-3]\\d' +
'|' +
'048[5-9]|049\\d|05[0-2]\\d|053[0-8]' +
'|' +
'054[1-9]|05[5-8]\\d|059[0-8]' +
'|' +
'070\\d|071[0-8]' +
'|' +
'072[0-7]' +
'|' +
'090[1-9]|09[1-6]\\d|097[0-8]' +
'|' +
'165[2-9]|16[6-7]\\d' +
'|' +
'50[0-1]\\d' +
'|' +
'502[1-9]|50[3-4]\\d|505[0-8]' +
')\\d{4}' +
'|' +
'64[4-9]' +
')\\d*$'),
patterns: [
6011,
[644, 649],
65
],
gaps: [4, 8, 12],

@@ -167,4 +138,7 @@ lengths: [16, 19],

type: JCB,
prefixPattern: /^(2|21|213|2131|1|18|180|1800|3|35)$/,
exactPattern: /^(2131|1800|35)\d*$/,
patterns: [
2131,
1800,
[3528, 3589]
],
gaps: [4, 8, 12],

@@ -181,26 +155,24 @@ lengths: [16, 17, 18, 19],

type: UNIONPAY,
prefixPattern: /^((6|62|62\d|(621(?!83|88|98|99))|622(?!06)|627[0267]\d?|628(?!0|1)|629[1,2])|622018)$/,
exactPattern: new RegExp('^(' +
'(' +
'620' +
'|' +
'(621(?!83|88|98|99))' +
'|' +
'622(?!06|018)' +
'|' +
'62[3-6]' +
'|' +
'627[026]' +
'|' +
'6277(?!80)\\d{2}' + // Elo card
'|' +
'628(?!0|1)' +
'|' +
'629[12]' +
')\\d*' +
'|' +
'622018\\d{12}' +
')$'),
patterns: [
620,
[624, 626],
[62100, 62182],
[62184, 62187],
[62185, 62197],
[62200, 62205],
[622010, 622999],
622018,
[622019, 622999],
[62207, 62209],
[622126, 622925],
[623, 626],
6270,
6272,
6276,
[627700, 627779],
[627781, 627799],
[6282, 6289],
6291,
6292
],
gaps: [4, 8, 12],

@@ -217,23 +189,11 @@ lengths: [16, 17, 18, 19],

type: MAESTRO,
prefixPattern: /^(5|5[06-9]|6\d*)$/,
exactPattern: new RegExp('^(' +
'5[6-9]' +
'|' +
'50' +
'(?!' + // Elo card ranges
'6699|067[0-6][0-9]' +
'|' +
'677[0-8]' +
'|' +
'9[0-9][0-9][0-9]' +
')\\d{4}' +
'|' +
'67' +
'|' +
'63' +
'(?!' + // More Elo card ranges
'6297|6368' +
')\\d{4}' +
')\\d*$'
),
patterns: [
493698,
[500000, 506698],
[506779, 508999],
[56, 59],
63,
67,
6
],
gaps: [4, 8, 12],

@@ -250,105 +210,29 @@ lengths: [12, 13, 14, 15, 16, 17, 18, 19],

type: ELO,
prefixPattern: new RegExp('^(' +
'[4-6]' +
'|' +
'4[035]|4[035]1' +
'|' +
'4011|40117|40117[89]' +
'|' +
'4312|43127|431274' +
'|' +
'438|4389|43893|438935' +
'|' +
'4514|45141|451416' +
'|' +
'457|457[36]|45739|45763|457393|45763[12]' +
'|' +
'50|50[69]' +
'|' +
'506[6-7]|50669|5067[0-7]|5067[0-6][0-9]|50677[0-8]' +
'|' +
'509[0-9]|509[0-9][0-9]|509[0-9][0-9][0-9]' +
'|' +
'6[235]|627|636|65[015]' +
'|' +
'6277|62778|627780' +
'|' +
'636[23]|63629|636297|63636|636368' +
'|' +
'650[0479]' +
'|' +
'6500[3-5]|65003[1-3]|65003[5-9]|65004[0-9]65005[01]' +
'|' +
'6504[0-3]|65040[5-9]|65041[0-9]' +
'|' +
'6505[4-9]|65054[1-9]|6505[5-8][0-9]|65059[0-8]' +
'|' +
'6507[0-2]|65070[0-9]|65071[0-8]|65072[0-7]' +
'|' +
'6509[0-7]|65090[1-9]|6509[1-6][0-9]|65097[0-8]' +
'|' +
'6516|6516[5-7]|65165[2-9]|6516[6-7][0-9]' +
'|' +
'6550|6550[0-5]|6550[01][0-9]|65502[1-9]|6550[3-4][0-9]|65505[0-8]' +
')$'),
exactPattern: new RegExp('^(' +
// Elo only ranges
'4(31274|51416|57393)' +
'|' +
'50(' +
'4175' +
'|' +
'6699|67[0-6][0-9]|677[0-8]' + // 506699-506778
'|' +
'9[0-9][0-9][0-9]' + // 509000-509999
')' +
'|' +
'627780' +
'|' +
'636(297|368)' +
'|' +
// Dual Branded with Visa
'4(0117[89]|38935|5763[12])' +
'|' +
// Dual Branded with Discover
'65(' +
'003[1-3]' + // 650031-650033
'|' +
'003[5-9]|004\\d|005[0-1]' + // 650035-650051
'|' +
'040[5-9]|04[1-3]\\d' + // 650405-650439
'|' +
'048[5-9]|049\\d|05[0-2]\\d|053[0-8]' + // 650485-650538
'|' +
'054[1-9]|05[5-8]\\d|059[0-8]' + // 650541-650598
'|' +
'070[0-9]|071[0-8]' + // 650700-650718
'|' +
'072[0-7]' + // 650720-650727
'|' +
'090[1-9]|09[1-6][0-9]|097[0-8]' + // 650901-650978
'|' +
'165[2-9]|16[6-7][0-9]' + // 651652-651679
'|' +
'50[0-1][0-9]' + // 655000-655019
'|' +
'502[1-9]|50[3-4][0-9]|505[0-8]' + // 655021-655058
')' +
')\\d*$'),
patterns: [
401178,
401179,
438935,
457631,
457632,
431274,
451416,
457393,
504175,
[506699, 506778],
[509000, 509999],
627780,
636297,
636368,
[650031, 650033],
[650035, 650051],
[650405, 650439],
[650485, 650538],
[650541, 650598],
[650700, 650718],
[650720, 650727],
[650901, 650978],
[651652, 651679],
[655000, 655019],
[655021, 655058]
],
gaps: [4, 8, 12],

@@ -365,4 +249,5 @@ lengths: [16],

type: MIR,
prefixPattern: /^(2|22|220|220[0-4])$/,
exactPattern: /^(220[0-4])\d*$/,
patterns: [
[2200, 2204]
],
gaps: [4, 8, 12],

@@ -380,30 +265,124 @@ lengths: [16, 17, 18, 19],

function isValidInputType(cardNumber) {
return typeof cardNumber === 'string' || cardNumber instanceof String;
}
function hasEnoughResultsToDetermineBestMatch(results) {
var numberOfResultsWithMaxStrengthProperty = results.filter(function (result) {
return result.matchStrength;
}).length;
// if all possible results have a maxStrength property
// that means the card number is sufficiently long
// enough to determine conclusively what the type is
return numberOfResultsWithMaxStrengthProperty > 0 &&
numberOfResultsWithMaxStrengthProperty === results.length;
}
function findBestMatch(results) {
if (!hasEnoughResultsToDetermineBestMatch(results)) {
return;
}
return results.reduce(function (bestMatch, result) { // eslint-disable-line consistent-return
if (!bestMatch) {
return result;
}
// if the current best match pattern is less specific
// than this result, set the result as the new best match
if (bestMatch.matchStrength < result.matchStrength) {
return result;
}
return bestMatch;
});
}
function getAllCardTypes() {
return testOrder.map(function (type) {
return clone(findType(type));
});
}
function creditCardType(cardNumber) {
var type, value, i;
var prefixResults = [];
var exactResults = [];
var bestMatch;
var results = [];
if (!(typeof cardNumber === 'string' || cardNumber instanceof String)) {
if (!isValidInputType(cardNumber)) {
return [];
}
for (i = 0; i < testOrder.length; i++) {
type = testOrder[i];
value = findType(type);
if (cardNumber.length === 0) {
return getAllCardTypes();
}
if (cardNumber.length === 0) {
prefixResults.push(clone(value));
testOrder.forEach(function (type) {
var cardConfiguration = findType(type);
loopOverCardPatterns(cardNumber, cardConfiguration, results);
});
bestMatch = findBestMatch(results);
if (bestMatch) {
return [bestMatch];
}
return results;
}
function loopOverCardPatterns(cardNumber, cardConfiguration, results) {
var i, pattern, patternLength, clonedCardConfiguration;
for (i = 0; i < cardConfiguration.patterns.length; i++) {
pattern = cardConfiguration.patterns[i];
if (!matches(cardNumber, pattern)) {
continue;
}
if (value.exactPattern.test(cardNumber)) {
exactResults.push(clone(value));
} else if (value.prefixPattern.test(cardNumber)) {
prefixResults.push(clone(value));
clonedCardConfiguration = clone(cardConfiguration);
if (Array.isArray(pattern)) {
patternLength = String(pattern[0]).length;
} else {
patternLength = String(pattern).length;
}
if (cardNumber.length >= patternLength) {
clonedCardConfiguration.matchStrength = patternLength;
}
results.push(clonedCardConfiguration);
break;
}
}
return exactResults.length ? exactResults : prefixResults;
function matches(cardNumber, pattern) {
if (Array.isArray(pattern)) {
return matchesRange(cardNumber, pattern[0], pattern[1]);
}
return matchesPattern(cardNumber, pattern);
}
function matchesPattern(cardNumber, pattern) {
pattern = String(pattern);
return pattern.substring(0, cardNumber.length) === cardNumber.substring(0, pattern.length);
}
// Adapted from https://github.com/polvo-labs/card-type/blob/aaab11f80fa1939bccc8f24905a06ae3cd864356/src/cardType.js#L37-L42
function matchesRange(cardNumber, min, max) {
var maxLengthToCheck = String(min).length;
var substr = cardNumber.substr(0, maxLengthToCheck);
var integerRepresentationOfCardNumber = parseInt(substr, 10);
min = parseInt(String(min).substr(0, substr.length), 10);
max = parseInt(String(max).substr(0, substr.length), 10);
return integerRepresentationOfCardNumber >= min && integerRepresentationOfCardNumber <= max;
}
creditCardType.getTypeInfo = function (type) {

@@ -410,0 +389,0 @@ return clone(findType(type));

@@ -1,1 +0,1 @@

!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;"undefined"!=typeof window?t=window:"undefined"!=typeof global?t=global:"undefined"!=typeof self&&(t=self),t.creditCardType=e()}}(function(){return function e(t,n,r){function a(p,d){if(!n[p]){if(!t[p]){var o="function"==typeof require&&require;if(!d&&o)return o(p,!0);if(i)return i(p,!0);var s=new Error("Cannot find module '"+p+"'");throw s.code="MODULE_NOT_FOUND",s}var c=n[p]={exports:{}};t[p][0].call(c.exports,function(e){var n=t[p][1][e];return a(n?n:e)},c,c.exports,e,t,n,r)}return n[p].exports}for(var i="function"==typeof require&&require,p=0;p<r.length;p++)a(r[p]);return a}({1:[function(e,t,n){"use strict";function r(e,t){var n,r,a;return e?(r=e.prefixPattern,a=e.exactPattern,n=JSON.parse(JSON.stringify(e)),t?(n.prefixPattern=r,n.exactPattern=a):(delete n.prefixPattern,delete n.exactPattern),n):null}function a(e){return s[e]||o[e]}function i(e){var t,n,i,p=[],o=[];if(!("string"==typeof e||e instanceof String))return[];for(i=0;i<d.length;i++)t=d[i],n=a(t),0!==e.length?n.exactPattern.test(e)?o.push(r(n)):n.prefixPattern.test(e)&&p.push(r(n)):p.push(r(n));return o.length?o:p}function p(e,t){var n=d.indexOf(e);if(!t&&n===-1)throw new Error('"'+e+'" is not a supported card type.');return n}var d,o={},s={},c="visa",f="mastercard",u="american-express",y="diners-club",x="discover",g="elo",l="jcb",P="unionpay",h="maestro",E="mir",m="CVV",C="CID",v="CVC",w="CVN",$="CVP2",T="CVE",R=[c,f,u,y,x,l,P,h,g,E];d=r(R),o[c]={niceType:"Visa",type:c,prefixPattern:/^4/,exactPattern:new RegExp("^4(?!31274|51416|57393|0117[89]|38935|5763[12])\\d{5,}$"),gaps:[4,8,12],lengths:[16,18,19],code:{name:m,size:3}},o[f]={niceType:"Mastercard",type:f,prefixPattern:/^(5|5[1-5]|2|22|222|222[1-9]|2[3-6]|27|27[0-2]|2720)$/,exactPattern:/^(5[1-5]|222[1-9]|22[3-9]|2[3-6]|27[0-1]|2720)\d*$/,gaps:[4,8,12],lengths:[16],code:{name:v,size:3}},o[u]={niceType:"American Express",type:u,prefixPattern:/^(3|34|37)$/,exactPattern:/^3[47]\d*$/,isAmex:!0,gaps:[4,10],lengths:[15],code:{name:C,size:4}},o[y]={niceType:"Diners Club",type:y,prefixPattern:/^(3|3[0689]|30[0-5])$/,exactPattern:/^3(0[0-5]|[689])\d*$/,gaps:[4,10],lengths:[14,16,19],code:{name:m,size:3}},o[x]={niceType:"Discover",type:x,prefixPattern:/^(6|60|601|6011|65|65\d{1,4}|64|64[4-9])$/,exactPattern:new RegExp("^(6011|65(?!003[1-3]|003[5-9]|004\\d|005[0-1]|040[5-9]|04[1-3]\\d|048[5-9]|049\\d|05[0-2]\\d|053[0-8]|054[1-9]|05[5-8]\\d|059[0-8]|070\\d|071[0-8]|072[0-7]|090[1-9]|09[1-6]\\d|097[0-8]|165[2-9]|16[6-7]\\d|50[0-1]\\d|502[1-9]|50[3-4]\\d|505[0-8])\\d{4}|64[4-9])\\d*$"),gaps:[4,8,12],lengths:[16,19],code:{name:C,size:3}},o[l]={niceType:"JCB",type:l,prefixPattern:/^(2|21|213|2131|1|18|180|1800|3|35)$/,exactPattern:/^(2131|1800|35)\d*$/,gaps:[4,8,12],lengths:[16,17,18,19],code:{name:m,size:3}},o[P]={niceType:"UnionPay",type:P,prefixPattern:/^((6|62|62\d|(621(?!83|88|98|99))|622(?!06)|627[0267]\d?|628(?!0|1)|629[1,2])|622018)$/,exactPattern:new RegExp("^((620|(621(?!83|88|98|99))|622(?!06|018)|62[3-6]|627[026]|6277(?!80)\\d{2}|628(?!0|1)|629[12])\\d*|622018\\d{12})$"),gaps:[4,8,12],lengths:[16,17,18,19],code:{name:w,size:3}},o[h]={niceType:"Maestro",type:h,prefixPattern:/^(5|5[06-9]|6\d*)$/,exactPattern:new RegExp("^(5[6-9]|50(?!6699|067[0-6][0-9]|677[0-8]|9[0-9][0-9][0-9])\\d{4}|67|63(?!6297|6368)\\d{4})\\d*$"),gaps:[4,8,12],lengths:[12,13,14,15,16,17,18,19],code:{name:v,size:3}},o[g]={niceType:"Elo",type:g,prefixPattern:new RegExp("^([4-6]|4[035]|4[035]1|4011|40117|40117[89]|4312|43127|431274|438|4389|43893|438935|4514|45141|451416|457|457[36]|45739|45763|457393|45763[12]|50|50[69]|506[6-7]|50669|5067[0-7]|5067[0-6][0-9]|50677[0-8]|509[0-9]|509[0-9][0-9]|509[0-9][0-9][0-9]|6[235]|627|636|65[015]|6277|62778|627780|636[23]|63629|636297|63636|636368|650[0479]|6500[3-5]|65003[1-3]|65003[5-9]|65004[0-9]65005[01]|6504[0-3]|65040[5-9]|65041[0-9]|6505[4-9]|65054[1-9]|6505[5-8][0-9]|65059[0-8]|6507[0-2]|65070[0-9]|65071[0-8]|65072[0-7]|6509[0-7]|65090[1-9]|6509[1-6][0-9]|65097[0-8]|6516|6516[5-7]|65165[2-9]|6516[6-7][0-9]|6550|6550[0-5]|6550[01][0-9]|65502[1-9]|6550[3-4][0-9]|65505[0-8])$"),exactPattern:new RegExp("^(4(31274|51416|57393)|50(4175|6699|67[0-6][0-9]|677[0-8]|9[0-9][0-9][0-9])|627780|636(297|368)|4(0117[89]|38935|5763[12])|65(003[1-3]|003[5-9]|004\\d|005[0-1]|040[5-9]|04[1-3]\\d|048[5-9]|049\\d|05[0-2]\\d|053[0-8]|054[1-9]|05[5-8]\\d|059[0-8]|070[0-9]|071[0-8]|072[0-7]|090[1-9]|09[1-6][0-9]|097[0-8]|165[2-9]|16[6-7][0-9]|50[0-1][0-9]|502[1-9]|50[3-4][0-9]|505[0-8]))\\d*$"),gaps:[4,8,12],lengths:[16],code:{name:T,size:3}},o[E]={niceType:"Mir",type:E,prefixPattern:/^(2|22|220|220[0-4])$/,exactPattern:/^(220[0-4])\d*$/,gaps:[4,8,12],lengths:[16,17,18,19],code:{name:$,size:3}},i.getTypeInfo=function(e){return r(a(e))},i.removeCard=function(e){var t=p(e);d.splice(t,1)},i.addCard=function(e){var t=p(e.type,!0);s[e.type]=e,t===-1&&d.push(e.type)},i.updateCard=function(e,t){var n,a=s[e]||o[e];if(!a)throw new Error('"'+e+'" is not a recognized type. Use `addCard` instead.');if(t.type&&a.type!==t.type)throw new Error("Cannot overwrite type parameter.");n=r(a,!0),Object.keys(n).forEach(function(e){t[e]&&(n[e]=t[e])}),s[n.type]=n},i.changeOrder=function(e,t){var n=p(e);d.splice(n,1),d.splice(t,0,e)},i.resetModifications=function(){d=r(R),s={}},i.types={VISA:c,MASTERCARD:f,AMERICAN_EXPRESS:u,DINERS_CLUB:y,DISCOVER:x,JCB:l,UNIONPAY:P,MAESTRO:h,ELO:g,MIR:E},t.exports=i},{}]},{},[1])(1)});
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var n;"undefined"!=typeof window?n=window:"undefined"!=typeof global?n=global:"undefined"!=typeof self&&(n=self),n.creditCardType=e()}}(function(){return function e(n,t,r){function i(s,o){if(!t[s]){if(!n[s]){var p="function"==typeof require&&require;if(!o&&p)return p(s,!0);if(a)return a(s,!0);var c=new Error("Cannot find module '"+s+"'");throw c.code="MODULE_NOT_FOUND",c}var u=t[s]={exports:{}};n[s][0].call(u.exports,function(e){var t=n[s][1][e];return i(t?t:e)},u,u.exports,e,n,t,r)}return t[s].exports}for(var a="function"==typeof require&&require,s=0;s<r.length;s++)i(r[s]);return i}({1:[function(e,n,t){"use strict";function r(e){var n;return e?n=JSON.parse(JSON.stringify(e)):null}function i(e){return m[e]||h[e]}function a(e){return"string"==typeof e||e instanceof String}function s(e){var n=e.filter(function(e){return e.matchStrength}).length;return n>0&&n===e.length}function o(e){if(s(e))return e.reduce(function(e,n){return e?e.matchStrength<n.matchStrength?n:e:n})}function p(){return l.map(function(e){return r(i(e))})}function c(e){var n,t=[];return a(e)?0===e.length?p():(l.forEach(function(n){var r=i(n);u(e,r,t)}),n=o(t),n?[n]:t):[]}function u(e,n,t){var i,a,s,o;for(i=0;i<n.patterns.length;i++)if(a=n.patterns[i],f(e,a)){o=r(n),s=Array.isArray(a)?String(a[0]).length:String(a).length,e.length>=s&&(o.matchStrength=s),t.push(o);break}}function f(e,n){return Array.isArray(n)?d(e,n[0],n[1]):g(e,n)}function g(e,n){return n=String(n),n.substring(0,e.length)===e.substring(0,n.length)}function d(e,n,t){var r=String(n).length,i=e.substr(0,r),a=parseInt(i,10);return n=parseInt(String(n).substr(0,i.length),10),t=parseInt(String(t).substr(0,i.length),10),a>=n&&a<=t}function y(e,n){var t=l.indexOf(e);if(!n&&t===-1)throw new Error('"'+e+'" is not a supported card type.');return t}var l,h={},m={},v="visa",C="mastercard",S="american-express",E="diners-club",T="discover",b="elo",w="jcb",A="unionpay",O="maestro",z="mir",I="CVV",x="CID",M="CVC",N="CVN",V="CVP2",D="CVE",R=[v,C,S,E,T,w,A,O,b,z];l=r(R),h[v]={niceType:"Visa",type:v,patterns:[4],gaps:[4,8,12],lengths:[16,18,19],code:{name:I,size:3}},h[C]={niceType:"Mastercard",type:C,patterns:[[51,55],[2221,2229],[223,229],[23,26],[270,271],2720],gaps:[4,8,12],lengths:[16],code:{name:M,size:3}},h[S]={niceType:"American Express",type:S,patterns:[34,37],gaps:[4,10],lengths:[15],code:{name:x,size:4}},h[E]={niceType:"Diners Club",type:E,patterns:[[300,305],36,38,39],gaps:[4,10],lengths:[14,16,19],code:{name:I,size:3}},h[T]={niceType:"Discover",type:T,patterns:[6011,[644,649],65],gaps:[4,8,12],lengths:[16,19],code:{name:x,size:3}},h[w]={niceType:"JCB",type:w,patterns:[2131,1800,[3528,3589]],gaps:[4,8,12],lengths:[16,17,18,19],code:{name:I,size:3}},h[A]={niceType:"UnionPay",type:A,patterns:[620,[624,626],[62100,62182],[62184,62187],[62185,62197],[62200,62205],[622010,622999],622018,[622019,622999],[62207,62209],[622126,622925],[623,626],6270,6272,6276,[627700,627779],[627781,627799],[6282,6289],6291,6292],gaps:[4,8,12],lengths:[16,17,18,19],code:{name:N,size:3}},h[O]={niceType:"Maestro",type:O,patterns:[493698,[5e5,506698],[506779,508999],[56,59],63,67,6],gaps:[4,8,12],lengths:[12,13,14,15,16,17,18,19],code:{name:M,size:3}},h[b]={niceType:"Elo",type:b,patterns:[401178,401179,438935,457631,457632,431274,451416,457393,504175,[506699,506778],[509e3,509999],627780,636297,636368,[650031,650033],[650035,650051],[650405,650439],[650485,650538],[650541,650598],[650700,650718],[650720,650727],[650901,650978],[651652,651679],[655e3,655019],[655021,655058]],gaps:[4,8,12],lengths:[16],code:{name:D,size:3}},h[z]={niceType:"Mir",type:z,patterns:[[2200,2204]],gaps:[4,8,12],lengths:[16,17,18,19],code:{name:V,size:3}},c.getTypeInfo=function(e){return r(i(e))},c.removeCard=function(e){var n=y(e);l.splice(n,1)},c.addCard=function(e){var n=y(e.type,!0);m[e.type]=e,n===-1&&l.push(e.type)},c.updateCard=function(e,n){var t,i=m[e]||h[e];if(!i)throw new Error('"'+e+'" is not a recognized type. Use `addCard` instead.');if(n.type&&i.type!==n.type)throw new Error("Cannot overwrite type parameter.");t=r(i,!0),Object.keys(t).forEach(function(e){n[e]&&(t[e]=n[e])}),m[t.type]=t},c.changeOrder=function(e,n){var t=y(e);l.splice(t,1),l.splice(n,0,e)},c.resetModifications=function(){l=r(R),m={}},c.types={VISA:v,MASTERCARD:C,AMERICAN_EXPRESS:S,DINERS_CLUB:E,DISCOVER:T,JCB:w,UNIONPAY:A,MAESTRO:O,ELO:b,MIR:z},n.exports=c},{}]},{},[1])(1)});

@@ -35,19 +35,9 @@ 'use strict';

function clone(originalObject, persistPatterns) {
var dupe, prefixPattern, exactPattern;
function clone(originalObject) {
var dupe;
if (!originalObject) { return null; }
prefixPattern = originalObject.prefixPattern;
exactPattern = originalObject.exactPattern;
dupe = JSON.parse(JSON.stringify(originalObject));
if (persistPatterns) {
dupe.prefixPattern = prefixPattern;
dupe.exactPattern = exactPattern;
} else {
delete dupe.prefixPattern;
delete dupe.exactPattern;
}
return dupe;

@@ -61,9 +51,5 @@ }

type: VISA,
prefixPattern: /^4/,
exactPattern: new RegExp('^' +
'4' +
'(?!' +
'31274|51416|57393|0117[89]|38935|5763[12]' + // Elo cards
')\\d{5,}' +
'$'),
patterns: [
4
],
gaps: [4, 8, 12],

@@ -80,4 +66,10 @@ lengths: [16, 18, 19],

type: MASTERCARD,
prefixPattern: /^(5|5[1-5]|2|22|222|222[1-9]|2[3-6]|27|27[0-2]|2720)$/,
exactPattern: /^(5[1-5]|222[1-9]|22[3-9]|2[3-6]|27[0-1]|2720)\d*$/,
patterns: [
[51, 55],
[2221, 2229],
[223, 229],
[23, 26],
[270, 271],
2720
],
gaps: [4, 8, 12],

@@ -94,5 +86,6 @@ lengths: [16],

type: AMERICAN_EXPRESS,
prefixPattern: /^(3|34|37)$/,
exactPattern: /^3[47]\d*$/,
isAmex: true,
patterns: [
34,
37
],
gaps: [4, 10],

@@ -109,4 +102,8 @@ lengths: [15],

type: DINERS_CLUB,
prefixPattern: /^(3|3[0689]|30[0-5])$/,
exactPattern: /^3(0[0-5]|[689])\d*$/,
patterns: [
[300, 305],
36,
38,
39
],
gaps: [4, 10],

@@ -123,33 +120,7 @@ lengths: [14, 16, 19],

type: DISCOVER,
prefixPattern: /^(6|60|601|6011|65|65\d{1,4}|64|64[4-9])$/,
exactPattern: new RegExp('^(' +
'6011' +
'|' +
'65' +
'(?!' + // Elo cards
'003[1-3]' +
'|' +
'003[5-9]|004\\d|005[0-1]' +
'|' +
'040[5-9]|04[1-3]\\d' +
'|' +
'048[5-9]|049\\d|05[0-2]\\d|053[0-8]' +
'|' +
'054[1-9]|05[5-8]\\d|059[0-8]' +
'|' +
'070\\d|071[0-8]' +
'|' +
'072[0-7]' +
'|' +
'090[1-9]|09[1-6]\\d|097[0-8]' +
'|' +
'165[2-9]|16[6-7]\\d' +
'|' +
'50[0-1]\\d' +
'|' +
'502[1-9]|50[3-4]\\d|505[0-8]' +
')\\d{4}' +
'|' +
'64[4-9]' +
')\\d*$'),
patterns: [
6011,
[644, 649],
65
],
gaps: [4, 8, 12],

@@ -166,4 +137,7 @@ lengths: [16, 19],

type: JCB,
prefixPattern: /^(2|21|213|2131|1|18|180|1800|3|35)$/,
exactPattern: /^(2131|1800|35)\d*$/,
patterns: [
2131,
1800,
[3528, 3589]
],
gaps: [4, 8, 12],

@@ -180,26 +154,24 @@ lengths: [16, 17, 18, 19],

type: UNIONPAY,
prefixPattern: /^((6|62|62\d|(621(?!83|88|98|99))|622(?!06)|627[0267]\d?|628(?!0|1)|629[1,2])|622018)$/,
exactPattern: new RegExp('^(' +
'(' +
'620' +
'|' +
'(621(?!83|88|98|99))' +
'|' +
'622(?!06|018)' +
'|' +
'62[3-6]' +
'|' +
'627[026]' +
'|' +
'6277(?!80)\\d{2}' + // Elo card
'|' +
'628(?!0|1)' +
'|' +
'629[12]' +
')\\d*' +
'|' +
'622018\\d{12}' +
')$'),
patterns: [
620,
[624, 626],
[62100, 62182],
[62184, 62187],
[62185, 62197],
[62200, 62205],
[622010, 622999],
622018,
[622019, 622999],
[62207, 62209],
[622126, 622925],
[623, 626],
6270,
6272,
6276,
[627700, 627779],
[627781, 627799],
[6282, 6289],
6291,
6292
],
gaps: [4, 8, 12],

@@ -216,23 +188,11 @@ lengths: [16, 17, 18, 19],

type: MAESTRO,
prefixPattern: /^(5|5[06-9]|6\d*)$/,
exactPattern: new RegExp('^(' +
'5[6-9]' +
'|' +
'50' +
'(?!' + // Elo card ranges
'6699|067[0-6][0-9]' +
'|' +
'677[0-8]' +
'|' +
'9[0-9][0-9][0-9]' +
')\\d{4}' +
'|' +
'67' +
'|' +
'63' +
'(?!' + // More Elo card ranges
'6297|6368' +
')\\d{4}' +
')\\d*$'
),
patterns: [
493698,
[500000, 506698],
[506779, 508999],
[56, 59],
63,
67,
6
],
gaps: [4, 8, 12],

@@ -249,105 +209,29 @@ lengths: [12, 13, 14, 15, 16, 17, 18, 19],

type: ELO,
prefixPattern: new RegExp('^(' +
'[4-6]' +
'|' +
'4[035]|4[035]1' +
'|' +
'4011|40117|40117[89]' +
'|' +
'4312|43127|431274' +
'|' +
'438|4389|43893|438935' +
'|' +
'4514|45141|451416' +
'|' +
'457|457[36]|45739|45763|457393|45763[12]' +
'|' +
'50|50[69]' +
'|' +
'506[6-7]|50669|5067[0-7]|5067[0-6][0-9]|50677[0-8]' +
'|' +
'509[0-9]|509[0-9][0-9]|509[0-9][0-9][0-9]' +
'|' +
'6[235]|627|636|65[015]' +
'|' +
'6277|62778|627780' +
'|' +
'636[23]|63629|636297|63636|636368' +
'|' +
'650[0479]' +
'|' +
'6500[3-5]|65003[1-3]|65003[5-9]|65004[0-9]65005[01]' +
'|' +
'6504[0-3]|65040[5-9]|65041[0-9]' +
'|' +
'6505[4-9]|65054[1-9]|6505[5-8][0-9]|65059[0-8]' +
'|' +
'6507[0-2]|65070[0-9]|65071[0-8]|65072[0-7]' +
'|' +
'6509[0-7]|65090[1-9]|6509[1-6][0-9]|65097[0-8]' +
'|' +
'6516|6516[5-7]|65165[2-9]|6516[6-7][0-9]' +
'|' +
'6550|6550[0-5]|6550[01][0-9]|65502[1-9]|6550[3-4][0-9]|65505[0-8]' +
')$'),
exactPattern: new RegExp('^(' +
// Elo only ranges
'4(31274|51416|57393)' +
'|' +
'50(' +
'4175' +
'|' +
'6699|67[0-6][0-9]|677[0-8]' + // 506699-506778
'|' +
'9[0-9][0-9][0-9]' + // 509000-509999
')' +
'|' +
'627780' +
'|' +
'636(297|368)' +
'|' +
// Dual Branded with Visa
'4(0117[89]|38935|5763[12])' +
'|' +
// Dual Branded with Discover
'65(' +
'003[1-3]' + // 650031-650033
'|' +
'003[5-9]|004\\d|005[0-1]' + // 650035-650051
'|' +
'040[5-9]|04[1-3]\\d' + // 650405-650439
'|' +
'048[5-9]|049\\d|05[0-2]\\d|053[0-8]' + // 650485-650538
'|' +
'054[1-9]|05[5-8]\\d|059[0-8]' + // 650541-650598
'|' +
'070[0-9]|071[0-8]' + // 650700-650718
'|' +
'072[0-7]' + // 650720-650727
'|' +
'090[1-9]|09[1-6][0-9]|097[0-8]' + // 650901-650978
'|' +
'165[2-9]|16[6-7][0-9]' + // 651652-651679
'|' +
'50[0-1][0-9]' + // 655000-655019
'|' +
'502[1-9]|50[3-4][0-9]|505[0-8]' + // 655021-655058
')' +
')\\d*$'),
patterns: [
401178,
401179,
438935,
457631,
457632,
431274,
451416,
457393,
504175,
[506699, 506778],
[509000, 509999],
627780,
636297,
636368,
[650031, 650033],
[650035, 650051],
[650405, 650439],
[650485, 650538],
[650541, 650598],
[650700, 650718],
[650720, 650727],
[650901, 650978],
[651652, 651679],
[655000, 655019],
[655021, 655058]
],
gaps: [4, 8, 12],

@@ -364,4 +248,5 @@ lengths: [16],

type: MIR,
prefixPattern: /^(2|22|220|220[0-4])$/,
exactPattern: /^(220[0-4])\d*$/,
patterns: [
[2200, 2204]
],
gaps: [4, 8, 12],

@@ -379,30 +264,124 @@ lengths: [16, 17, 18, 19],

function isValidInputType(cardNumber) {
return typeof cardNumber === 'string' || cardNumber instanceof String;
}
function hasEnoughResultsToDetermineBestMatch(results) {
var numberOfResultsWithMaxStrengthProperty = results.filter(function (result) {
return result.matchStrength;
}).length;
// if all possible results have a maxStrength property
// that means the card number is sufficiently long
// enough to determine conclusively what the type is
return numberOfResultsWithMaxStrengthProperty > 0 &&
numberOfResultsWithMaxStrengthProperty === results.length;
}
function findBestMatch(results) {
if (!hasEnoughResultsToDetermineBestMatch(results)) {
return;
}
return results.reduce(function (bestMatch, result) { // eslint-disable-line consistent-return
if (!bestMatch) {
return result;
}
// if the current best match pattern is less specific
// than this result, set the result as the new best match
if (bestMatch.matchStrength < result.matchStrength) {
return result;
}
return bestMatch;
});
}
function getAllCardTypes() {
return testOrder.map(function (type) {
return clone(findType(type));
});
}
function creditCardType(cardNumber) {
var type, value, i;
var prefixResults = [];
var exactResults = [];
var bestMatch;
var results = [];
if (!(typeof cardNumber === 'string' || cardNumber instanceof String)) {
if (!isValidInputType(cardNumber)) {
return [];
}
for (i = 0; i < testOrder.length; i++) {
type = testOrder[i];
value = findType(type);
if (cardNumber.length === 0) {
return getAllCardTypes();
}
if (cardNumber.length === 0) {
prefixResults.push(clone(value));
testOrder.forEach(function (type) {
var cardConfiguration = findType(type);
loopOverCardPatterns(cardNumber, cardConfiguration, results);
});
bestMatch = findBestMatch(results);
if (bestMatch) {
return [bestMatch];
}
return results;
}
function loopOverCardPatterns(cardNumber, cardConfiguration, results) {
var i, pattern, patternLength, clonedCardConfiguration;
for (i = 0; i < cardConfiguration.patterns.length; i++) {
pattern = cardConfiguration.patterns[i];
if (!matches(cardNumber, pattern)) {
continue;
}
if (value.exactPattern.test(cardNumber)) {
exactResults.push(clone(value));
} else if (value.prefixPattern.test(cardNumber)) {
prefixResults.push(clone(value));
clonedCardConfiguration = clone(cardConfiguration);
if (Array.isArray(pattern)) {
patternLength = String(pattern[0]).length;
} else {
patternLength = String(pattern).length;
}
if (cardNumber.length >= patternLength) {
clonedCardConfiguration.matchStrength = patternLength;
}
results.push(clonedCardConfiguration);
break;
}
}
return exactResults.length ? exactResults : prefixResults;
function matches(cardNumber, pattern) {
if (Array.isArray(pattern)) {
return matchesRange(cardNumber, pattern[0], pattern[1]);
}
return matchesPattern(cardNumber, pattern);
}
function matchesPattern(cardNumber, pattern) {
pattern = String(pattern);
return pattern.substring(0, cardNumber.length) === cardNumber.substring(0, pattern.length);
}
// Adapted from https://github.com/polvo-labs/card-type/blob/aaab11f80fa1939bccc8f24905a06ae3cd864356/src/cardType.js#L37-L42
function matchesRange(cardNumber, min, max) {
var maxLengthToCheck = String(min).length;
var substr = cardNumber.substr(0, maxLengthToCheck);
var integerRepresentationOfCardNumber = parseInt(substr, 10);
min = parseInt(String(min).substr(0, substr.length), 10);
max = parseInt(String(max).substr(0, substr.length), 10);
return integerRepresentationOfCardNumber >= min && integerRepresentationOfCardNumber <= max;
}
creditCardType.getTypeInfo = function (type) {

@@ -409,0 +388,0 @@ return clone(findType(type));

{
"name": "credit-card-type",
"version": "7.1.0",
"version": "8.0.0",
"description": "A library for determining credit card type",

@@ -8,3 +8,4 @@ "main": "index.js",

"lint": "eslint .",
"test": "npm run lint && mocha test/**/*.js",
"pretest": "npm run lint",
"test": "mocha test/**/*.js",
"build": "npm run lint && gulp build"

@@ -11,0 +12,0 @@ },

@@ -124,5 +124,32 @@ Credit Card Type [![Build Status](https://travis-ci.org/braintree/credit-card-type.svg)](https://travis-ci.org/braintree/credit-card-type) [![npm version](https://badge.fury.io/js/credit-card-type.svg)](http://badge.fury.io/js/credit-card-type) [![Bower](https://badge.fury.io/bo/credit-card-type.svg)](http://badge.fury.io/bo/credit-card-type)

#### Pattern Detection
Each card type has a `patterns` attribute that is an array of numbers and ranges of numbers (represented by an array of 2 values, a min and a max).
If the pattern is a number, the modules compares it against the card number. Partial matches for card numbers that are shorter than the pattern also match. Given the pattern `123`, then the card numbers `1`, `12`, `123`, `1234` will all match, but `2`, `13`, and `124` will not.
If the pattern is an array of numbers, then the card number is checked to be within the range of those numbers. Again, partial matches are accepted. Given the range `[100, 123]`, then the card numbers `1`, `10`, `100`, `12`, `120`,
`123` will all match, but `2`, `13`, and `124` will not.
For detection, the module loops over each card type's `patterns` array, and if a match occurs, that card type is added to the array of results.
In the case where multiple matches are made, if the entirety of the pattern is matched, the card type with the stronger pattern is preferred. For instance, Visa cards match anything that starts with a 4, but there are
some Elo cards that begin with a 4. One example is `401178`. So for the card
numbers, `4`, `40`, `401`, `4011`, `40117`, the module will report that this
card is _either_ a Visa or an Elo card. Once the card number becomes `401178`,
the modules sees that an exact match for the ELO bin has been made, and the module reports
that the card can only be an Elo card.
```javascript
var visa = creditCardType.getTypeInfo(creditCardType.types.VISA);
visa.prefixPattern = /^(4)$/;
visa.exactPattern = /^(4[0-1])\d*$/; // restrict to only match visas that start with 40 or 41
creditCardType.addCard(visa);
```
#### Adding Card Types
You can add additional card brands not supportted by the the module with `addCard`. Pass in the configuration object.
You can add additional card brands not supportted by the the module with `addCard`. Pass in the configuration object.

@@ -133,4 +160,6 @@ ```javascript

type: 'new-card',
prefixPattern: /^(2|23|234)$/,
exactPattern: /^(2345)\d*$/,
patterns: [
2345,
2376
],
gaps: [4, 8, 12],

@@ -145,3 +174,3 @@ lengths: [16],

You can also modify existing cards:
If you add a card that already exists in the module, it will overwrite it.

@@ -152,4 +181,6 @@ ```javascript

type: creditCardType.types.VISA,
prefixPattern: /^(4)$/,
exactPattern: /^(4[0-1])\d*$/, // restrict to only match visas that start with 40 or 41
patterns: [
41111
[44, 47]
],
gaps: [4, 8, 12],

@@ -164,15 +195,2 @@ lengths: [13, 16, 19], // add support for old, deprecated 13 digit visas

The `exactPattern` regex is checked first. If that pattern is matched, the module takes that result over the `prefixPattern`. The `prefixPattern` is a softer matcher for when the exact card type has not yet been determined, so multiple card types may be returned.
As an example, by default, the Visa `exactPattern` matches any card number that starts with 4. If you are adding a card type that has a bin range that starts with 4, you will not only have to call `addCard` with the new card type, but `addCard` with Visa to alter the `exactPattern` and `prefixPattern`;
```javascript
var visa = creditCardType.getTypeInfo(creditCardType.types.VISA);
visa.prefixPattern = /^(4)$/;
visa.exactPattern = /^(4[0-1])\d*$/; // restrict to only match visas that start with 40 or 41
creditCardType.addCard(visa);
```
Adding new cards puts them at the bottom of the priority for testing. Priority is determined by an array. By default, the priority looks like:

@@ -179,0 +197,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc