Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/us/ssn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import * as exceptions from '../exceptions';
import { strings } from '../util';
import { Validator, ValidateReturn } from '../types';

const invalidSSN = [
const invalidSSNSet = new Set([

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will note that if this is a performance optimization, that object keys are the fastest with a if (value in invalidSSN) { as the check will out perform Set().

'111111111',
'222222222',
'333333333',
Expand All @@ -27,7 +27,6 @@ const invalidSSN = [
'888888888',
'999999999',
'123123123',
'999999999',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

While removing the duplicate '999999999' is a good cleanup, the remaining '999999999' entry (now on line 28) is also completely redundant. Any SSN starting with 9 (including 999999999) is already rejected by the regex check /^(000|666|9)\d+/ on line 99. Therefore, both entries can be safely removed from the blacklist.

// Used in Advertising and known "invalid"
'002281852',
'042103580',
Expand All @@ -51,7 +50,7 @@ const invalidSSN = [
'457555462',
'468288779',
'549241889',
];
]);

function clean(input: string): ReturnType<typeof strings.cleanUnicode> {
return strings.cleanUnicode(input, '- ');
Expand Down Expand Up @@ -94,7 +93,7 @@ const impl: Validator = {
if (!strings.isdigits(value)) {
return { isValid: false, error: new exceptions.InvalidComponent() };
}
if (invalidSSN.includes(value)) {
if (invalidSSNSet.has(value)) {
return { isValid: false, error: new exceptions.InvalidComponent() };
}
if (/^(000|666|9)\d+/.test(value)) {
Expand Down
39 changes: 21 additions & 18 deletions src/util/checksum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ export function luhnChecksumValidate(

const sum = value
.split('')
// .reverse()
.map(v => alphabet.indexOf(v))
.reduce((acc, val, idx) => {
let v = val;
Expand Down Expand Up @@ -213,32 +212,36 @@ function modulo(dividentIn: string, divisor: number) {
return parseInt(divident, 10) % divisor;
}

/**
* Convert a string using alphanumeric alphabet to its numeric representation.
* Returns null if any character is not in the alphabet.
*/
function alphabetToNumber(

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this feels needless.

value: string,
alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ',
): string | null {
Comment on lines +219 to +222

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Since the PR description mentions that this helper is intended to be reused by other functions/modules that need alphanumeric-to-numeric conversion, it should be exported so that other files can import it.

Suggested change
function alphabetToNumber(
value: string,
alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ',
): string | null {
export function alphabetToNumber(
value: string,
alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ',
): string | null {

let result = '';
for (const c of value) {
const idx = alphabet.indexOf(c);
if (idx === -1) {
return null;
}
result += String(idx);
}
return result;
}

/**
* The ISO 7064 Mod 97, 10 algorithm.
*
* The Mod 97, 10 algorithm evaluates the whole number as an integer which is
* valid if the number modulo 97 is 1. As such it has two check digits.
*/
export function mod97base10Validate(value: string, expect = 1): boolean {
const alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
let fail = false;

const bigValue = value
.split('')
.map(c => {
const idx = alphabet.indexOf(c);
if (idx === -1) {
fail = true;
return '';
}
return String(idx);
})
.join('');

if (fail) {
const bigValue = alphabetToNumber(value);
if (bigValue === null) {
return false;
}

return modulo(bigValue, 97) === expect;
}

Expand Down