From d9896ca416091cc39dd9c84361072da94820116a Mon Sep 17 00:00:00 2001 From: ST-DDT Date: Sun, 22 May 2022 18:53:36 +0200 Subject: [PATCH 1/2] feat(isLuhnValid): Expose isLuhnValid independently from isCreditCard --- README.md | 1 + src/index.js | 2 ++ src/lib/isCreditCard.js | 22 ++-------------------- src/lib/isLuhnValid.js | 26 ++++++++++++++++++++++++++ 4 files changed, 31 insertions(+), 20 deletions(-) create mode 100644 src/lib/isLuhnValid.js diff --git a/README.md b/README.md index 9674841ea..629933c9a 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,7 @@ Validator | Description **isLicensePlate(str [, locale])** | check if string matches the format of a country's license plate.

(locale is one of `['cs-CZ', 'de-DE', 'de-LI', 'fi-FI', 'pt-BR', 'pt-PT', 'sq-AL', 'sv-SE']` or `any`) **isLocale(str)** | check if the string is a locale **isLowercase(str)** | check if the string is lowercase. +**isLuhnValid(str)** | check if the string passes the luhn check. **isMACAddress(str [, options])** | check if the string is a MAC address.

`options` is an object which defaults to `{no_separators: false}`. If `no_separators` is true, the validator will allow MAC addresses without separators. Also, it allows the use of hyphens, spaces or dots e.g '01 02 03 04 05 ab', '01-02-03-04-05-ab' or '0102.0304.05ab'. The options also allow a `eui` property to specify if it needs to be validated against EUI-48 or EUI-64. The accepted values of `eui` are: 48, 64. **isMagnetURI(str)** | check if the string is a [magnet uri format](https://en.wikipedia.org/wiki/Magnet_URI_scheme). **isMD5(str)** | check if the string is a MD5 hash.

Please note that you can also use the `isHash(str, 'md5')` function. Keep in mind that MD5 has some collision weaknesses compared to other algorithms (e.g., SHA). diff --git a/src/index.js b/src/index.js index ec6fe528a..42e1e8b69 100644 --- a/src/index.js +++ b/src/index.js @@ -69,6 +69,7 @@ import isBefore from './lib/isBefore'; import isIn from './lib/isIn'; +import isLuhnValid from './lib/isLuhnValid'; import isCreditCard from './lib/isCreditCard'; import isIdentityCard from './lib/isIdentityCard'; @@ -183,6 +184,7 @@ const validator = { isAfter, isBefore, isIn, + isLuhnValid, isCreditCard, isIdentityCard, isEAN, diff --git a/src/lib/isCreditCard.js b/src/lib/isCreditCard.js index b11c4cc90..53c80eb80 100644 --- a/src/lib/isCreditCard.js +++ b/src/lib/isCreditCard.js @@ -1,4 +1,5 @@ import assertString from './util/assertString'; +import isLuhnValid from './isLuhnValid'; /* eslint-disable max-len */ 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}))$/; @@ -10,24 +11,5 @@ export default function isCreditCard(str) { if (!creditCard.test(sanitized)) { return false; } - let sum = 0; - let digit; - let tmpNum; - let shouldDouble; - for (let i = sanitized.length - 1; i >= 0; i--) { - digit = sanitized.substring(i, (i + 1)); - tmpNum = parseInt(digit, 10); - if (shouldDouble) { - tmpNum *= 2; - if (tmpNum >= 10) { - sum += ((tmpNum % 10) + 1); - } else { - sum += tmpNum; - } - } else { - sum += tmpNum; - } - shouldDouble = !shouldDouble; - } - return !!((sum % 10) === 0 ? sanitized : false); + return isLuhnValid(str); } diff --git a/src/lib/isLuhnValid.js b/src/lib/isLuhnValid.js new file mode 100644 index 000000000..da205271f --- /dev/null +++ b/src/lib/isLuhnValid.js @@ -0,0 +1,26 @@ +import assertString from './util/assertString'; + +export default function isLuhnValid(str) { + assertString(str); + const sanitized = str.replace(/[- ]+/g, ''); + let sum = 0; + let digit; + let tmpNum; + let shouldDouble; + for (let i = sanitized.length - 1; i >= 0; i--) { + digit = sanitized.substring(i, (i + 1)); + tmpNum = parseInt(digit, 10); + if (shouldDouble) { + tmpNum *= 2; + if (tmpNum >= 10) { + sum += ((tmpNum % 10) + 1); + } else { + sum += tmpNum; + } + } else { + sum += tmpNum; + } + shouldDouble = !shouldDouble; + } + return !!((sum % 10) === 0 ? sanitized : false); +} From 4098467d7e588aae7322eac1519458df1524b880 Mon Sep 17 00:00:00 2001 From: ST-DDT Date: Mon, 23 May 2022 16:12:38 +0200 Subject: [PATCH 2/2] test: add tests specifically for isLuhnValid --- test/validators.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/validators.js b/test/validators.js index 16fb6b89b..1ef34d7bb 100644 --- a/test/validators.js +++ b/test/validators.js @@ -4931,6 +4931,34 @@ describe('Validators', () => { }); }); + it('should validate luhn numbers', () => { + test({ + validator: 'isLuhnValid', + valid: [ + '0', + '5421', + '01234567897', + '0123456789012345678906', + '0123456789012345678901234567891', + '123456789012345678906', + '375556917985515', + '36050234196908', + '4716461583322103', + '4716-2210-5188-5662', + '4929 7226 5379 7141', + ], + invalid: [ + '', + '1', + '5422', + 'foo', + 'prefix6234917882863855', + '623491788middle2863855', + '6234917882863855suffix', + ], + }); + }); + it('should validate credit cards', () => { test({ validator: 'isCreditCard',