From f40fb252a30d78740e5fbdb246e05cd8ff4f888b Mon Sep 17 00:00:00 2001 From: Justin Worthe Date: Sun, 13 Dec 2015 20:58:37 +0200 Subject: Initial commit --- index.js | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 index.js (limited to 'index.js') diff --git a/index.js b/index.js new file mode 100644 index 0000000..be7bf61 --- /dev/null +++ b/index.js @@ -0,0 +1,125 @@ +module.exports = { + parse: parse, + validate: validate, + parseDateOfBirth: parseDateOfBirth, + parseIsMale: parseIsMale, + parseIsFemale: parseIsFemale, + parseIsSouthAfricanCitizen: parseIsSouthAfricanCitizen +}; + +function parse(idNumber) { + if (typeof(idNumber) !== 'string') { + return undefined; + } + + var isValid = validate(idNumber); + if (!isValid) { + return { + valid: false + }; + } + + return { + isValid: isValid, + dateOfBirth: parseDateOfBirth(idNumber), + isMale: parseIsMale(idNumber), + isFemale: parseIsFemale(idNumber), + isSouthAfricanCitizen: parseIsSouthAfricanCitizen(idNumber) + }; +} + +function validate(idNumber) { + if (!regexpValidate(idNumber) || !datePartValidate(idNumber) || !controlDigitValidate(idNumber)) { + return false; + } + + return true; +} + +function regexpValidate(idNumber) { + if (typeof(idNumber) !== 'string') { + return false; + } + var regexp = /^[0-9]{13}$/; + return regexp.test(idNumber); +} + +function datePartValidate(idNumber) { + var dateOfBirth = parseDateOfBirth(idNumber); + return !!dateOfBirth; +} + +function controlDigitValidate(idNumber) { + var checkDigit = parseInt(idNumber[idNumber.length - 1], 10); + + var oddDigitsSum = 0; + + for (var i = 0; i < idNumber.length - 1; i+=2) { + oddDigitsSum += parseInt(idNumber[i], 10); + } + var evenDigits = ''; + for (var j = 1; j < idNumber.length - 1; j+=2) { + evenDigits += idNumber[j]; + } + evenDigits = parseInt(evenDigits, 10); + evenDigits *= 2; + evenDigits = '' + evenDigits; + + var sumOfEvenDigits = 0; + for (var k = 0; k < evenDigits.length; k++) { + sumOfEvenDigits += parseInt(evenDigits[k], 10); + } + var total = sumOfEvenDigits + oddDigitsSum; + var computedCheckDigit = 10 - (total % 10); + + if (computedCheckDigit === 10) { + computedCheckDigit = 0; + } + return computedCheckDigit === checkDigit; +} + +function parseDateOfBirth(idNumber) { + if (!regexpValidate(idNumber)) { + return undefined; + } + + //get year, and assume century + var currentYear = new Date().getFullYear(); + var currentCentury = Math.floor(currentYear/100)*100; + var yearPart = currentCentury + Number(idNumber.substring(0,2)); + if (yearPart > currentYear) { + yearPart -= 100; //must be last century + } + + //In Javascript, Jan=0. In ID Numbers, Jan=1. + var monthPart = Number(idNumber.substring(2,4))-1; + + var dayPart = Number(idNumber.substring(4,6)); + + var dateOfBirth = new Date(yearPart, monthPart, dayPart); + + //validate that date is in a valid range by making sure that it wasn't 'corrected' during construction + if (!dateOfBirth || dateOfBirth.getFullYear() !== yearPart || dateOfBirth.getMonth() !== monthPart || dateOfBirth.getDate() !== dayPart) { + return undefined; + } + + return dateOfBirth; +} + +function parseIsMale(idNumber) { + return !parseIsFemale(idNumber); +} + +function parseIsFemale(idNumber) { + if (!regexpValidate(idNumber)) { + return undefined; + } + return Number(idNumber[6]) <= 4; +} + +function parseIsSouthAfricanCitizen(idNumber) { + if (!regexpValidate(idNumber)) { + return undefined; + } + return Number(idNumber[6]) === 0; +} -- cgit v1.2.3