forked from CredenceOrg/Credence-Frontend
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathiban.ts
More file actions
61 lines (52 loc) · 1.84 KB
/
Copy pathiban.ts
File metadata and controls
61 lines (52 loc) · 1.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
export enum IbanErrorCode {
INVALID_LENGTH = 'INVALID_LENGTH',
INVALID_COUNTRY_CODE = 'INVALID_COUNTRY_CODE',
INVALID_FORMAT = 'INVALID_FORMAT',
INVALID_CHECKSUM = 'INVALID_CHECKSUM',
}
export interface IbanValidationResult {
valid: boolean
error?: IbanErrorCode
}
/**
* Validates an International Bank Account Number (IBAN).
*
* @param iban - The IBAN string to validate.
* @returns A structured validation result with an error code if invalid.
*/
export function validateIban(iban: string): IbanValidationResult {
const sanitized = iban.replace(/[\s-]+/g, '').toUpperCase()
// Basic length check (shortest is Norway 15, longest is 34)
if (sanitized.length < 15 || sanitized.length > 34) {
return { valid: false, error: IbanErrorCode.INVALID_LENGTH }
}
const countryCode = sanitized.substring(0, 2)
if (!/^[A-Z]{2}$/.test(countryCode)) {
return { valid: false, error: IbanErrorCode.INVALID_COUNTRY_CODE }
}
// Check if it contains only alphanumeric characters
if (!/^[A-Z0-9]+$/.test(sanitized)) {
return { valid: false, error: IbanErrorCode.INVALID_FORMAT }
}
// Modulo 97 checksum validation
const rearranged = sanitized.substring(4) + sanitized.substring(0, 4)
const numeric = rearranged
.split('')
.map((char) => {
const code = char.charCodeAt(0)
// Convert letters to numbers (A=10, B=11, ..., Z=35)
return code >= 65 && code <= 90 ? (code - 55).toString() : char
})
.join('')
// Compute modulo 97 on the large numeric string
let remainder = numeric
let block: string
while (remainder.length > 2) {
block = remainder.substring(0, 9)
remainder = (parseInt(block, 10) % 97).toString() + remainder.substring(block.length)
}
if (parseInt(remainder, 10) % 97 !== 1) {
return { valid: false, error: IbanErrorCode.INVALID_CHECKSUM }
}
return { valid: true }
}