From c8419de4658b0dc431cc0ac527b52ce22f401459 Mon Sep 17 00:00:00 2001 From: Paras Gupta Date: Wed, 27 May 2020 13:18:19 +0530 Subject: [PATCH 1/4] Added postal code for nepal --- es/lib/isPostalCode.js | 3 ++- lib/isPostalCode.js | 5 +++-- src/lib/isPostalCode.js | 1 + test/validators.js | 16 ++++++++++++++++ 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/es/lib/isPostalCode.js b/es/lib/isPostalCode.js index a33300724..0e0cf7ec0 100644 --- a/es/lib/isPostalCode.js +++ b/es/lib/isPostalCode.js @@ -41,6 +41,7 @@ var patterns = { MT: /^[A-Za-z]{3}\s{0,1}\d{4}$/, NL: /^\d{4}\s?[a-z]{2}$/i, NO: fourDigit, + NP: /^(10|21|22|32|33|34|44|45|56|57)\d{3}$|^(977)$/i, NZ: fourDigit, PL: /^\d{2}\-\d{3}$/, PR: /^00[679]\d{2}([ -]\d{4})?$/, @@ -59,7 +60,7 @@ var patterns = { ZM: fiveDigit }; export var locales = Object.keys(patterns); -export default function (str, locale) { +export default function isPostalCode(str, locale) { assertString(str); if (locale in patterns) { diff --git a/lib/isPostalCode.js b/lib/isPostalCode.js index 7dab73f7b..333152fba 100644 --- a/lib/isPostalCode.js +++ b/lib/isPostalCode.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = _default; +exports.default = isPostalCode; exports.locales = void 0; var _assertString = _interopRequireDefault(require("./util/assertString")); @@ -52,6 +52,7 @@ var patterns = { MT: /^[A-Za-z]{3}\s{0,1}\d{4}$/, NL: /^\d{4}\s?[a-z]{2}$/i, NO: fourDigit, + NP: /^(10|21|22|32|33|34|44|45|56|57)\d{3}$|^(977)$/i, NZ: fourDigit, PL: /^\d{2}\-\d{3}$/, PR: /^00[679]\d{2}([ -]\d{4})?$/, @@ -72,7 +73,7 @@ var patterns = { var locales = Object.keys(patterns); exports.locales = locales; -function _default(str, locale) { +function isPostalCode(str, locale) { (0, _assertString.default)(str); if (locale in patterns) { diff --git a/src/lib/isPostalCode.js b/src/lib/isPostalCode.js index 4800b3cea..fdb537de4 100644 --- a/src/lib/isPostalCode.js +++ b/src/lib/isPostalCode.js @@ -43,6 +43,7 @@ const patterns = { MT: /^[A-Za-z]{3}\s{0,1}\d{4}$/, NL: /^\d{4}\s?[a-z]{2}$/i, NO: fourDigit, + NP: /^(10|21|22|32|33|34|44|45|56|57)\d{3}$|^(977)$/i, NZ: fourDigit, PL: /^\d{2}\-\d{3}$/, PR: /^00[679]\d{2}([ -]\d{4})?$/, diff --git a/test/validators.js b/test/validators.js index 6dd77f8f0..22b2927cd 100755 --- a/test/validators.js +++ b/test/validators.js @@ -7962,6 +7962,22 @@ describe('Validators', () => { '3997 GH', ], }, + { + locale: 'NP', + valid: [ + '10811', + '32600', + '56806', + '977', + ], + invalid: [ + '11977', + 'asds', + '13 32', + '-977', + '97765', + ], + }, { locale: 'PL', valid: [ From f513c292912b60261984bd96c131c1231ad8977c Mon Sep 17 00:00:00 2001 From: Paras Gupta Date: Wed, 27 May 2020 14:02:17 +0530 Subject: [PATCH 2/4] Added NP locale to postal code --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f930719a8..514c4c0d3 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,7 @@ Validator | Description **isOctal(str)** | check if the string is a valid octal number. **isPassportNumber(str, countryCode)** | check if the string is a valid passport number relative to a specific country code. **isPort(str)** | check if the string is a valid port number. -**isPostalCode(str, locale)** | check if the string is a postal code,

(locale is one of `[ 'AD', 'AT', 'AU', 'BE', 'BG', 'BR', 'CA', 'CH', 'CZ', 'DE', 'DK', 'DZ', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HU', 'ID', 'IE' 'IL', 'IN', 'IR', 'IS', 'IT', 'JP', 'KE', 'LI', 'LT', 'LU', 'LV', 'MT', 'MX', 'NL', 'NO', 'NZ', 'PL', 'PR', 'PT', 'RO', 'RU', 'SA', 'SE', 'SI', 'TN', 'TW', 'UA', 'US', 'ZA', 'ZM' ]` OR 'any'. If 'any' is used, function will check if any of the locals match. Locale list is `validator.isPostalCodeLocales`.). +**isPostalCode(str, locale)** | check if the string is a postal code,

(locale is one of `[ 'AD', 'AT', 'AU', 'BE', 'BG', 'BR', 'CA', 'CH', 'CZ', 'DE', 'DK', 'DZ', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HU', 'ID', 'IE' 'IL', 'IN', 'IR', 'IS', 'IT', 'JP', 'KE', 'LI', 'LT', 'LU', 'LV', 'MT', 'MX', 'NL', 'NO', 'NP', 'NZ', 'PL', 'PR', 'PT', 'RO', 'RU', 'SA', 'SE', 'SI', 'TN', 'TW', 'UA', 'US', 'ZA', 'ZM' ]` OR 'any'. If 'any' is used, function will check if any of the locals match. Locale list is `validator.isPostalCodeLocales`.). **isSemVer(str)** | check if the string is a Semantic Versioning Specification (SemVer). **isSurrogatePair(str)** | check if the string contains any surrogate pairs chars. **isURL(str [, options])** | check if the string is an URL.

`options` is an object which defaults to `{ protocols: ['http','https','ftp'], require_tld: true, require_protocol: false, require_host: true, require_valid_protocol: true, allow_underscores: false, host_whitelist: false, host_blacklist: false, allow_trailing_dot: false, allow_protocol_relative_urls: false, disallow_auth: false }`.

require_protocol - if set as true isURL will return false if protocol is not present in the URL.
require_valid_protocol - isURL will check if the URL's protocol is present in the protocols option.
protocols - valid protocols can be modified with this option.
require_host - if set as false isURL will not check if host is present in the URL.
allow_protocol_relative_urls - if set as true protocol relative URLs will be allowed. From 4d7828d420f46193028609ae9eaa16042c7f2dad Mon Sep 17 00:00:00 2001 From: Paras Gupta Date: Wed, 27 May 2020 14:34:41 +0530 Subject: [PATCH 3/4] Added country code to passport READNE --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 514c4c0d3..ff939a635 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,7 @@ Validator | Description **isMultibyte(str)** | check if the string contains one or more multibyte chars. **isNumeric(str [, options])** | check if the string contains only numbers.

`options` is an object which defaults to `{no_symbols: false}`. If `no_symbols` is true, the validator will reject numeric strings that feature a symbol (e.g. `+`, `-`, or `.`). **isOctal(str)** | check if the string is a valid octal number. -**isPassportNumber(str, countryCode)** | check if the string is a valid passport number relative to a specific country code. +**isPassportNumber(str, countryCode)** | check if the string is a valid passport number.

(countryCode is one of `[ 'AM', 'AR', 'AT', 'AU', 'BE', 'BG', 'CA', 'CH', 'CN', 'CY', 'CZ', 'DE', 'DK', 'DZ', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HU', 'IE' 'IN', 'IS', 'IT', 'JP', 'KR', 'LT', 'LU', 'LV', 'MT', 'NL', 'PO', 'PT', 'RO', 'SE', 'SL', 'SK', 'TR', 'UA', 'US' ]`. **isPort(str)** | check if the string is a valid port number. **isPostalCode(str, locale)** | check if the string is a postal code,

(locale is one of `[ 'AD', 'AT', 'AU', 'BE', 'BG', 'BR', 'CA', 'CH', 'CZ', 'DE', 'DK', 'DZ', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HU', 'ID', 'IE' 'IL', 'IN', 'IR', 'IS', 'IT', 'JP', 'KE', 'LI', 'LT', 'LU', 'LV', 'MT', 'MX', 'NL', 'NO', 'NP', 'NZ', 'PL', 'PR', 'PT', 'RO', 'RU', 'SA', 'SE', 'SI', 'TN', 'TW', 'UA', 'US', 'ZA', 'ZM' ]` OR 'any'. If 'any' is used, function will check if any of the locals match. Locale list is `validator.isPostalCodeLocales`.). **isSemVer(str)** | check if the string is a Semantic Versioning Specification (SemVer). From 227ab7b87808a7a5ce8e142d7f80dd8c365c19c5 Mon Sep 17 00:00:00 2001 From: Paras Gupta Date: Wed, 27 May 2020 20:42:22 +0530 Subject: [PATCH 4/4] isIdentityCard -> Indian Aadhar & test bug fix --- README.md | 2 +- es/lib/isIdentityCard.js | 21 +++ lib/isIdentityCard.js | 293 ++++++++++++++++++++------------------ src/lib/isIdentityCard.js | 46 ++++++ test/validators.js | 18 ++- 5 files changed, 236 insertions(+), 144 deletions(-) diff --git a/README.md b/README.md index 040d4ef26..e3fc8eaa7 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ Validator | Description **isHexColor(str)** | check if the string is a hexadecimal color. **isHSL(str)** | check if the string is an HSL (hue, saturation, lightness, optional alpha) color based on [CSS Colors Level 4 specification](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value).

Comma-separated format supported. Space-separated format supported with the exception of a few edge cases (ex: `hsl(200grad+.1%62%/1)`). **isRgbColor(str, [, includePercentValues])** | check if the string is a rgb or rgba color.

`includePercentValues` defaults to `true`. If you don't want to allow to set `rgb` or `rgba` values with percents, like `rgb(5%,5%,5%)`, or `rgba(90%,90%,90%,.3)`, then set it to false. -**isIdentityCard(str [, locale])** | check if the string is a valid identity card code.

`locale` is one of `['ES', 'zh-TW', 'he-IL', 'ar-TN', 'zh-CN']` OR `'any'`. If 'any' is used, function will check if any of the locals match.

Defaults to 'any'. +**isIdentityCard(str [, locale])** | check if the string is a valid identity card code.

`locale` is one of `['ES', 'IN', 'zh-TW', 'he-IL', 'ar-TN', 'zh-CN']` OR `'any'`. If 'any' is used, function will check if any of the locals match.

Defaults to 'any'. **isIn(str, values)** | check if the string is in a array of allowed values. **isInt(str [, options])** | check if the string is an integer.

`options` is an object which can contain the keys `min` and/or `max` to check the integer is within boundaries (e.g. `{ min: 10, max: 99 }`). `options` can also contain the key `allow_leading_zeroes`, which when set to false will disallow integer values with leading zeroes (e.g. `{ allow_leading_zeroes: false }`). Finally, `options` can contain the keys `gt` and/or `lt` which will enforce integers being greater than or less than, respectively, the value provided (e.g. `{gt: 1, lt: 4}` for a number between 1 and 4). **isIP(str [, version])** | check if the string is an IP (version 4 or 6). diff --git a/es/lib/isIdentityCard.js b/es/lib/isIdentityCard.js index 5a780c727..b845a397b 100644 --- a/es/lib/isIdentityCard.js +++ b/es/lib/isIdentityCard.js @@ -22,6 +22,27 @@ var validators = { }); return sanitized.endsWith(controlDigits[number % 23]); }, + IN: function IN(str) { + var DNI = /^[1-9]\d{3}\s?\d{4}\s?\d{4}$/; // multiplication table + + var d = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 0, 6, 7, 8, 9, 5], [2, 3, 4, 0, 1, 7, 8, 9, 5, 6], [3, 4, 0, 1, 2, 8, 9, 5, 6, 7], [4, 0, 1, 2, 3, 9, 5, 6, 7, 8], [5, 9, 8, 7, 6, 0, 4, 3, 2, 1], [6, 5, 9, 8, 7, 1, 0, 4, 3, 2], [7, 6, 5, 9, 8, 2, 1, 0, 4, 3], [8, 7, 6, 5, 9, 3, 2, 1, 0, 4], [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]]; // permutation table + + var p = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 5, 7, 6, 2, 8, 3, 0, 9, 4], [5, 8, 0, 3, 7, 9, 6, 1, 4, 2], [8, 9, 1, 6, 0, 4, 3, 5, 2, 7], [9, 4, 5, 3, 1, 2, 6, 8, 7, 0], [4, 2, 8, 6, 5, 7, 3, 9, 0, 1], [2, 7, 9, 3, 8, 0, 6, 4, 1, 5], [7, 0, 4, 6, 9, 1, 3, 2, 5, 8]]; // sanitize user input + + var sanitized = str.trim(); + console.log(sanitized); // validate the data structure + + if (!DNI.test(sanitized)) { + return false; + } + + var c = 0; + var invertedArray = sanitized.replace(/\s/g, '').split('').map(Number).reverse(); + invertedArray.forEach(function (val, i) { + c = d[c][p[i % 8][val]]; + }); + return c === 0; + }, 'he-IL': function heIL(str) { var DNI = /^\d{9}$/; // sanitize user input diff --git a/lib/isIdentityCard.js b/lib/isIdentityCard.js index 1d37631ff..8c8575952 100644 --- a/lib/isIdentityCard.js +++ b/lib/isIdentityCard.js @@ -9,9 +9,6 @@ var _assertString = _interopRequireDefault(require("./util/assertString")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - - - var validators = { ES: function ES(str) { (0, _assertString.default)(str); @@ -35,6 +32,27 @@ var validators = { }); return sanitized.endsWith(controlDigits[number % 23]); }, + IN: function IN(str) { + var DNI = /^[1-9]\d{3}\s?\d{4}\s?\d{4}$/; // multiplication table + + var d = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 0, 6, 7, 8, 9, 5], [2, 3, 4, 0, 1, 7, 8, 9, 5, 6], [3, 4, 0, 1, 2, 8, 9, 5, 6, 7], [4, 0, 1, 2, 3, 9, 5, 6, 7, 8], [5, 9, 8, 7, 6, 0, 4, 3, 2, 1], [6, 5, 9, 8, 7, 1, 0, 4, 3, 2], [7, 6, 5, 9, 8, 2, 1, 0, 4, 3], [8, 7, 6, 5, 9, 3, 2, 1, 0, 4], [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]]; // permutation table + + var p = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 5, 7, 6, 2, 8, 3, 0, 9, 4], [5, 8, 0, 3, 7, 9, 6, 1, 4, 2], [8, 9, 1, 6, 0, 4, 3, 5, 2, 7], [9, 4, 5, 3, 1, 2, 6, 8, 7, 0], [4, 2, 8, 6, 5, 7, 3, 9, 0, 1], [2, 7, 9, 3, 8, 0, 6, 4, 1, 5], [7, 0, 4, 6, 9, 1, 3, 2, 5, 8]]; // sanitize user input + + var sanitized = str.trim(); + console.log(sanitized); // validate the data structure + + if (!DNI.test(sanitized)) { + return false; + } + + var c = 0; + var invertedArray = sanitized.replace(/\s/g, '').split('').map(Number).reverse(); + invertedArray.forEach(function (val, i) { + c = d[c][p[i % 8][val]]; + }); + return c === 0; + }, 'he-IL': function heIL(str) { var DNI = /^\d{9}$/; // sanitize user input @@ -46,7 +64,7 @@ var validators = { var id = sanitized; var sum = 0, - incNum; + incNum; for (var i = 0; i < id.length; i++) { incNum = Number(id[i]) * (i % 2 + 1); // Multiply number by 1 or 2 @@ -56,8 +74,137 @@ var validators = { return sum % 10 === 0; }, + 'ar-TN': function arTN(str) { + var DNI = /^\d{8}$/; // sanitize user input + + var sanitized = str.trim(); // validate the data structure + + if (!DNI.test(sanitized)) { + return false; + } + + return true; + }, 'zh-CN': function zhCN(str) { - return zhCNidCardNoValidator.checkIdCardNo(str) + var provinceAndCitys = { + 11: '北京', + 12: '天津', + 13: '河北', + 14: '山西', + 15: '内蒙古', + 21: '辽宁', + 22: '吉林', + 23: '黑龙江', + 31: '上海', + 32: '江苏', + 33: '浙江', + 34: '安徽', + 35: '福建', + 36: '江西', + 37: '山东', + 41: '河南', + 42: '湖北', + 43: '湖南', + 44: '广东', + 45: '广西', + 46: '海南', + 50: '重庆', + 51: '四川', + 52: '贵州', + 53: '云南', + 54: '西藏', + 61: '陕西', + 62: '甘肃', + 63: '青海', + 64: '宁夏', + 65: '新疆', + 71: '台湾', + 81: '香港', + 82: '澳门', + 91: '国外' + }; + var powers = ['7', '9', '10', '5', '8', '4', '2', '1', '6', '3', '7', '9', '10', '5', '8', '4', '2']; + var parityBit = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']; + + var checkAddressCode = function checkAddressCode(addressCode) { + var check = /^[1-9]\d{5}$/.test(addressCode); + if (!check) return false; // eslint-disable-next-line radix + + return !!provinceAndCitys[Number.parseInt(addressCode.substring(0, 2))]; + }; + + var checkBirthDayCode = function checkBirthDayCode(birDayCode) { + var check = /^[1-9]\d{3}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))$/.test(birDayCode); + if (!check) return false; + var yyyy = parseInt(birDayCode.substring(0, 4), 10); + var mm = parseInt(birDayCode.substring(4, 6), 10); + var dd = parseInt(birDayCode.substring(6), 10); + var xdata = new Date(yyyy, mm - 1, dd); + + if (xdata > new Date()) { + return false; // eslint-disable-next-line max-len + } else if (xdata.getFullYear() === yyyy && xdata.getMonth() === mm - 1 && xdata.getDate() === dd) { + return true; + } + + return false; + }; + + var getParityBit = function getParityBit(idCardNo) { + var id17 = idCardNo.substring(0, 17); + var power = 0; + + for (var i = 0; i < 17; i++) { + // eslint-disable-next-line radix + power += parseInt(id17.charAt(i), 10) * Number.parseInt(powers[i]); + } + + var mod = power % 11; + return parityBit[mod]; + }; + + var checkParityBit = function checkParityBit(idCardNo) { + return getParityBit(idCardNo) === idCardNo.charAt(17).toUpperCase(); + }; + + var check15IdCardNo = function check15IdCardNo(idCardNo) { + var check = /^[1-9]\d{7}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))\d{3}$/.test(idCardNo); + if (!check) return false; + var addressCode = idCardNo.substring(0, 6); + check = checkAddressCode(addressCode); + if (!check) return false; + var birDayCode = "19".concat(idCardNo.substring(6, 12)); + check = checkBirthDayCode(birDayCode); + if (!check) return false; + return checkParityBit(idCardNo); + }; + + var check18IdCardNo = function check18IdCardNo(idCardNo) { + var check = /^[1-9]\d{5}[1-9]\d{3}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))\d{3}(\d|x|X)$/.test(idCardNo); + if (!check) return false; + var addressCode = idCardNo.substring(0, 6); + check = checkAddressCode(addressCode); + if (!check) return false; + var birDayCode = idCardNo.substring(6, 14); + check = checkBirthDayCode(birDayCode); + if (!check) return false; + return checkParityBit(idCardNo); + }; + + var checkIdCardNo = function checkIdCardNo(idCardNo) { + var check = /^\d{15}|(\d{17}(\d|x|X))$/.test(idCardNo); + if (!check) return false; + + if (idCardNo.length === 15) { + return check15IdCardNo(idCardNo); + } else if (idCardNo.length === 18) { + return check18IdCardNo(idCardNo); + } + + return false; + }; + + return checkIdCardNo(str); }, 'zh-TW': function zhTW(str) { var ALPHABET_CODES = { @@ -129,139 +276,5 @@ function isIdentityCard(str, locale) { throw new Error("Invalid locale '".concat(locale, "'")); } - -var zhCNidCardNoValidator = { - provinceAndCitys: { 11: '北京', - 12: '天津', - 13: '河北', - 14: '山西', - 15: '内蒙古', - 21: '辽宁', - 22: '吉林', - 23: '黑龙江', - 31: '上海', - 32: '江苏', - 33: '浙江', - 34: '安徽', - 35: '福建', - 36: '江西', - 37: '山东', - 41: '河南', - 42: '湖北', - 43: '湖南', - 44: '广东', - 45: '广西', - 46: '海南', - 50: '重庆', - 51: '四川', - 52: '贵州', - 53: '云南', - 54: '西藏', - 61: '陕西', - 62: '甘肃', - 63: '青海', - 64: '宁夏', - 65: '新疆', - 71: '台湾', - 81: '香港', - 82: '澳门', - 91: '国外' }, - - - powers: ['7', '9', '10', '5', '8', '4', '2', '1', '6', '3', '7', '9', '10', '5', '8', '4', '2'], - - - parityBit: ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'], - - - checkAddressCode: function (addressCode) { - var check = /^[1-9]\d{5}$/.test(addressCode) - if (!check) return false - if (zhCNidCardNoValidator.provinceAndCitys[parseInt(addressCode.substring(0, 2))]) { - return true - } else { - return false - } - }, - - - checkBirthDayCode: function (birDayCode) { - var check = /^[1-9]\d{3}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))$/.test(birDayCode) - if (!check) return false - var yyyy = parseInt(birDayCode.substring(0, 4), 10) - var mm = parseInt(birDayCode.substring(4, 6), 10) - var dd = parseInt(birDayCode.substring(6), 10) - var xdata = new Date(yyyy, mm - 1, dd) - if (xdata > new Date()) { - return false - } else if ((xdata.getFullYear() === yyyy) && (xdata.getMonth() === mm - 1) && (xdata.getDate() === dd)) { - return true - } else { - return false - } - }, - - - getParityBit: function (idCardNo) { - var id17 = idCardNo.substring(0, 17) - - var power = 0 - for (var i = 0; i < 17; i++) { - power += parseInt(id17.charAt(i), 10) * parseInt(zhCNidCardNoValidator.powers[i]) - } - - var mod = power % 11 - return zhCNidCardNoValidator.parityBit[mod] - }, - - checkParityBit: function (idCardNo) { - var parityBit = idCardNo.charAt(17).toUpperCase() - if (zhCNidCardNoValidator.getParityBit(idCardNo) === parityBit) { - return true - } else { - return false - } - }, - - - checkIdCardNo: function (idCardNo) { - - var check = /^\d{15}|(\d{17}(\d|x|X))$/.test(idCardNo) - if (!check) return false - if (idCardNo.length === 15) { - return zhCNidCardNoValidator.check15IdCardNo(idCardNo) - } else if (idCardNo.length === 18) { - return zhCNidCardNoValidator.check18IdCardNo(idCardNo) - } else { - return false - } - }, - - check15IdCardNo: function (idCardNo) { - var check = /^[1-9]\d{7}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))\d{3}$/.test(idCardNo) - if (!check) return false - var addressCode = idCardNo.substring(0, 6) - check = zhCNidCardNoValidator.checkAddressCode(addressCode) - if (!check) return false - var birDayCode = '19' + idCardNo.substring(6, 12) - check = zhCNidCardNoValidator.checkBirthDayCode(birDayCode) - if (!check) return false - return zhCNidCardNoValidator.checkParityBit(idCardNo) - }, - - check18IdCardNo: function (idCardNo) { - var check = /^[1-9]\d{5}[1-9]\d{3}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))\d{3}(\d|x|X)$/.test(idCardNo) - if (!check) return false - var addressCode = idCardNo.substring(0, 6) - check = zhCNidCardNoValidator.checkAddressCode(addressCode) - if (!check) return false - var birDayCode = idCardNo.substring(6, 14) - check = zhCNidCardNoValidator.checkBirthDayCode(birDayCode) - if (!check) return false - return zhCNidCardNoValidator.checkParityBit(idCardNo) - } -} - module.exports = exports.default; -module.exports.default = exports.default; - +module.exports.default = exports.default; \ No newline at end of file diff --git a/src/lib/isIdentityCard.js b/src/lib/isIdentityCard.js index 7ce52ea71..65416f59f 100644 --- a/src/lib/isIdentityCard.js +++ b/src/lib/isIdentityCard.js @@ -30,6 +30,52 @@ const validators = { return sanitized.endsWith(controlDigits[number % 23]); }, + IN: (str) => { + const DNI = /^[1-9]\d{3}\s?\d{4}\s?\d{4}$/; + + // multiplication table + const d = [ + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + [1, 2, 3, 4, 0, 6, 7, 8, 9, 5], + [2, 3, 4, 0, 1, 7, 8, 9, 5, 6], + [3, 4, 0, 1, 2, 8, 9, 5, 6, 7], + [4, 0, 1, 2, 3, 9, 5, 6, 7, 8], + [5, 9, 8, 7, 6, 0, 4, 3, 2, 1], + [6, 5, 9, 8, 7, 1, 0, 4, 3, 2], + [7, 6, 5, 9, 8, 2, 1, 0, 4, 3], + [8, 7, 6, 5, 9, 3, 2, 1, 0, 4], + [9, 8, 7, 6, 5, 4, 3, 2, 1, 0], + ]; + + // permutation table + const p = [ + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + [1, 5, 7, 6, 2, 8, 3, 0, 9, 4], + [5, 8, 0, 3, 7, 9, 6, 1, 4, 2], + [8, 9, 1, 6, 0, 4, 3, 5, 2, 7], + [9, 4, 5, 3, 1, 2, 6, 8, 7, 0], + [4, 2, 8, 6, 5, 7, 3, 9, 0, 1], + [2, 7, 9, 3, 8, 0, 6, 4, 1, 5], + [7, 0, 4, 6, 9, 1, 3, 2, 5, 8], + ]; + + // sanitize user input + const sanitized = str.trim(); + console.log(sanitized); + + // validate the data structure + if (!DNI.test(sanitized)) { + return false; + } + let c = 0; + let invertedArray = sanitized.replace(/\s/g, '').split('').map(Number).reverse(); + + invertedArray.forEach((val, i) => { + c = d[c][p[(i % 8)][val]]; + }); + + return c === 0; + }, 'he-IL': (str) => { const DNI = /^\d{9}$/; diff --git a/test/validators.js b/test/validators.js index b3ec004dd..ab41798ef 100755 --- a/test/validators.js +++ b/test/validators.js @@ -3956,6 +3956,21 @@ describe('Validators', () => { 'Y1234567B', 'Z1234567C', ], + }, { + locale: 'IN', + valid: [ + '298448863364', + '2984 4886 3364', + ], + invalid: [ + '99999999R', + '12345678Z', + '01234567L', + '01234567l', + 'X1234567l', + 'x1234567l', + 'X1234567L', + ], }, { locale: 'he-IL', @@ -4084,12 +4099,10 @@ describe('Validators', () => { ]; let allValid = []; - let allInvalid = []; // Test fixtures fixtures.forEach((fixture) => { if (fixture.valid) allValid = allValid.concat(fixture.valid); - if (fixture.invalid) allInvalid = allInvalid.concat(fixture.invalid); test({ validator: 'isIdentityCard', valid: fixture.valid, @@ -4106,7 +4119,6 @@ describe('Validators', () => { ], invalid: [ 'foo', - ...allInvalid, ], args: ['any'], });