UNPKG

verifiera

Version:

A JavaScript library to perform common operations on Personal Identification Numbers (Social Security Numbers), like: Validation, censoring the individual digits, calculating age and detecting gender.

618 lines (600 loc) 22 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); /*! ***************************************************************************** Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; /*! * verifiera * @license MIT * Copyright (c) 2020 Milad Kawas CALE. All rights reserved. */ var calculateAge = function (birthday, today) { var isLeapYear = function (year) { var date = new Date(year, 1, 28); date.setDate(date.getDate() + 1); return date.getMonth() === 1; }; var d = new Date(birthday); var now = today ? new Date(today) : new Date(); var years = now.getFullYear() - d.getFullYear(); d.setFullYear(d.getFullYear() + years); if (d > now) { years -= 1; d.setFullYear(d.getFullYear() - 1); } var days = (now.getTime() - d.getTime()) / (3600 * 24 * 1000); var age = years + days / (isLeapYear(now.getFullYear()) ? 366 : 365); return age > 0 ? Math.floor(age) : 0; }; var validateDate = function (day, month, year) { var date = new Date(); date.setFullYear(year, month - 1, day); return date.getFullYear() === year && date.getMonth() + 1 === month && date.getDate() === day; }; var clean = function (input) { return input.replace(/[^\d]/g, '') .trim(); }; var calculateBitCheckSum = function (str, numbers) { var cleaned = clean(str); var sum = 0; numbers.forEach(function (num, index) { sum += num * parseInt(cleaned[index], 10); }); return sum; }; var validateBitCheckSum = function (personalNumber, numbers, mod) { if (mod === void 0) { mod = 11; } return calculateBitCheckSum(personalNumber, numbers) % mod === 0; }; var reverseString = function (str) { return str.split('').reverse().join(''); }; var defaultGetAge = function () { return 0; }; var defaultGetBirthday = function () { return ''; }; var defaultGetCensored = function () { return ''; }; var defaultGetCountry = function () { return ''; }; var defaultGetGender = function () { return ''; }; var defaultGetYear = function () { return 0; }; var defaultIsCoordinationNo = function () { return false; }; var defaultIsDNumber = function () { return false; }; var defaultValidate = function () { return false; }; var getGenderFactory = function (parts) { return function () { return (parseInt(parts.gender, 10) % 2) === 0 ? 'f' : 'm'; }; }; var getBirthdayFactory = function (parts, getYear) { return function () { return getYear() + "-" + parts.month + "-" + parts.day; }; }; var getAgeFactory = function (getBirthday) { return function (today) { if (today === void 0) { today = ''; } return calculateAge(getBirthday(), today); }; }; var validateFactory = function (personalNumber, regex, parts, getYear, localValidate) { return function () { return (personalNumber.length > 0 && regex.test(personalNumber) && validateDate(parseInt(parts.day, 10), parseInt(parts.month, 10), getYear()) && localValidate()); }; }; var defaultTools = function (extraTools) { if (extraTools === void 0) { extraTools = {}; } return __assign(__assign({ getAge: defaultGetAge, getBirthday: defaultGetBirthday, getCensored: defaultGetCensored, getCountry: defaultGetCountry, getGender: defaultGetGender, getYear: defaultGetYear }, extraTools), { validate: defaultValidate }); }; var czechSlovakia = function (personalNumber) { var format = '^([0-9]{2})([0-9]{2})([0-9]{2})/([0-9]{3})([0-9])?$'; var regex = new RegExp(format); var matches = regex.exec(personalNumber); if (!matches) { return defaultTools(); } var getMonth = function () { var month = parseInt(matches[2], 10); if (month >= 51 && month <= 62) { var newMonth = month - 50; return (newMonth < 10 ? '0' : '') + newMonth.toString(); } return matches[2]; }; var parts = { day: matches[3], month: getMonth(), year: matches[1], individualNumber: matches[4] }; var getYear = function () { var century = '19'; var year = parseInt(parts.year, 10); if (personalNumber.length === 10 && year >= 54) { century = '18'; } else if (personalNumber.length === 11 && year < 54) { century = '20'; } return parseInt(century + parts.year, 10); }; var localValidate = function () { if (personalNumber.length === 10) { return true; } var cleanedPersonalNumber = clean(personalNumber); var oddNumbers = 0; var evenNumbers = 0; for (var i = 0; i < cleanedPersonalNumber.length; i++) { var digit = parseInt(cleanedPersonalNumber[i], 10); if ((i + 1) % 2 === 0) { evenNumbers += digit; } else { oddNumbers += digit; } } return (oddNumbers - evenNumbers) % 11 === 0; }; var validate = validateFactory(personalNumber, regex, parts, getYear, localValidate); if (!validate()) { return defaultTools(); } var getBirthday = getBirthdayFactory(parts, getYear); var getAge = getAgeFactory(getBirthday); var getGender = function () { var month = parseInt(matches[2], 10); if (month >= 51 && month <= 62) { return 'f'; } return 'm'; }; var getCensored = function () { return "" + parts.year + matches[2] + parts.day + "/****"; }; var getCountry = function () { return 'czech_slovakia'; }; return { getAge: getAge, getBirthday: getBirthday, getCensored: getCensored, getCountry: getCountry, getGender: getGender, getYear: getYear, validate: validate }; }; var denmark = function (personalNumber, strict) { if (strict === void 0) { strict = false; } var format = '^([0-9]{2})([0-9]{2})([0-9]{2})-([0-9])([0-9]{2})([0-9])$'; var regex = new RegExp(format); var matches = regex.exec(personalNumber); if (!matches) { return defaultTools(); } var parts = { day: matches[1], month: matches[2], year: matches[3], centuryIndicator: matches[4], individualNumber: matches[5], gender: matches[6] }; var getYear = function () { var year = parseInt(parts.year, 10); var inGroup1 = ['4', '9'].includes(parts.centuryIndicator); var inGroup2 = ['5', '6', '7', '8'].includes(parts.centuryIndicator); var century = '19'; if ((inGroup1 && year <= 36) || (inGroup2 && year <= 57)) { century = '20'; } else if (inGroup2 && year >= 58) { century = '18'; } return parseInt("" + century + parts.year, 10); }; var localValidate = function () { if (strict) { return validateBitCheckSum(clean(personalNumber), [4, 3, 2, 7, 6, 5, 4, 3, 2, 1]); } return true; }; var validate = validateFactory(personalNumber, regex, parts, getYear, localValidate); if (!validate()) { return defaultTools(); } var getBirthday = getBirthdayFactory(parts, getYear); var getAge = getAgeFactory(getBirthday); var getGender = getGenderFactory(parts); var getCensored = function () { return "" + parts.day + parts.month + parts.year + "-****"; }; var getCountry = function () { return 'denmark'; }; return { getAge: getAge, getBirthday: getBirthday, getCensored: getCensored, getCountry: getCountry, getGender: getGender, getYear: getYear, validate: validate }; }; var finland = function (personalNumber) { var format = '^([0-9]{2})([0-9]{2})([0-9]{2})([-+A])([0-9]{3})([0-9A-Y])$'; var regex = new RegExp(format); var matches = regex.exec(personalNumber); if (!matches) { return defaultTools(); } var parts = { day: matches[1], month: matches[2], year: matches[3], centuryIndicator: matches[4], individualNumber: matches[5], checksum: matches[6], gender: matches[5] }; var getYear = function () { var century = '19'; switch (parts.centuryIndicator) { case '-': century = '19'; break; case '+': century = '18'; break; case 'A': century = '20'; break; } return parseInt("" + century + parts.year, 10); }; var localValidate = function () { var controlCharacter = '0123456789ABCDEFHJKLMNPRSTUVWXY'; var num = parseInt("" + parts.day + parts.month + parts.year + parts.individualNumber, 10); var remainder = num % 31; return controlCharacter[remainder] === parts.checksum.toUpperCase(); }; var validate = validateFactory(personalNumber, regex, parts, getYear, localValidate); if (!validate()) { return defaultTools(); } var getBirthday = getBirthdayFactory(parts, getYear); var getAge = getAgeFactory(getBirthday); var getGender = getGenderFactory(parts); var getCensored = function () { return "" + parts.day + parts.month + parts.year + parts.centuryIndicator + "****"; }; var getCountry = function () { return 'finland'; }; return { getAge: getAge, getBirthday: getBirthday, getCensored: getCensored, getCountry: getCountry, getGender: getGender, getYear: getYear, validate: validate }; }; var netherlands = function (personalNumber) { var format = '^([0-9]{9})$'; var regex = new RegExp(format); var matches = regex.exec(personalNumber); var validate = function () { return validateBitCheckSum(personalNumber, [9, 8, 7, 6, 5, 4, 3, 2, -1]); }; var result = defaultTools(); if (!matches || !validate()) { return result; } result.validate = validate; var getCensored = function () { return '*********'; }; var getCountry = function () { return 'netherlands'; }; result.getCensored = getCensored; result.getCountry = getCountry; return result; }; var norway = function (personalNumber) { var isDNumber = function () { return /^[4-7][0-9]{10}$/.test(personalNumber); }; var format = '^([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{3})([0-9])([0-9])$'; var regex = new RegExp(format); var matches = regex.exec(personalNumber); if (!matches) { return defaultTools({ isDNumber: defaultIsDNumber }); } var getDay = function () { if (isDNumber()) { var newDay = parseInt(matches[1], 10) - 40; return (newDay < 10 ? '0' : '') + newDay.toString(); } return matches[1]; }; var parts = { day: getDay(), month: matches[2], year: matches[3], individualNumber: matches[4], gender: matches[4] }; var getYear = function () { var individualNumber = parseInt(parts.individualNumber, 10); var year = parseInt(parts.year, 10); var century = 19; if (individualNumber > 499) { if (individualNumber < 750 && year >= 54) { century = 18; } else if (year < 40) { century = 20; } else if (individualNumber >= 900 && year >= 40) { century = 19; } } return (century * 100) + year; }; var localValidate = function () { return (validateBitCheckSum(personalNumber, [3, 7, 6, 1, 8, 9, 4, 5, 2, 1]) && validateBitCheckSum(personalNumber, [5, 4, 3, 2, 7, 6, 5, 4, 3, 2, 1])); }; var validate = validateFactory(personalNumber, regex, parts, getYear, localValidate); if (!validate()) { return defaultTools({ isDNumber: defaultIsDNumber }); } var getBirthday = getBirthdayFactory(parts, getYear); var getAge = getAgeFactory(getBirthday); var getGender = getGenderFactory(parts); var getCensored = function () { return "" + matches[1] + parts.month + parts.year + "*****"; }; var getCountry = function () { return 'norway'; }; return { getAge: getAge, getBirthday: getBirthday, getCensored: getCensored, getCountry: getCountry, getGender: getGender, getYear: getYear, isDNumber: isDNumber, validate: validate }; }; var poland = function (personalNumber) { var format = '^([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{3})([0-9])([0-9])$'; var regex = new RegExp(format); var matches = regex.exec(personalNumber); if (!matches) { return defaultTools(); } var getMonth = function () { var month = parseInt(matches[2], 10); var newMonth = month % 20; return (newMonth < 10 ? '0' : '') + newMonth.toString(); }; var parts = { day: matches[3], month: getMonth(), year: matches[1], individualNumber: matches[4], gender: matches[5], checksum: matches[6] }; var getYear = function () { var month = parseInt(matches[2], 10); var century = '19'; if (month < 20) { century = '19'; } else if (month > 20 && month < 33) { century = '20'; } else if (month > 40 && month < 53) { century = '21'; } else if (month > 60 && month < 73) { century = '22'; } return parseInt(century + parts.year, 10); }; var localValidate = function () { var numbers = [1, 3, 7, 9, 1, 3, 7, 9, 1, 3]; var sum = calculateBitCheckSum(personalNumber, numbers); var modulo = sum % 10; var tenthDigit = parseInt(personalNumber[10], 10); return (modulo === 0 && tenthDigit === 0) || (tenthDigit === 10 - modulo); }; var validate = validateFactory(personalNumber, regex, parts, getYear, localValidate); if (!validate()) { return defaultTools(); } var getBirthday = getBirthdayFactory(parts, getYear); var getAge = getAgeFactory(getBirthday); var getGender = getGenderFactory(parts); var getCensored = function () { return "" + parts.year + matches[2] + parts.day + "*****"; }; var getCountry = function () { return 'poland'; }; return { getAge: getAge, getBirthday: getBirthday, getCensored: getCensored, getCountry: getCountry, getGender: getGender, getYear: getYear, validate: validate }; }; var luhnChecksum = function (input) { var num = reverseString(clean(input)); var total = 0; for (var i = 0; i <= num.length - 1; i += 1) { var val = parseInt(num[i], 10); val = (i % 2 === 1) ? val * 2 : val; if (val > 9) { val -= 9; } total += val; } return total % 10; }; var isLuhnValid = function (input) { var num = clean(input); return luhnChecksum(num) === 0; }; var sweden = function (personalNumber, strict) { if (strict === void 0) { strict = true; } var dayLocation = strict ? 3 : 4; var format = '^([0-9]{2})([0-9]{2})([0-9]{2})([-+])([0-9]{3})([0-9])$'; if (!strict) { format = '^(18|19|20)?([0-9]{2})([0-9]{2})([0-9]{2})([-+])?([0-9]{3})([0-9])$'; } var regex = new RegExp(format); var matches = regex.exec(personalNumber); if (!matches) { return defaultTools({ isCoordinationNo: defaultIsCoordinationNo }); } var getDay = function () { var day = parseInt(matches[dayLocation], 10); if (day >= 61) { var newDay = day - 60; return (newDay <= 9 ? '0' : '') + newDay.toString(); } return matches[dayLocation]; }; var parts = { centuryIndicator: '', day: getDay(), month: matches[2], year: matches[1], separator: matches[4], individualNumber: matches[5], gender: matches[5], checksum: matches[6] }; if (!strict) { parts = { centuryIndicator: matches[1] || '', day: getDay(), month: matches[3], year: matches[2], separator: matches[5] || '', individualNumber: matches[6], gender: matches[6], checksum: matches[7] }; } var isCoordinationNo = function () { return ['6', '7', '8', '9'].includes(matches[dayLocation][0]); }; var getYear = function () { if (!strict && parts.centuryIndicator) { return parseInt("" + parts.centuryIndicator + parts.year, 10); } var birthday = parts.year + "-" + parts.month + "-" + parts.day; var todayObj = new Date(); var century = '19'; if (todayObj < new Date("20" + birthday)) { century = '19'; } else if (todayObj >= new Date("20" + birthday) && parts.separator === '-') { century = '20'; } else if (todayObj >= new Date("19" + birthday) && parts.separator === '+') { century = '19'; } return parseInt("" + century + parts.year, 10); }; var localValidate = function () { return isLuhnValid(personalNumber); }; if (!strict && parts.centuryIndicator) { localValidate = function () { return isLuhnValid(personalNumber.replace(new RegExp("^" + parts.centuryIndicator), '')); }; } var validate = validateFactory(personalNumber, regex, parts, getYear, localValidate); if (!validate()) { return defaultTools({ isCoordinationNo: defaultIsCoordinationNo }); } var getBirthday = getBirthdayFactory(parts, getYear); var getAge = getAgeFactory(getBirthday); var getGender = getGenderFactory(parts); var getCensored = function () { if (!strict) { return "" + parts.centuryIndicator + parts.year + parts.month + matches[4] + parts.separator + "****"; } return "" + parts.year + parts.month + matches[3] + parts.separator + "****"; }; var getCountry = function () { return 'sweden'; }; return { getAge: getAge, getBirthday: getBirthday, getCensored: getCensored, getCountry: getCountry, getGender: getGender, getYear: getYear, isCoordinationNo: isCoordinationNo, validate: validate }; }; var countries = [ czechSlovakia, denmark, finland, netherlands, norway, poland, sweden ]; var detectCountry = function (personalNumber) { for (var _i = 0, countries_1 = countries; _i < countries_1.length; _i++) { var country = countries_1[_i]; if (country.length === 1) { var detector = country(personalNumber); if (detector.validate()) { return detector.getCountry(); } } else if (country.length === 2) { var detector1 = country(personalNumber, true); var detector2 = country(personalNumber, false); if (detector1.validate()) { return detector1.getCountry(); } if (detector2.validate()) { return detector2.getCountry(); } } } return ''; }; var getCountryTools = function (personalNumber) { for (var _i = 0, countries_2 = countries; _i < countries_2.length; _i++) { var country = countries_2[_i]; if (country.length === 1) { var detector = country(personalNumber); if (detector.validate()) { return detector; } } else if (country.length === 2) { var detector1 = country(personalNumber, true); var detector2 = country(personalNumber, false); if (detector1.validate()) { return detector1; } if (detector2.validate()) { return detector2; } } } return defaultTools(); }; exports.czechSlovakia = czechSlovakia; exports.denmark = denmark; exports.detectCountry = detectCountry; exports.finland = finland; exports.getCountryTools = getCountryTools; exports.netherlands = netherlands; exports.norway = norway; exports.poland = poland; exports.sweden = sweden;