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'], });