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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ Validator | Description
**isHexadecimal(str)** | check if the string is a hexadecimal number.
**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][CSS Colors Level 4 Specification].<br/><br/>Comma-separated format supported. Space-separated format supported with the exception of a few edge cases (ex: `hsl(200grad+.1%62%/1)`).
**isIBAN(str, [, options])** | check if the string is an IBAN (International Bank Account Number).<br/><br/>`options` is an object which accepts two attributes: `whitelist`: where you can restrict IBAN codes you want to receive data from and `blacklist`: where you can remove some of the countries from the current list. For both you can use an array with the following values `['AD','AE','AL','AT','AZ','BA','BE','BG','BH','BR','BY','CH','CR','CY','CZ','DE','DK','DO','EE','EG','ES','FI','FO','FR','GB','GE','GI','GL','GR','GT','HR','HU','IE','IL','IQ','IR','IS','IT','JO','KW','KZ','LB','LC','LI','LT','LU','LV','MC','MD','ME','MK','MR','MT','MU','MZ','NL','NO','PK','PL','PS','PT','QA','RO','RS','SA','SC','SE','SI','SK','SM','SV','TL','TN','TR','UA','VA','VG','XK']`.
**isIBAN(str [, options])** | check if the string is an IBAN (International Bank Account Number).<br/><br/>`options` is an object which accepts:<br/>- `strip` (default `true`): when `true`, whitespace and hyphens are removed before validation; when `false`, the input is validated as-is (it is still uppercased internally).<br/>- `whitelist`: restrict valid IBANs to the listed ISO alpha-2 country codes.<br/>- `blacklist`: exclude the listed ISO alpha-2 country codes.<br/>For both `whitelist` and `blacklist`, you can use an array with the following values `['AD','AE','AL','AT','AZ','BA','BE','BG','BH','BR','BY','CH','CR','CY','CZ','DE','DK','DO','EE','EG','ES','FI','FO','FR','GB','GE','GI','GL','GR','GT','HR','HU','IE','IL','IQ','IR','IS','IT','JO','KW','KZ','LB','LC','LI','LT','LU','LV','MC','MD','ME','MK','MR','MT','MU','MZ','NL','NO','PK','PL','PS','PT','QA','RO','RS','SA','SC','SE','SI','SK','SM','SV','TL','TN','TR','UA','VA','VG','XK']`.
**isIdentityCard(str [, locale])** | check if the string is a valid identity card code.<br/><br/>`locale` is one of `['LK', 'PL', 'ES', 'FI', 'IN', 'IT', 'IR', 'MZ', 'NO', 'TH', 'zh-TW', 'he-IL', 'ar-LY', 'ar-TN', 'zh-CN', 'zh-HK', 'PK']` OR `'any'`. If 'any' is used, function will check if any of the locales match.<br/><br/>Defaults to 'any'.
**isIMEI(str [, options]))** | check if the string is a valid [IMEI number][IMEI]. IMEI should be of format `###############` or `##-######-######-#`.<br/><br/>`options` is an object which can contain the keys `allow_hyphens`. Defaults to first format. If `allow_hyphens` is set to true, the validator will validate the second format.
**isIn(str, values)** | check if the string is in an array of allowed values.
Expand Down
34 changes: 29 additions & 5 deletions src/lib/isIBAN.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,22 @@ const ibanRegexThroughCountryCode = {
XK: /^(XK[0-9]{2})\d{16}$/,
};


/**
* Normalize an IBAN string.
*
* If `strip` is true, removes characters matching `pattern` (by default, any
* non-alphanumeric). Converts the resulting string to uppercase.
*
* @param {string} str - IBAN string to normalize.
* @param {boolean} strip - Whether to remove characters matching `pattern`.
* @param {RegExp} pattern=/[^A-Z0-9]+/gi - Pattern used when stripping.
* @return {string} Normalized (uppercase) IBAN string.
*/
function normalizeIbanString(str, strip, pattern = /[^A-Z0-9]+/gi) {
return (strip ? str.replace(pattern, '') : str).toUpperCase();
}

/**
* Check if the country codes passed are valid using the
* ibanRegexThroughCountryCode as a reference
Expand Down Expand Up @@ -117,12 +133,16 @@ function hasOnlyValidCountryCodes(countryCodeArray) {
* NOTE: Permitted IBAN characters are: digits [0-9] and the 26 latin alphabetic [A-Z]
*
* @param {string} str - string under validation
* @param {object} options - object to pass the countries to be either whitelisted or blacklisted
* @param {boolean} options.strip - If truthy, whitespace and hyphens are removed before validation.
* @param {string[]} options.whitelist - Optional set of allowed ISO country codes
* (e.g., ["DE","GB","CH"]). If present, IBANs for other countries are rejected.
* @param {string[]} options.blacklist - Optional set of disallowed ISO country codes
* (e.g., ["DE","GB","CH"]). If present, IBANs for these countries are rejected.
* @return {boolean}
*/
function hasValidIbanFormat(str, options) {
// Strip white spaces and hyphens
const strippedStr = str.replace(/[\s\-]+/gi, '').toUpperCase();
const strippedStr = normalizeIbanString(str, options.strip, /[\s\-]+/gi);
const isoCountryCode = strippedStr.slice(0, 2).toUpperCase();

const isoCountryCodeInIbanRegexCodeObject = isoCountryCode in ibanRegexThroughCountryCode;
Expand Down Expand Up @@ -162,10 +182,11 @@ function hasValidIbanFormat(str, options) {
* Reference: https://en.wikipedia.org/wiki/International_Bank_Account_Number
*
* @param {string} str
* @param {boolean} strip - Whether to strip the string of non-alphanumeric characters
* @return {boolean}
*/
function hasValidIbanChecksum(str) {
const strippedStr = str.replace(/[^A-Z0-9]+/gi, '').toUpperCase(); // Keep only digits and A-Z latin alphabetic
function hasValidIbanChecksum(str, strip) {
const strippedStr = normalizeIbanString(str, strip, /[^A-Z0-9]+/gi);
const rearranged = strippedStr.slice(4) + strippedStr.slice(0, 4);
const alphaCapsReplacedWithDigits = rearranged.replace(/[A-Z]/g, char => char.charCodeAt(0) - 55);

Expand All @@ -176,9 +197,12 @@ function hasValidIbanChecksum(str) {
}

export default function isIBAN(str, options = {}) {
const optionsWithDefaults = { strip: true, ...options };

assertString(str);

return hasValidIbanFormat(str, options) && hasValidIbanChecksum(str);
return hasValidIbanFormat(str, optionsWithDefaults)
&& hasValidIbanChecksum(str, optionsWithDefaults.strip);
}

export const locales = Object.keys(ibanRegexThroughCountryCode);
113 changes: 113 additions & 0 deletions test/validators.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6176,6 +6176,119 @@ describe('Validators', () => {
'IT60X0542811101000000123456',
],
});
test({
validator: 'isIBAN',
args: [{ strip: true }],
valid: [
'SC52BAHL01031234567890123456USD',
'LC14BOSL123456789012345678901234',
'MT31MALT01100000000000000000123',
'SV43ACAT00000000000000123123',
'EG800002000156789012345180002',
'BE71 0961 2345 6769',
'FR76 3000 6000 0112 3456 7890 189',
'DE91 1000 0000 0123 4567 89',
'GR96 0810 0010 0000 0123 4567 890',
'RO09 BCYP 0000 0012 3456 7890',
'SA44 2000 0001 2345 6789 1234',
'ES79 2100 0813 6101 2345 6789',
'CH56 0483 5012 3456 7800 9',
'GB98 MIDL 0700 9312 3456 78',
'IL170108000000012612345',
'IT60X0542811101000000123456',
'JO71CBJO0000000000001234567890',
'TR320010009999901234567890',
'BR1500000000000010932840814P2',
'LB92000700000000123123456123',
'IR200170000000339545727003',
'MZ97123412341234123412341',
'MA64011519000001205000534921',
'VG96VPVG0000012345678901',
'DZ580002100001113000000570',
'IE29AIBK93115212345678',
'PS92PALS000000000400123456702',
'PS92PALS00000000040012345670O',
],
invalid: [
'XX22YYY1234567890123',
'FR14 2004 1010 0505 0001 3',
'FR7630006000011234567890189@',
'FR7630006000011234567890189😅',
'FR763000600001123456!!🤨7890189@',
'VG46H07Y0223060094359858',
'IE95TE8270900834048660',
'PS072435171802145240705922007',
],
});
test({
validator: 'isIBAN',
args: [{ strip: false }],
valid: [
'gb29nwbk60161331926819',
'IE29AIBK93115212345678',
'IL170108000000012612345',
'JO71CBJO0000000000001234567890',
'TR320010009999901234567890',
'BR1500000000000010932840814P2',
'LB92000700000000123123456123',
'IR200170000000339545727003',
],
invalid: [
'GB29 NWBK 6016 1331 9268 19',
'GB29-NWBK-6016-1331-9268-19',
'GB29\tNWBK60161331926819',
'CH56 0483 5012 3456 7800 9',
'FR7630006000011234567890189@',
'FR7630006000011234567890189😅',
'FR763000600001123456!!🤨7890189@',
'VG46H07Y0223060094359858',
'IE95TE8270900834048660',
'PS072435171802145240705922007',
],
});
test({
validator: 'isIBAN',
args: [{ strip: false, blacklist: ['IT'] }],
valid: [
'GB29NWBK60161331926819',
'IE29AIBK93115212345678',
'IL170108000000012612345',
'JO71CBJO0000000000001234567890',
'TR320010009999901234567890',
'BR1500000000000010932840814P2',
'LB92000700000000123123456123',
'IR200170000000339545727003',
],
invalid: [
'IT60X0542811101000000123456',
'IT60 X054 2811 1010 0000 0123 456',
'GB98 MIDL 0700 9312 3456 78',
'CH56 0483 5012 3456 7800 9',
'FR7630006000011234567890189@',
'FR7630006000011234567890189😅',
'FR763000600001123456!!🤨7890189@',
'VG46H07Y0223060094359858',
'IE95TE8270900834048660',
'PS072435171802145240705922007',
],
});
test({
validator: 'isIBAN',
args: [{ strip: false, whitelist: ['DK', 'GB'] }],
valid: [
'DK5000400440116243',
'GB29NWBK60161331926819',
'gb29nwbk60161331926819',
],
invalid: [
'BE71096123456769',
'FR7630006000011234567890189',
'GB98 MIDL 0700 9312 3456 78',
'GB29-NWBK-6016-1331-9268-19',
'DK50 0040 0440 1162 43',
'IT60X0542811101000000123456',
],
});
});

it('should validate BIC codes', () => {
Expand Down
Loading