ibantools 4.5.1 → 4.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/ibantools.js +150 -152
- package/jsnext/ibantools.js +137 -139
- package/package.json +18 -21
package/build/ibantools.js
CHANGED
|
@@ -12,13 +12,26 @@
|
|
|
12
12
|
* @package Documentation
|
|
13
13
|
* @author Saša Jovanić
|
|
14
14
|
* @module ibantools
|
|
15
|
-
* @version 4.5.
|
|
15
|
+
* @version 4.5.2
|
|
16
16
|
* @license MIT or MPL-2.0
|
|
17
17
|
* @preferred
|
|
18
18
|
*/
|
|
19
19
|
'use strict';
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
-
exports.countrySpecs = exports.setCountryBBANValidation = exports.
|
|
21
|
+
exports.countrySpecs = exports.setCountryBBANValidation = exports.ValidationErrorsBIC = exports.ValidationErrorsIBAN = void 0;
|
|
22
|
+
exports.isValidIBAN = isValidIBAN;
|
|
23
|
+
exports.validateIBAN = validateIBAN;
|
|
24
|
+
exports.isValidBBAN = isValidBBAN;
|
|
25
|
+
exports.isSEPACountry = isSEPACountry;
|
|
26
|
+
exports.isQRIBAN = isQRIBAN;
|
|
27
|
+
exports.composeIBAN = composeIBAN;
|
|
28
|
+
exports.extractIBAN = extractIBAN;
|
|
29
|
+
exports.electronicFormatIBAN = electronicFormatIBAN;
|
|
30
|
+
exports.friendlyFormatIBAN = friendlyFormatIBAN;
|
|
31
|
+
exports.getCountrySpecifications = getCountrySpecifications;
|
|
32
|
+
exports.isValidBIC = isValidBIC;
|
|
33
|
+
exports.validateBIC = validateBIC;
|
|
34
|
+
exports.extractBIC = extractBIC;
|
|
22
35
|
/**
|
|
23
36
|
* Validate IBAN
|
|
24
37
|
* ```
|
|
@@ -38,13 +51,12 @@ exports.countrySpecs = exports.setCountryBBANValidation = exports.extractBIC = e
|
|
|
38
51
|
* ibantools.isValidIBAN('CH4431999123000889012', { allowQRIBAN: false });
|
|
39
52
|
* ```
|
|
40
53
|
*/
|
|
41
|
-
function isValidIBAN(iban, validationOptions) {
|
|
42
|
-
if (validationOptions === void 0) { validationOptions = { allowQRIBAN: true }; }
|
|
54
|
+
function isValidIBAN(iban, validationOptions = { allowQRIBAN: true }) {
|
|
43
55
|
if (iban === undefined || iban === null)
|
|
44
56
|
return false;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
57
|
+
const reg = new RegExp('^[0-9]{2}$', '');
|
|
58
|
+
const countryCode = iban.slice(0, 2);
|
|
59
|
+
const spec = exports.countrySpecs[countryCode];
|
|
48
60
|
if (spec === undefined || spec.bban_regexp === undefined || spec.bban_regexp === null || spec.chars === undefined)
|
|
49
61
|
return false;
|
|
50
62
|
return (spec.chars === iban.length &&
|
|
@@ -53,7 +65,6 @@ function isValidIBAN(iban, validationOptions) {
|
|
|
53
65
|
isValidIBANChecksum(iban) &&
|
|
54
66
|
(validationOptions.allowQRIBAN || !isQRIBAN(iban)));
|
|
55
67
|
}
|
|
56
|
-
exports.isValidIBAN = isValidIBAN;
|
|
57
68
|
/**
|
|
58
69
|
* IBAM validation errors
|
|
59
70
|
*/
|
|
@@ -84,11 +95,10 @@ var ValidationErrorsIBAN;
|
|
|
84
95
|
* ibantools.validateIBAN('CH4431999123000889012', { allowQRIBAN: false });
|
|
85
96
|
* ```
|
|
86
97
|
*/
|
|
87
|
-
function validateIBAN(iban, validationOptions) {
|
|
88
|
-
|
|
89
|
-
var result = { errorCodes: [], valid: true };
|
|
98
|
+
function validateIBAN(iban, validationOptions = { allowQRIBAN: true }) {
|
|
99
|
+
const result = { errorCodes: [], valid: true };
|
|
90
100
|
if (iban !== undefined && iban !== null && iban !== '') {
|
|
91
|
-
|
|
101
|
+
const spec = exports.countrySpecs[iban.slice(0, 2)];
|
|
92
102
|
if (!spec || !(spec.bban_regexp || spec.chars)) {
|
|
93
103
|
result.valid = false;
|
|
94
104
|
result.errorCodes.push(ValidationErrorsIBAN.NoIBANCountry);
|
|
@@ -106,7 +116,7 @@ function validateIBAN(iban, validationOptions) {
|
|
|
106
116
|
result.valid = false;
|
|
107
117
|
result.errorCodes.push(ValidationErrorsIBAN.WrongAccountBankBranchChecksum);
|
|
108
118
|
}
|
|
109
|
-
|
|
119
|
+
const reg = new RegExp('^[0-9]{2}$', '');
|
|
110
120
|
if (!reg.test(iban.slice(2, 4))) {
|
|
111
121
|
result.valid = false;
|
|
112
122
|
result.errorCodes.push(ValidationErrorsIBAN.ChecksumNotNumber);
|
|
@@ -126,7 +136,6 @@ function validateIBAN(iban, validationOptions) {
|
|
|
126
136
|
}
|
|
127
137
|
return result;
|
|
128
138
|
}
|
|
129
|
-
exports.validateIBAN = validateIBAN;
|
|
130
139
|
/**
|
|
131
140
|
* Validate BBAN
|
|
132
141
|
*
|
|
@@ -142,7 +151,7 @@ exports.validateIBAN = validateIBAN;
|
|
|
142
151
|
function isValidBBAN(bban, countryCode) {
|
|
143
152
|
if (bban === undefined || bban === null || countryCode === undefined || countryCode === null)
|
|
144
153
|
return false;
|
|
145
|
-
|
|
154
|
+
const spec = exports.countrySpecs[countryCode];
|
|
146
155
|
if (spec === undefined ||
|
|
147
156
|
spec === null ||
|
|
148
157
|
spec.bban_regexp === undefined ||
|
|
@@ -158,7 +167,6 @@ function isValidBBAN(bban, countryCode) {
|
|
|
158
167
|
}
|
|
159
168
|
return false;
|
|
160
169
|
}
|
|
161
|
-
exports.isValidBBAN = isValidBBAN;
|
|
162
170
|
/**
|
|
163
171
|
* Validate if country code is from a SEPA country
|
|
164
172
|
* ```
|
|
@@ -172,14 +180,13 @@ exports.isValidBBAN = isValidBBAN;
|
|
|
172
180
|
*/
|
|
173
181
|
function isSEPACountry(countryCode) {
|
|
174
182
|
if (countryCode !== undefined && countryCode !== null) {
|
|
175
|
-
|
|
183
|
+
const spec = exports.countrySpecs[countryCode];
|
|
176
184
|
if (spec !== undefined) {
|
|
177
185
|
return spec.SEPA ? spec.SEPA : false;
|
|
178
186
|
}
|
|
179
187
|
}
|
|
180
188
|
return false;
|
|
181
189
|
}
|
|
182
|
-
exports.isSEPACountry = isSEPACountry;
|
|
183
190
|
/**
|
|
184
191
|
* Check if IBAN is QR-IBAN
|
|
185
192
|
* ```
|
|
@@ -194,14 +201,13 @@ exports.isSEPACountry = isSEPACountry;
|
|
|
194
201
|
function isQRIBAN(iban) {
|
|
195
202
|
if (iban === undefined || iban === null)
|
|
196
203
|
return false;
|
|
197
|
-
|
|
198
|
-
|
|
204
|
+
const countryCode = iban.slice(0, 2);
|
|
205
|
+
const QRIBANCountries = ['LI', 'CH'];
|
|
199
206
|
if (!QRIBANCountries.includes(countryCode))
|
|
200
207
|
return false;
|
|
201
|
-
|
|
208
|
+
const reg = new RegExp('^3[0-1]{1}[0-9]{3}$', '');
|
|
202
209
|
return reg.test(iban.slice(4, 9));
|
|
203
210
|
}
|
|
204
|
-
exports.isQRIBAN = isQRIBAN;
|
|
205
211
|
/**
|
|
206
212
|
* composeIBAN
|
|
207
213
|
*
|
|
@@ -211,11 +217,11 @@ exports.isQRIBAN = isQRIBAN;
|
|
|
211
217
|
* ```
|
|
212
218
|
*/
|
|
213
219
|
function composeIBAN(params) {
|
|
214
|
-
|
|
220
|
+
const formated_bban = electronicFormatIBAN(params.bban) || '';
|
|
215
221
|
if (params.countryCode === null || params.countryCode === undefined) {
|
|
216
222
|
return null;
|
|
217
223
|
}
|
|
218
|
-
|
|
224
|
+
const spec = exports.countrySpecs[params.countryCode];
|
|
219
225
|
if (formated_bban !== '' &&
|
|
220
226
|
spec !== undefined &&
|
|
221
227
|
spec.chars &&
|
|
@@ -224,12 +230,11 @@ function composeIBAN(params) {
|
|
|
224
230
|
spec.bban_regexp &&
|
|
225
231
|
spec.bban_regexp !== null &&
|
|
226
232
|
checkFormatBBAN(formated_bban, spec.bban_regexp)) {
|
|
227
|
-
|
|
233
|
+
const checksom = mod9710Iban(params.countryCode + '00' + formated_bban);
|
|
228
234
|
return params.countryCode + ('0' + (98 - checksom)).slice(-2) + formated_bban;
|
|
229
235
|
}
|
|
230
236
|
return null;
|
|
231
237
|
}
|
|
232
|
-
exports.composeIBAN = composeIBAN;
|
|
233
238
|
/**
|
|
234
239
|
* extractIBAN
|
|
235
240
|
* ```
|
|
@@ -238,30 +243,30 @@ exports.composeIBAN = composeIBAN;
|
|
|
238
243
|
* ```
|
|
239
244
|
*/
|
|
240
245
|
function extractIBAN(iban) {
|
|
241
|
-
|
|
242
|
-
|
|
246
|
+
const result = {};
|
|
247
|
+
const eFormatIBAN = electronicFormatIBAN(iban);
|
|
243
248
|
result.iban = eFormatIBAN || iban;
|
|
244
249
|
if (!!eFormatIBAN && isValidIBAN(eFormatIBAN)) {
|
|
245
250
|
result.bban = eFormatIBAN.slice(4);
|
|
246
251
|
result.countryCode = eFormatIBAN.slice(0, 2);
|
|
247
252
|
result.valid = true;
|
|
248
|
-
|
|
253
|
+
const spec = exports.countrySpecs[result.countryCode];
|
|
249
254
|
if (spec.account_indentifier) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
255
|
+
const ac = spec.account_indentifier.split('-');
|
|
256
|
+
const starting = parseInt(ac[0]);
|
|
257
|
+
const ending = parseInt(ac[1]);
|
|
253
258
|
result.accountNumber = result.iban.slice(starting, ending + 1);
|
|
254
259
|
}
|
|
255
260
|
if (spec.bank_identifier) {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
261
|
+
const ac = spec.bank_identifier.split('-');
|
|
262
|
+
const starting = parseInt(ac[0]);
|
|
263
|
+
const ending = parseInt(ac[1]);
|
|
259
264
|
result.bankIdentifier = result.bban.slice(starting, ending + 1);
|
|
260
265
|
}
|
|
261
266
|
if (spec.branch_indentifier) {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
267
|
+
const ac = spec.branch_indentifier.split('-');
|
|
268
|
+
const starting = parseInt(ac[0]);
|
|
269
|
+
const ending = parseInt(ac[1]);
|
|
265
270
|
result.branchIdentifier = result.bban.slice(starting, ending + 1);
|
|
266
271
|
}
|
|
267
272
|
}
|
|
@@ -270,14 +275,13 @@ function extractIBAN(iban) {
|
|
|
270
275
|
}
|
|
271
276
|
return result;
|
|
272
277
|
}
|
|
273
|
-
exports.extractIBAN = extractIBAN;
|
|
274
278
|
/**
|
|
275
279
|
* Check BBAN format
|
|
276
280
|
*
|
|
277
281
|
* @ignore
|
|
278
282
|
*/
|
|
279
283
|
function checkFormatBBAN(bban, bformat) {
|
|
280
|
-
|
|
284
|
+
const reg = new RegExp(bformat, '');
|
|
281
285
|
return reg.test(bban);
|
|
282
286
|
}
|
|
283
287
|
/**
|
|
@@ -295,7 +299,6 @@ function electronicFormatIBAN(iban) {
|
|
|
295
299
|
}
|
|
296
300
|
return iban.replace(/[-\ ]/g, '').toUpperCase();
|
|
297
301
|
}
|
|
298
|
-
exports.electronicFormatIBAN = electronicFormatIBAN;
|
|
299
302
|
/**
|
|
300
303
|
* Get IBAN in friendly format (separated after every 4 characters)
|
|
301
304
|
* IBAN validation is not performed.
|
|
@@ -316,23 +319,22 @@ function friendlyFormatIBAN(iban, separator) {
|
|
|
316
319
|
if (separator === undefined || separator === null) {
|
|
317
320
|
separator = ' ';
|
|
318
321
|
}
|
|
319
|
-
|
|
322
|
+
const electronic_iban = electronicFormatIBAN(iban);
|
|
320
323
|
/* istanbul ignore if */
|
|
321
324
|
if (electronic_iban === null) {
|
|
322
325
|
return null;
|
|
323
326
|
}
|
|
324
327
|
return electronic_iban.replace(/(.{4})(?!$)/g, '$1' + separator);
|
|
325
328
|
}
|
|
326
|
-
exports.friendlyFormatIBAN = friendlyFormatIBAN;
|
|
327
329
|
/**
|
|
328
330
|
* Calculate checksum of IBAN and compares it with checksum provided in IBAN Registry
|
|
329
331
|
*
|
|
330
332
|
* @ignore
|
|
331
333
|
*/
|
|
332
334
|
function isValidIBANChecksum(iban) {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
335
|
+
const countryCode = iban.slice(0, 2);
|
|
336
|
+
const providedChecksum = parseInt(iban.slice(2, 4), 10);
|
|
337
|
+
const bban = iban.slice(4);
|
|
336
338
|
// Wikipedia[validating_iban] says there are a specif way to check if a IBAN is valid but
|
|
337
339
|
// it. It says 'If the remainder is 1, the check digit test is passed and the
|
|
338
340
|
// IBAN might be valid.'. might, MIGHT!
|
|
@@ -350,8 +352,8 @@ function isValidIBANChecksum(iban) {
|
|
|
350
352
|
//
|
|
351
353
|
// [validating_iban][https://en.wikipedia.org/wiki/International_Bank_Account_Number#Validating_the_IBAN]
|
|
352
354
|
// [generating-iban-check][https://en.wikipedia.org/wiki/International_Bank_Account_Number#Generating_IBAN_check_digits]
|
|
353
|
-
|
|
354
|
-
|
|
355
|
+
const validationString = replaceCharaterWithCode(`${bban}${countryCode}00`);
|
|
356
|
+
const rest = mod9710(validationString);
|
|
355
357
|
return 98 - rest === providedChecksum;
|
|
356
358
|
}
|
|
357
359
|
/**
|
|
@@ -365,8 +367,8 @@ function replaceCharaterWithCode(str) {
|
|
|
365
367
|
// https://jsbench.me/ttkzgsekae/1
|
|
366
368
|
return str
|
|
367
369
|
.split('')
|
|
368
|
-
.map(
|
|
369
|
-
|
|
370
|
+
.map((c) => {
|
|
371
|
+
const code = c.charCodeAt(0);
|
|
370
372
|
return code >= 65 ? (code - 55).toString() : c;
|
|
371
373
|
})
|
|
372
374
|
.join('');
|
|
@@ -402,9 +404,9 @@ function mod9710Iban(iban) {
|
|
|
402
404
|
* ```
|
|
403
405
|
*/
|
|
404
406
|
function getCountrySpecifications() {
|
|
405
|
-
|
|
406
|
-
for (
|
|
407
|
-
|
|
407
|
+
const countyMap = {};
|
|
408
|
+
for (const countyCode in exports.countrySpecs) {
|
|
409
|
+
const county = exports.countrySpecs[countyCode];
|
|
408
410
|
countyMap[countyCode] = {
|
|
409
411
|
chars: county.chars || null,
|
|
410
412
|
bban_regexp: county.bban_regexp || null,
|
|
@@ -414,7 +416,6 @@ function getCountrySpecifications() {
|
|
|
414
416
|
}
|
|
415
417
|
return countyMap;
|
|
416
418
|
}
|
|
417
|
-
exports.getCountrySpecifications = getCountrySpecifications;
|
|
418
419
|
/**
|
|
419
420
|
* Validate BIC/SWIFT
|
|
420
421
|
*
|
|
@@ -436,11 +437,10 @@ function isValidBIC(bic) {
|
|
|
436
437
|
if (!bic) {
|
|
437
438
|
return false;
|
|
438
439
|
}
|
|
439
|
-
|
|
440
|
-
|
|
440
|
+
const reg = new RegExp('^[a-zA-Z]{6}[a-zA-Z0-9]{2}([a-zA-Z0-9]{3})?$', '');
|
|
441
|
+
const spec = exports.countrySpecs[bic.toUpperCase().slice(4, 6)];
|
|
441
442
|
return reg.test(bic) && spec !== undefined;
|
|
442
443
|
}
|
|
443
|
-
exports.isValidBIC = isValidBIC;
|
|
444
444
|
/**
|
|
445
445
|
* BIC validation errors
|
|
446
446
|
*/
|
|
@@ -458,15 +458,15 @@ var ValidationErrorsBIC;
|
|
|
458
458
|
* ```
|
|
459
459
|
*/
|
|
460
460
|
function validateBIC(bic) {
|
|
461
|
-
|
|
461
|
+
const result = { errorCodes: [], valid: true };
|
|
462
462
|
if (bic !== undefined && bic !== null && bic !== '') {
|
|
463
|
-
|
|
463
|
+
const spec = exports.countrySpecs[bic.toUpperCase().slice(4, 6)];
|
|
464
464
|
if (spec === undefined) {
|
|
465
465
|
result.valid = false;
|
|
466
466
|
result.errorCodes.push(ValidationErrorsBIC.NoBICCountry);
|
|
467
467
|
}
|
|
468
468
|
else {
|
|
469
|
-
|
|
469
|
+
const reg = new RegExp('^[a-zA-Z]{6}[a-zA-Z0-9]{2}([a-zA-Z0-9]{3})?$', '');
|
|
470
470
|
if (!reg.test(bic)) {
|
|
471
471
|
result.valid = false;
|
|
472
472
|
result.errorCodes.push(ValidationErrorsBIC.WrongBICFormat);
|
|
@@ -479,7 +479,6 @@ function validateBIC(bic) {
|
|
|
479
479
|
}
|
|
480
480
|
return result;
|
|
481
481
|
}
|
|
482
|
-
exports.validateBIC = validateBIC;
|
|
483
482
|
/**
|
|
484
483
|
* extractBIC
|
|
485
484
|
* ```
|
|
@@ -488,8 +487,8 @@ exports.validateBIC = validateBIC;
|
|
|
488
487
|
* ```
|
|
489
488
|
*/
|
|
490
489
|
function extractBIC(inputBic) {
|
|
491
|
-
|
|
492
|
-
|
|
490
|
+
const result = {};
|
|
491
|
+
const bic = inputBic.toUpperCase();
|
|
493
492
|
if (isValidBIC(bic)) {
|
|
494
493
|
result.bankCode = bic.slice(0, 4);
|
|
495
494
|
result.countryCode = bic.slice(4, 6);
|
|
@@ -503,22 +502,21 @@ function extractBIC(inputBic) {
|
|
|
503
502
|
}
|
|
504
503
|
return result;
|
|
505
504
|
}
|
|
506
|
-
exports.extractBIC = extractBIC;
|
|
507
505
|
/**
|
|
508
506
|
* Used for Norway BBAN check
|
|
509
507
|
*
|
|
510
508
|
* @ignore
|
|
511
509
|
*/
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
for (
|
|
510
|
+
const checkNorwayBBAN = (bban) => {
|
|
511
|
+
const weights = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2];
|
|
512
|
+
const bbanWithoutSpacesAndPeriods = bban.replace(/[\s.]+/g, '');
|
|
513
|
+
const controlDigit = parseInt(bbanWithoutSpacesAndPeriods.charAt(10), 10);
|
|
514
|
+
const bbanWithoutControlDigit = bbanWithoutSpacesAndPeriods.substring(0, 10);
|
|
515
|
+
let sum = 0;
|
|
516
|
+
for (let index = 0; index < 10; index++) {
|
|
519
517
|
sum += parseInt(bbanWithoutControlDigit.charAt(index), 10) * weights[index];
|
|
520
518
|
}
|
|
521
|
-
|
|
519
|
+
const remainder = sum % 11;
|
|
522
520
|
return controlDigit === (remainder === 0 ? 0 : 11 - remainder);
|
|
523
521
|
};
|
|
524
522
|
/**
|
|
@@ -526,11 +524,11 @@ var checkNorwayBBAN = function (bban) {
|
|
|
526
524
|
*
|
|
527
525
|
* @ignore
|
|
528
526
|
*/
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
527
|
+
const checkBelgianBBAN = (bban) => {
|
|
528
|
+
const stripped = bban.replace(/[\s.]+/g, '');
|
|
529
|
+
const checkingPart = parseInt(stripped.substring(0, stripped.length - 2), 10);
|
|
530
|
+
const checksum = parseInt(stripped.substring(stripped.length - 2, stripped.length), 10);
|
|
531
|
+
const remainder = checkingPart % 97 === 0 ? 97 : checkingPart % 97;
|
|
534
532
|
return remainder === checksum;
|
|
535
533
|
};
|
|
536
534
|
/**
|
|
@@ -538,15 +536,15 @@ var checkBelgianBBAN = function (bban) {
|
|
|
538
536
|
*
|
|
539
537
|
* @ignore
|
|
540
538
|
*/
|
|
541
|
-
|
|
539
|
+
const mod9710 = (validationString) => {
|
|
542
540
|
while (validationString.length > 2) {
|
|
543
541
|
// > Any computer programming language or software package that is used to compute D
|
|
544
542
|
// > mod 97 directly must have the ability to handle integers of more than 30 digits.
|
|
545
543
|
// > In practice, this can only be done by software that either supports
|
|
546
544
|
// > arbitrary-precision arithmetic or that can handle 219-bit (unsigned) integers
|
|
547
545
|
// https://en.wikipedia.org/wiki/International_Bank_Account_Number#Modulo_operation_on_IBAN
|
|
548
|
-
|
|
549
|
-
|
|
546
|
+
const part = validationString.slice(0, 6);
|
|
547
|
+
const partInt = parseInt(part, 10);
|
|
550
548
|
if (isNaN(partInt)) {
|
|
551
549
|
return NaN;
|
|
552
550
|
}
|
|
@@ -560,9 +558,9 @@ var mod9710 = function (validationString) {
|
|
|
560
558
|
*
|
|
561
559
|
* @ignore
|
|
562
560
|
*/
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
561
|
+
const checkMod9710BBAN = (bban) => {
|
|
562
|
+
const stripped = bban.replace(/[\s.]+/g, '');
|
|
563
|
+
const reminder = mod9710(stripped);
|
|
566
564
|
return reminder === 1;
|
|
567
565
|
};
|
|
568
566
|
/**
|
|
@@ -570,15 +568,15 @@ var checkMod9710BBAN = function (bban) {
|
|
|
570
568
|
*
|
|
571
569
|
* @ignore
|
|
572
570
|
*/
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
for (
|
|
571
|
+
const checkPolandBBAN = (bban) => {
|
|
572
|
+
const weights = [3, 9, 7, 1, 3, 9, 7];
|
|
573
|
+
const controlDigit = parseInt(bban.charAt(7), 10);
|
|
574
|
+
const toCheck = bban.substring(0, 7);
|
|
575
|
+
let sum = 0;
|
|
576
|
+
for (let index = 0; index < 7; index++) {
|
|
579
577
|
sum += parseInt(toCheck.charAt(index), 10) * weights[index];
|
|
580
578
|
}
|
|
581
|
-
|
|
579
|
+
const remainder = sum % 10;
|
|
582
580
|
return controlDigit === (remainder === 0 ? 0 : 10 - remainder);
|
|
583
581
|
};
|
|
584
582
|
/**
|
|
@@ -586,23 +584,23 @@ var checkPolandBBAN = function (bban) {
|
|
|
586
584
|
*
|
|
587
585
|
* @ignore
|
|
588
586
|
*/
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
for (
|
|
587
|
+
const checkSpainBBAN = (bban) => {
|
|
588
|
+
const weightsBankBranch = [4, 8, 5, 10, 9, 7, 3, 6];
|
|
589
|
+
const weightsAccount = [1, 2, 4, 8, 5, 10, 9, 7, 3, 6];
|
|
590
|
+
const controlBankBranch = parseInt(bban.charAt(8), 10);
|
|
591
|
+
const controlAccount = parseInt(bban.charAt(9), 10);
|
|
592
|
+
const bankBranch = bban.substring(0, 8);
|
|
593
|
+
const account = bban.substring(10, 20);
|
|
594
|
+
let sum = 0;
|
|
595
|
+
for (let index = 0; index < 8; index++) {
|
|
598
596
|
sum += parseInt(bankBranch.charAt(index), 10) * weightsBankBranch[index];
|
|
599
597
|
}
|
|
600
|
-
|
|
598
|
+
let remainder = sum % 11;
|
|
601
599
|
if (controlBankBranch !== (remainder === 0 ? 0 : remainder === 1 ? 1 : 11 - remainder)) {
|
|
602
600
|
return false;
|
|
603
601
|
}
|
|
604
602
|
sum = 0;
|
|
605
|
-
for (
|
|
603
|
+
for (let index = 0; index < 10; index++) {
|
|
606
604
|
sum += parseInt(account.charAt(index), 10) * weightsAccount[index];
|
|
607
605
|
}
|
|
608
606
|
remainder = sum % 11;
|
|
@@ -613,9 +611,9 @@ var checkSpainBBAN = function (bban) {
|
|
|
613
611
|
*
|
|
614
612
|
* @ignore
|
|
615
613
|
*/
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
for (
|
|
614
|
+
const checkMod1110 = (toCheck, control) => {
|
|
615
|
+
let nr = 10;
|
|
616
|
+
for (let index = 0; index < toCheck.length; index++) {
|
|
619
617
|
nr += parseInt(toCheck.charAt(index), 10);
|
|
620
618
|
if (nr % 10 !== 0) {
|
|
621
619
|
nr = nr % 10;
|
|
@@ -630,11 +628,11 @@ var checkMod1110 = function (toCheck, control) {
|
|
|
630
628
|
*
|
|
631
629
|
* @ignore
|
|
632
630
|
*/
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
631
|
+
const checkCroatianBBAN = (bban) => {
|
|
632
|
+
const controlBankBranch = parseInt(bban.charAt(6), 10);
|
|
633
|
+
const controlAccount = parseInt(bban.charAt(16), 10);
|
|
634
|
+
const bankBranch = bban.substring(0, 6);
|
|
635
|
+
const account = bban.substring(7, 16);
|
|
638
636
|
return checkMod1110(bankBranch, controlBankBranch) && checkMod1110(account, controlAccount);
|
|
639
637
|
};
|
|
640
638
|
/**
|
|
@@ -642,23 +640,23 @@ var checkCroatianBBAN = function (bban) {
|
|
|
642
640
|
*
|
|
643
641
|
* @ignore
|
|
644
642
|
*/
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
for (
|
|
643
|
+
const checkCzechAndSlovakBBAN = (bban) => {
|
|
644
|
+
const weightsPrefix = [10, 5, 8, 4, 2, 1];
|
|
645
|
+
const weightsSuffix = [6, 3, 7, 9, 10, 5, 8, 4, 2, 1];
|
|
646
|
+
const controlPrefix = parseInt(bban.charAt(9), 10);
|
|
647
|
+
const controlSuffix = parseInt(bban.charAt(19), 10);
|
|
648
|
+
const prefix = bban.substring(4, 9);
|
|
649
|
+
const suffix = bban.substring(10, 19);
|
|
650
|
+
let sum = 0;
|
|
651
|
+
for (let index = 0; index < prefix.length; index++) {
|
|
654
652
|
sum += parseInt(prefix.charAt(index), 10) * weightsPrefix[index];
|
|
655
653
|
}
|
|
656
|
-
|
|
654
|
+
let remainder = sum % 11;
|
|
657
655
|
if (controlPrefix !== (remainder === 0 ? 0 : remainder === 1 ? 1 : 11 - remainder)) {
|
|
658
656
|
return false;
|
|
659
657
|
}
|
|
660
658
|
sum = 0;
|
|
661
|
-
for (
|
|
659
|
+
for (let index = 0; index < suffix.length; index++) {
|
|
662
660
|
sum += parseInt(suffix.charAt(index), 10) * weightsSuffix[index];
|
|
663
661
|
}
|
|
664
662
|
remainder = sum % 11;
|
|
@@ -669,15 +667,15 @@ var checkCzechAndSlovakBBAN = function (bban) {
|
|
|
669
667
|
*
|
|
670
668
|
* @ignore
|
|
671
669
|
*/
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
for (
|
|
670
|
+
const checkEstonianBBAN = (bban) => {
|
|
671
|
+
const weights = [7, 1, 3, 7, 1, 3, 7, 1, 3, 7, 1, 3, 7];
|
|
672
|
+
const controlDigit = parseInt(bban.charAt(15), 10);
|
|
673
|
+
const toCheck = bban.substring(2, 15);
|
|
674
|
+
let sum = 0;
|
|
675
|
+
for (let index = 0; index < toCheck.length; index++) {
|
|
678
676
|
sum += parseInt(toCheck.charAt(index), 10) * weights[index];
|
|
679
677
|
}
|
|
680
|
-
|
|
678
|
+
const remainder = sum % 10;
|
|
681
679
|
return controlDigit === (remainder === 0 ? 0 : 10 - remainder);
|
|
682
680
|
};
|
|
683
681
|
/**
|
|
@@ -686,11 +684,11 @@ var checkEstonianBBAN = function (bban) {
|
|
|
686
684
|
*
|
|
687
685
|
* @ignore
|
|
688
686
|
*/
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
for (
|
|
693
|
-
|
|
687
|
+
const checkFrenchBBAN = (bban) => {
|
|
688
|
+
const stripped = bban.replace(/[\s.]+/g, '');
|
|
689
|
+
const normalized = Array.from(stripped);
|
|
690
|
+
for (let index = 0; index < stripped.length; index++) {
|
|
691
|
+
const c = normalized[index].charCodeAt(0);
|
|
694
692
|
if (c >= 65) {
|
|
695
693
|
switch (c) {
|
|
696
694
|
case 65:
|
|
@@ -740,7 +738,7 @@ var checkFrenchBBAN = function (bban) {
|
|
|
740
738
|
}
|
|
741
739
|
}
|
|
742
740
|
}
|
|
743
|
-
|
|
741
|
+
const remainder = mod9710(normalized.join(''));
|
|
744
742
|
return remainder === 0;
|
|
745
743
|
};
|
|
746
744
|
/**
|
|
@@ -748,36 +746,36 @@ var checkFrenchBBAN = function (bban) {
|
|
|
748
746
|
*
|
|
749
747
|
* @ignore
|
|
750
748
|
*/
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
for (
|
|
749
|
+
const checkHungarianBBAN = (bban) => {
|
|
750
|
+
const weights = [9, 7, 3, 1, 9, 7, 3, 1, 9, 7, 3, 1, 9, 7, 3];
|
|
751
|
+
const controlDigitBankBranch = parseInt(bban.charAt(7), 10);
|
|
752
|
+
const toCheckBankBranch = bban.substring(0, 7);
|
|
753
|
+
let sum = 0;
|
|
754
|
+
for (let index = 0; index < toCheckBankBranch.length; index++) {
|
|
757
755
|
sum += parseInt(toCheckBankBranch.charAt(index), 10) * weights[index];
|
|
758
756
|
}
|
|
759
|
-
|
|
757
|
+
const remainder = sum % 10;
|
|
760
758
|
if (controlDigitBankBranch !== (remainder === 0 ? 0 : 10 - remainder)) {
|
|
761
759
|
return false;
|
|
762
760
|
}
|
|
763
761
|
sum = 0;
|
|
764
762
|
if (bban.endsWith('00000000')) {
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
for (
|
|
763
|
+
const toCheckAccount = bban.substring(8, 15);
|
|
764
|
+
const controlDigitAccount = parseInt(bban.charAt(15), 10);
|
|
765
|
+
for (let index = 0; index < toCheckAccount.length; index++) {
|
|
768
766
|
sum += parseInt(toCheckAccount.charAt(index), 10) * weights[index];
|
|
769
767
|
}
|
|
770
|
-
|
|
771
|
-
return controlDigitAccount === (
|
|
768
|
+
const remainder = sum % 10;
|
|
769
|
+
return controlDigitAccount === (remainder === 0 ? 0 : 10 - remainder);
|
|
772
770
|
}
|
|
773
771
|
else {
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
for (
|
|
772
|
+
const toCheckAccount = bban.substring(8, 23);
|
|
773
|
+
const controlDigitAccount = parseInt(bban.charAt(23), 10);
|
|
774
|
+
for (let index = 0; index < toCheckAccount.length; index++) {
|
|
777
775
|
sum += parseInt(toCheckAccount.charAt(index), 10) * weights[index];
|
|
778
776
|
}
|
|
779
|
-
|
|
780
|
-
return controlDigitAccount === (
|
|
777
|
+
const remainder = sum % 10;
|
|
778
|
+
return controlDigitAccount === (remainder === 0 ? 0 : 10 - remainder);
|
|
781
779
|
}
|
|
782
780
|
};
|
|
783
781
|
/**
|
|
@@ -786,7 +784,7 @@ var checkHungarianBBAN = function (bban) {
|
|
|
786
784
|
* If `bban_validation_func` already exists for the corresponding country,
|
|
787
785
|
* it will be overwritten.
|
|
788
786
|
*/
|
|
789
|
-
|
|
787
|
+
const setCountryBBANValidation = (country, func) => {
|
|
790
788
|
if (typeof exports.countrySpecs[country] === 'undefined') {
|
|
791
789
|
return false;
|
|
792
790
|
}
|
|
@@ -988,7 +986,7 @@ exports.countrySpecs = {
|
|
|
988
986
|
IBANRegistry: true,
|
|
989
987
|
SEPA: true,
|
|
990
988
|
bank_identifier: '0-7',
|
|
991
|
-
account_indentifier: '
|
|
989
|
+
account_indentifier: '12-22',
|
|
992
990
|
},
|
|
993
991
|
DJ: {
|
|
994
992
|
chars: 27,
|
package/jsnext/ibantools.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* @package Documentation
|
|
13
13
|
* @author Saša Jovanić
|
|
14
14
|
* @module ibantools
|
|
15
|
-
* @version 4.5.
|
|
15
|
+
* @version 4.5.2
|
|
16
16
|
* @license MIT or MPL-2.0
|
|
17
17
|
* @preferred
|
|
18
18
|
*/
|
|
@@ -36,13 +36,12 @@
|
|
|
36
36
|
* ibantools.isValidIBAN('CH4431999123000889012', { allowQRIBAN: false });
|
|
37
37
|
* ```
|
|
38
38
|
*/
|
|
39
|
-
export function isValidIBAN(iban, validationOptions) {
|
|
40
|
-
if (validationOptions === void 0) { validationOptions = { allowQRIBAN: true }; }
|
|
39
|
+
export function isValidIBAN(iban, validationOptions = { allowQRIBAN: true }) {
|
|
41
40
|
if (iban === undefined || iban === null)
|
|
42
41
|
return false;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
const reg = new RegExp('^[0-9]{2}$', '');
|
|
43
|
+
const countryCode = iban.slice(0, 2);
|
|
44
|
+
const spec = countrySpecs[countryCode];
|
|
46
45
|
if (spec === undefined || spec.bban_regexp === undefined || spec.bban_regexp === null || spec.chars === undefined)
|
|
47
46
|
return false;
|
|
48
47
|
return (spec.chars === iban.length &&
|
|
@@ -81,11 +80,10 @@ export var ValidationErrorsIBAN;
|
|
|
81
80
|
* ibantools.validateIBAN('CH4431999123000889012', { allowQRIBAN: false });
|
|
82
81
|
* ```
|
|
83
82
|
*/
|
|
84
|
-
export function validateIBAN(iban, validationOptions) {
|
|
85
|
-
|
|
86
|
-
var result = { errorCodes: [], valid: true };
|
|
83
|
+
export function validateIBAN(iban, validationOptions = { allowQRIBAN: true }) {
|
|
84
|
+
const result = { errorCodes: [], valid: true };
|
|
87
85
|
if (iban !== undefined && iban !== null && iban !== '') {
|
|
88
|
-
|
|
86
|
+
const spec = countrySpecs[iban.slice(0, 2)];
|
|
89
87
|
if (!spec || !(spec.bban_regexp || spec.chars)) {
|
|
90
88
|
result.valid = false;
|
|
91
89
|
result.errorCodes.push(ValidationErrorsIBAN.NoIBANCountry);
|
|
@@ -103,7 +101,7 @@ export function validateIBAN(iban, validationOptions) {
|
|
|
103
101
|
result.valid = false;
|
|
104
102
|
result.errorCodes.push(ValidationErrorsIBAN.WrongAccountBankBranchChecksum);
|
|
105
103
|
}
|
|
106
|
-
|
|
104
|
+
const reg = new RegExp('^[0-9]{2}$', '');
|
|
107
105
|
if (!reg.test(iban.slice(2, 4))) {
|
|
108
106
|
result.valid = false;
|
|
109
107
|
result.errorCodes.push(ValidationErrorsIBAN.ChecksumNotNumber);
|
|
@@ -138,7 +136,7 @@ export function validateIBAN(iban, validationOptions) {
|
|
|
138
136
|
export function isValidBBAN(bban, countryCode) {
|
|
139
137
|
if (bban === undefined || bban === null || countryCode === undefined || countryCode === null)
|
|
140
138
|
return false;
|
|
141
|
-
|
|
139
|
+
const spec = countrySpecs[countryCode];
|
|
142
140
|
if (spec === undefined ||
|
|
143
141
|
spec === null ||
|
|
144
142
|
spec.bban_regexp === undefined ||
|
|
@@ -167,7 +165,7 @@ export function isValidBBAN(bban, countryCode) {
|
|
|
167
165
|
*/
|
|
168
166
|
export function isSEPACountry(countryCode) {
|
|
169
167
|
if (countryCode !== undefined && countryCode !== null) {
|
|
170
|
-
|
|
168
|
+
const spec = countrySpecs[countryCode];
|
|
171
169
|
if (spec !== undefined) {
|
|
172
170
|
return spec.SEPA ? spec.SEPA : false;
|
|
173
171
|
}
|
|
@@ -188,11 +186,11 @@ export function isSEPACountry(countryCode) {
|
|
|
188
186
|
export function isQRIBAN(iban) {
|
|
189
187
|
if (iban === undefined || iban === null)
|
|
190
188
|
return false;
|
|
191
|
-
|
|
192
|
-
|
|
189
|
+
const countryCode = iban.slice(0, 2);
|
|
190
|
+
const QRIBANCountries = ['LI', 'CH'];
|
|
193
191
|
if (!QRIBANCountries.includes(countryCode))
|
|
194
192
|
return false;
|
|
195
|
-
|
|
193
|
+
const reg = new RegExp('^3[0-1]{1}[0-9]{3}$', '');
|
|
196
194
|
return reg.test(iban.slice(4, 9));
|
|
197
195
|
}
|
|
198
196
|
/**
|
|
@@ -204,11 +202,11 @@ export function isQRIBAN(iban) {
|
|
|
204
202
|
* ```
|
|
205
203
|
*/
|
|
206
204
|
export function composeIBAN(params) {
|
|
207
|
-
|
|
205
|
+
const formated_bban = electronicFormatIBAN(params.bban) || '';
|
|
208
206
|
if (params.countryCode === null || params.countryCode === undefined) {
|
|
209
207
|
return null;
|
|
210
208
|
}
|
|
211
|
-
|
|
209
|
+
const spec = countrySpecs[params.countryCode];
|
|
212
210
|
if (formated_bban !== '' &&
|
|
213
211
|
spec !== undefined &&
|
|
214
212
|
spec.chars &&
|
|
@@ -217,7 +215,7 @@ export function composeIBAN(params) {
|
|
|
217
215
|
spec.bban_regexp &&
|
|
218
216
|
spec.bban_regexp !== null &&
|
|
219
217
|
checkFormatBBAN(formated_bban, spec.bban_regexp)) {
|
|
220
|
-
|
|
218
|
+
const checksom = mod9710Iban(params.countryCode + '00' + formated_bban);
|
|
221
219
|
return params.countryCode + ('0' + (98 - checksom)).slice(-2) + formated_bban;
|
|
222
220
|
}
|
|
223
221
|
return null;
|
|
@@ -230,30 +228,30 @@ export function composeIBAN(params) {
|
|
|
230
228
|
* ```
|
|
231
229
|
*/
|
|
232
230
|
export function extractIBAN(iban) {
|
|
233
|
-
|
|
234
|
-
|
|
231
|
+
const result = {};
|
|
232
|
+
const eFormatIBAN = electronicFormatIBAN(iban);
|
|
235
233
|
result.iban = eFormatIBAN || iban;
|
|
236
234
|
if (!!eFormatIBAN && isValidIBAN(eFormatIBAN)) {
|
|
237
235
|
result.bban = eFormatIBAN.slice(4);
|
|
238
236
|
result.countryCode = eFormatIBAN.slice(0, 2);
|
|
239
237
|
result.valid = true;
|
|
240
|
-
|
|
238
|
+
const spec = countrySpecs[result.countryCode];
|
|
241
239
|
if (spec.account_indentifier) {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
240
|
+
const ac = spec.account_indentifier.split('-');
|
|
241
|
+
const starting = parseInt(ac[0]);
|
|
242
|
+
const ending = parseInt(ac[1]);
|
|
245
243
|
result.accountNumber = result.iban.slice(starting, ending + 1);
|
|
246
244
|
}
|
|
247
245
|
if (spec.bank_identifier) {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
246
|
+
const ac = spec.bank_identifier.split('-');
|
|
247
|
+
const starting = parseInt(ac[0]);
|
|
248
|
+
const ending = parseInt(ac[1]);
|
|
251
249
|
result.bankIdentifier = result.bban.slice(starting, ending + 1);
|
|
252
250
|
}
|
|
253
251
|
if (spec.branch_indentifier) {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
252
|
+
const ac = spec.branch_indentifier.split('-');
|
|
253
|
+
const starting = parseInt(ac[0]);
|
|
254
|
+
const ending = parseInt(ac[1]);
|
|
257
255
|
result.branchIdentifier = result.bban.slice(starting, ending + 1);
|
|
258
256
|
}
|
|
259
257
|
}
|
|
@@ -268,7 +266,7 @@ export function extractIBAN(iban) {
|
|
|
268
266
|
* @ignore
|
|
269
267
|
*/
|
|
270
268
|
function checkFormatBBAN(bban, bformat) {
|
|
271
|
-
|
|
269
|
+
const reg = new RegExp(bformat, '');
|
|
272
270
|
return reg.test(bban);
|
|
273
271
|
}
|
|
274
272
|
/**
|
|
@@ -306,7 +304,7 @@ export function friendlyFormatIBAN(iban, separator) {
|
|
|
306
304
|
if (separator === undefined || separator === null) {
|
|
307
305
|
separator = ' ';
|
|
308
306
|
}
|
|
309
|
-
|
|
307
|
+
const electronic_iban = electronicFormatIBAN(iban);
|
|
310
308
|
/* istanbul ignore if */
|
|
311
309
|
if (electronic_iban === null) {
|
|
312
310
|
return null;
|
|
@@ -319,9 +317,9 @@ export function friendlyFormatIBAN(iban, separator) {
|
|
|
319
317
|
* @ignore
|
|
320
318
|
*/
|
|
321
319
|
function isValidIBANChecksum(iban) {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
320
|
+
const countryCode = iban.slice(0, 2);
|
|
321
|
+
const providedChecksum = parseInt(iban.slice(2, 4), 10);
|
|
322
|
+
const bban = iban.slice(4);
|
|
325
323
|
// Wikipedia[validating_iban] says there are a specif way to check if a IBAN is valid but
|
|
326
324
|
// it. It says 'If the remainder is 1, the check digit test is passed and the
|
|
327
325
|
// IBAN might be valid.'. might, MIGHT!
|
|
@@ -339,8 +337,8 @@ function isValidIBANChecksum(iban) {
|
|
|
339
337
|
//
|
|
340
338
|
// [validating_iban][https://en.wikipedia.org/wiki/International_Bank_Account_Number#Validating_the_IBAN]
|
|
341
339
|
// [generating-iban-check][https://en.wikipedia.org/wiki/International_Bank_Account_Number#Generating_IBAN_check_digits]
|
|
342
|
-
|
|
343
|
-
|
|
340
|
+
const validationString = replaceCharaterWithCode(`${bban}${countryCode}00`);
|
|
341
|
+
const rest = mod9710(validationString);
|
|
344
342
|
return 98 - rest === providedChecksum;
|
|
345
343
|
}
|
|
346
344
|
/**
|
|
@@ -354,8 +352,8 @@ function replaceCharaterWithCode(str) {
|
|
|
354
352
|
// https://jsbench.me/ttkzgsekae/1
|
|
355
353
|
return str
|
|
356
354
|
.split('')
|
|
357
|
-
.map(
|
|
358
|
-
|
|
355
|
+
.map((c) => {
|
|
356
|
+
const code = c.charCodeAt(0);
|
|
359
357
|
return code >= 65 ? (code - 55).toString() : c;
|
|
360
358
|
})
|
|
361
359
|
.join('');
|
|
@@ -391,9 +389,9 @@ function mod9710Iban(iban) {
|
|
|
391
389
|
* ```
|
|
392
390
|
*/
|
|
393
391
|
export function getCountrySpecifications() {
|
|
394
|
-
|
|
395
|
-
for (
|
|
396
|
-
|
|
392
|
+
const countyMap = {};
|
|
393
|
+
for (const countyCode in countrySpecs) {
|
|
394
|
+
const county = countrySpecs[countyCode];
|
|
397
395
|
countyMap[countyCode] = {
|
|
398
396
|
chars: county.chars || null,
|
|
399
397
|
bban_regexp: county.bban_regexp || null,
|
|
@@ -424,8 +422,8 @@ export function isValidBIC(bic) {
|
|
|
424
422
|
if (!bic) {
|
|
425
423
|
return false;
|
|
426
424
|
}
|
|
427
|
-
|
|
428
|
-
|
|
425
|
+
const reg = new RegExp('^[a-zA-Z]{6}[a-zA-Z0-9]{2}([a-zA-Z0-9]{3})?$', '');
|
|
426
|
+
const spec = countrySpecs[bic.toUpperCase().slice(4, 6)];
|
|
429
427
|
return reg.test(bic) && spec !== undefined;
|
|
430
428
|
}
|
|
431
429
|
/**
|
|
@@ -445,15 +443,15 @@ export var ValidationErrorsBIC;
|
|
|
445
443
|
* ```
|
|
446
444
|
*/
|
|
447
445
|
export function validateBIC(bic) {
|
|
448
|
-
|
|
446
|
+
const result = { errorCodes: [], valid: true };
|
|
449
447
|
if (bic !== undefined && bic !== null && bic !== '') {
|
|
450
|
-
|
|
448
|
+
const spec = countrySpecs[bic.toUpperCase().slice(4, 6)];
|
|
451
449
|
if (spec === undefined) {
|
|
452
450
|
result.valid = false;
|
|
453
451
|
result.errorCodes.push(ValidationErrorsBIC.NoBICCountry);
|
|
454
452
|
}
|
|
455
453
|
else {
|
|
456
|
-
|
|
454
|
+
const reg = new RegExp('^[a-zA-Z]{6}[a-zA-Z0-9]{2}([a-zA-Z0-9]{3})?$', '');
|
|
457
455
|
if (!reg.test(bic)) {
|
|
458
456
|
result.valid = false;
|
|
459
457
|
result.errorCodes.push(ValidationErrorsBIC.WrongBICFormat);
|
|
@@ -474,8 +472,8 @@ export function validateBIC(bic) {
|
|
|
474
472
|
* ```
|
|
475
473
|
*/
|
|
476
474
|
export function extractBIC(inputBic) {
|
|
477
|
-
|
|
478
|
-
|
|
475
|
+
const result = {};
|
|
476
|
+
const bic = inputBic.toUpperCase();
|
|
479
477
|
if (isValidBIC(bic)) {
|
|
480
478
|
result.bankCode = bic.slice(0, 4);
|
|
481
479
|
result.countryCode = bic.slice(4, 6);
|
|
@@ -494,16 +492,16 @@ export function extractBIC(inputBic) {
|
|
|
494
492
|
*
|
|
495
493
|
* @ignore
|
|
496
494
|
*/
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
for (
|
|
495
|
+
const checkNorwayBBAN = (bban) => {
|
|
496
|
+
const weights = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2];
|
|
497
|
+
const bbanWithoutSpacesAndPeriods = bban.replace(/[\s.]+/g, '');
|
|
498
|
+
const controlDigit = parseInt(bbanWithoutSpacesAndPeriods.charAt(10), 10);
|
|
499
|
+
const bbanWithoutControlDigit = bbanWithoutSpacesAndPeriods.substring(0, 10);
|
|
500
|
+
let sum = 0;
|
|
501
|
+
for (let index = 0; index < 10; index++) {
|
|
504
502
|
sum += parseInt(bbanWithoutControlDigit.charAt(index), 10) * weights[index];
|
|
505
503
|
}
|
|
506
|
-
|
|
504
|
+
const remainder = sum % 11;
|
|
507
505
|
return controlDigit === (remainder === 0 ? 0 : 11 - remainder);
|
|
508
506
|
};
|
|
509
507
|
/**
|
|
@@ -511,11 +509,11 @@ var checkNorwayBBAN = function (bban) {
|
|
|
511
509
|
*
|
|
512
510
|
* @ignore
|
|
513
511
|
*/
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
512
|
+
const checkBelgianBBAN = (bban) => {
|
|
513
|
+
const stripped = bban.replace(/[\s.]+/g, '');
|
|
514
|
+
const checkingPart = parseInt(stripped.substring(0, stripped.length - 2), 10);
|
|
515
|
+
const checksum = parseInt(stripped.substring(stripped.length - 2, stripped.length), 10);
|
|
516
|
+
const remainder = checkingPart % 97 === 0 ? 97 : checkingPart % 97;
|
|
519
517
|
return remainder === checksum;
|
|
520
518
|
};
|
|
521
519
|
/**
|
|
@@ -523,15 +521,15 @@ var checkBelgianBBAN = function (bban) {
|
|
|
523
521
|
*
|
|
524
522
|
* @ignore
|
|
525
523
|
*/
|
|
526
|
-
|
|
524
|
+
const mod9710 = (validationString) => {
|
|
527
525
|
while (validationString.length > 2) {
|
|
528
526
|
// > Any computer programming language or software package that is used to compute D
|
|
529
527
|
// > mod 97 directly must have the ability to handle integers of more than 30 digits.
|
|
530
528
|
// > In practice, this can only be done by software that either supports
|
|
531
529
|
// > arbitrary-precision arithmetic or that can handle 219-bit (unsigned) integers
|
|
532
530
|
// https://en.wikipedia.org/wiki/International_Bank_Account_Number#Modulo_operation_on_IBAN
|
|
533
|
-
|
|
534
|
-
|
|
531
|
+
const part = validationString.slice(0, 6);
|
|
532
|
+
const partInt = parseInt(part, 10);
|
|
535
533
|
if (isNaN(partInt)) {
|
|
536
534
|
return NaN;
|
|
537
535
|
}
|
|
@@ -545,9 +543,9 @@ var mod9710 = function (validationString) {
|
|
|
545
543
|
*
|
|
546
544
|
* @ignore
|
|
547
545
|
*/
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
546
|
+
const checkMod9710BBAN = (bban) => {
|
|
547
|
+
const stripped = bban.replace(/[\s.]+/g, '');
|
|
548
|
+
const reminder = mod9710(stripped);
|
|
551
549
|
return reminder === 1;
|
|
552
550
|
};
|
|
553
551
|
/**
|
|
@@ -555,15 +553,15 @@ var checkMod9710BBAN = function (bban) {
|
|
|
555
553
|
*
|
|
556
554
|
* @ignore
|
|
557
555
|
*/
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
for (
|
|
556
|
+
const checkPolandBBAN = (bban) => {
|
|
557
|
+
const weights = [3, 9, 7, 1, 3, 9, 7];
|
|
558
|
+
const controlDigit = parseInt(bban.charAt(7), 10);
|
|
559
|
+
const toCheck = bban.substring(0, 7);
|
|
560
|
+
let sum = 0;
|
|
561
|
+
for (let index = 0; index < 7; index++) {
|
|
564
562
|
sum += parseInt(toCheck.charAt(index), 10) * weights[index];
|
|
565
563
|
}
|
|
566
|
-
|
|
564
|
+
const remainder = sum % 10;
|
|
567
565
|
return controlDigit === (remainder === 0 ? 0 : 10 - remainder);
|
|
568
566
|
};
|
|
569
567
|
/**
|
|
@@ -571,23 +569,23 @@ var checkPolandBBAN = function (bban) {
|
|
|
571
569
|
*
|
|
572
570
|
* @ignore
|
|
573
571
|
*/
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
for (
|
|
572
|
+
const checkSpainBBAN = (bban) => {
|
|
573
|
+
const weightsBankBranch = [4, 8, 5, 10, 9, 7, 3, 6];
|
|
574
|
+
const weightsAccount = [1, 2, 4, 8, 5, 10, 9, 7, 3, 6];
|
|
575
|
+
const controlBankBranch = parseInt(bban.charAt(8), 10);
|
|
576
|
+
const controlAccount = parseInt(bban.charAt(9), 10);
|
|
577
|
+
const bankBranch = bban.substring(0, 8);
|
|
578
|
+
const account = bban.substring(10, 20);
|
|
579
|
+
let sum = 0;
|
|
580
|
+
for (let index = 0; index < 8; index++) {
|
|
583
581
|
sum += parseInt(bankBranch.charAt(index), 10) * weightsBankBranch[index];
|
|
584
582
|
}
|
|
585
|
-
|
|
583
|
+
let remainder = sum % 11;
|
|
586
584
|
if (controlBankBranch !== (remainder === 0 ? 0 : remainder === 1 ? 1 : 11 - remainder)) {
|
|
587
585
|
return false;
|
|
588
586
|
}
|
|
589
587
|
sum = 0;
|
|
590
|
-
for (
|
|
588
|
+
for (let index = 0; index < 10; index++) {
|
|
591
589
|
sum += parseInt(account.charAt(index), 10) * weightsAccount[index];
|
|
592
590
|
}
|
|
593
591
|
remainder = sum % 11;
|
|
@@ -598,9 +596,9 @@ var checkSpainBBAN = function (bban) {
|
|
|
598
596
|
*
|
|
599
597
|
* @ignore
|
|
600
598
|
*/
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
for (
|
|
599
|
+
const checkMod1110 = (toCheck, control) => {
|
|
600
|
+
let nr = 10;
|
|
601
|
+
for (let index = 0; index < toCheck.length; index++) {
|
|
604
602
|
nr += parseInt(toCheck.charAt(index), 10);
|
|
605
603
|
if (nr % 10 !== 0) {
|
|
606
604
|
nr = nr % 10;
|
|
@@ -615,11 +613,11 @@ var checkMod1110 = function (toCheck, control) {
|
|
|
615
613
|
*
|
|
616
614
|
* @ignore
|
|
617
615
|
*/
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
616
|
+
const checkCroatianBBAN = (bban) => {
|
|
617
|
+
const controlBankBranch = parseInt(bban.charAt(6), 10);
|
|
618
|
+
const controlAccount = parseInt(bban.charAt(16), 10);
|
|
619
|
+
const bankBranch = bban.substring(0, 6);
|
|
620
|
+
const account = bban.substring(7, 16);
|
|
623
621
|
return checkMod1110(bankBranch, controlBankBranch) && checkMod1110(account, controlAccount);
|
|
624
622
|
};
|
|
625
623
|
/**
|
|
@@ -627,23 +625,23 @@ var checkCroatianBBAN = function (bban) {
|
|
|
627
625
|
*
|
|
628
626
|
* @ignore
|
|
629
627
|
*/
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
for (
|
|
628
|
+
const checkCzechAndSlovakBBAN = (bban) => {
|
|
629
|
+
const weightsPrefix = [10, 5, 8, 4, 2, 1];
|
|
630
|
+
const weightsSuffix = [6, 3, 7, 9, 10, 5, 8, 4, 2, 1];
|
|
631
|
+
const controlPrefix = parseInt(bban.charAt(9), 10);
|
|
632
|
+
const controlSuffix = parseInt(bban.charAt(19), 10);
|
|
633
|
+
const prefix = bban.substring(4, 9);
|
|
634
|
+
const suffix = bban.substring(10, 19);
|
|
635
|
+
let sum = 0;
|
|
636
|
+
for (let index = 0; index < prefix.length; index++) {
|
|
639
637
|
sum += parseInt(prefix.charAt(index), 10) * weightsPrefix[index];
|
|
640
638
|
}
|
|
641
|
-
|
|
639
|
+
let remainder = sum % 11;
|
|
642
640
|
if (controlPrefix !== (remainder === 0 ? 0 : remainder === 1 ? 1 : 11 - remainder)) {
|
|
643
641
|
return false;
|
|
644
642
|
}
|
|
645
643
|
sum = 0;
|
|
646
|
-
for (
|
|
644
|
+
for (let index = 0; index < suffix.length; index++) {
|
|
647
645
|
sum += parseInt(suffix.charAt(index), 10) * weightsSuffix[index];
|
|
648
646
|
}
|
|
649
647
|
remainder = sum % 11;
|
|
@@ -654,15 +652,15 @@ var checkCzechAndSlovakBBAN = function (bban) {
|
|
|
654
652
|
*
|
|
655
653
|
* @ignore
|
|
656
654
|
*/
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
for (
|
|
655
|
+
const checkEstonianBBAN = (bban) => {
|
|
656
|
+
const weights = [7, 1, 3, 7, 1, 3, 7, 1, 3, 7, 1, 3, 7];
|
|
657
|
+
const controlDigit = parseInt(bban.charAt(15), 10);
|
|
658
|
+
const toCheck = bban.substring(2, 15);
|
|
659
|
+
let sum = 0;
|
|
660
|
+
for (let index = 0; index < toCheck.length; index++) {
|
|
663
661
|
sum += parseInt(toCheck.charAt(index), 10) * weights[index];
|
|
664
662
|
}
|
|
665
|
-
|
|
663
|
+
const remainder = sum % 10;
|
|
666
664
|
return controlDigit === (remainder === 0 ? 0 : 10 - remainder);
|
|
667
665
|
};
|
|
668
666
|
/**
|
|
@@ -671,11 +669,11 @@ var checkEstonianBBAN = function (bban) {
|
|
|
671
669
|
*
|
|
672
670
|
* @ignore
|
|
673
671
|
*/
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
for (
|
|
678
|
-
|
|
672
|
+
const checkFrenchBBAN = (bban) => {
|
|
673
|
+
const stripped = bban.replace(/[\s.]+/g, '');
|
|
674
|
+
const normalized = Array.from(stripped);
|
|
675
|
+
for (let index = 0; index < stripped.length; index++) {
|
|
676
|
+
const c = normalized[index].charCodeAt(0);
|
|
679
677
|
if (c >= 65) {
|
|
680
678
|
switch (c) {
|
|
681
679
|
case 65:
|
|
@@ -725,7 +723,7 @@ var checkFrenchBBAN = function (bban) {
|
|
|
725
723
|
}
|
|
726
724
|
}
|
|
727
725
|
}
|
|
728
|
-
|
|
726
|
+
const remainder = mod9710(normalized.join(''));
|
|
729
727
|
return remainder === 0;
|
|
730
728
|
};
|
|
731
729
|
/**
|
|
@@ -733,36 +731,36 @@ var checkFrenchBBAN = function (bban) {
|
|
|
733
731
|
*
|
|
734
732
|
* @ignore
|
|
735
733
|
*/
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
for (
|
|
734
|
+
const checkHungarianBBAN = (bban) => {
|
|
735
|
+
const weights = [9, 7, 3, 1, 9, 7, 3, 1, 9, 7, 3, 1, 9, 7, 3];
|
|
736
|
+
const controlDigitBankBranch = parseInt(bban.charAt(7), 10);
|
|
737
|
+
const toCheckBankBranch = bban.substring(0, 7);
|
|
738
|
+
let sum = 0;
|
|
739
|
+
for (let index = 0; index < toCheckBankBranch.length; index++) {
|
|
742
740
|
sum += parseInt(toCheckBankBranch.charAt(index), 10) * weights[index];
|
|
743
741
|
}
|
|
744
|
-
|
|
742
|
+
const remainder = sum % 10;
|
|
745
743
|
if (controlDigitBankBranch !== (remainder === 0 ? 0 : 10 - remainder)) {
|
|
746
744
|
return false;
|
|
747
745
|
}
|
|
748
746
|
sum = 0;
|
|
749
747
|
if (bban.endsWith('00000000')) {
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
for (
|
|
748
|
+
const toCheckAccount = bban.substring(8, 15);
|
|
749
|
+
const controlDigitAccount = parseInt(bban.charAt(15), 10);
|
|
750
|
+
for (let index = 0; index < toCheckAccount.length; index++) {
|
|
753
751
|
sum += parseInt(toCheckAccount.charAt(index), 10) * weights[index];
|
|
754
752
|
}
|
|
755
|
-
|
|
756
|
-
return controlDigitAccount === (
|
|
753
|
+
const remainder = sum % 10;
|
|
754
|
+
return controlDigitAccount === (remainder === 0 ? 0 : 10 - remainder);
|
|
757
755
|
}
|
|
758
756
|
else {
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
for (
|
|
757
|
+
const toCheckAccount = bban.substring(8, 23);
|
|
758
|
+
const controlDigitAccount = parseInt(bban.charAt(23), 10);
|
|
759
|
+
for (let index = 0; index < toCheckAccount.length; index++) {
|
|
762
760
|
sum += parseInt(toCheckAccount.charAt(index), 10) * weights[index];
|
|
763
761
|
}
|
|
764
|
-
|
|
765
|
-
return controlDigitAccount === (
|
|
762
|
+
const remainder = sum % 10;
|
|
763
|
+
return controlDigitAccount === (remainder === 0 ? 0 : 10 - remainder);
|
|
766
764
|
}
|
|
767
765
|
};
|
|
768
766
|
/**
|
|
@@ -771,7 +769,7 @@ var checkHungarianBBAN = function (bban) {
|
|
|
771
769
|
* If `bban_validation_func` already exists for the corresponding country,
|
|
772
770
|
* it will be overwritten.
|
|
773
771
|
*/
|
|
774
|
-
export
|
|
772
|
+
export const setCountryBBANValidation = (country, func) => {
|
|
775
773
|
if (typeof countrySpecs[country] === 'undefined') {
|
|
776
774
|
return false;
|
|
777
775
|
}
|
|
@@ -781,7 +779,7 @@ export var setCountryBBANValidation = function (country, func) {
|
|
|
781
779
|
/**
|
|
782
780
|
* Country specifications
|
|
783
781
|
*/
|
|
784
|
-
export
|
|
782
|
+
export const countrySpecs = {
|
|
785
783
|
AD: {
|
|
786
784
|
chars: 24,
|
|
787
785
|
bban_regexp: '^[0-9]{8}[A-Z0-9]{12}$',
|
|
@@ -972,7 +970,7 @@ export var countrySpecs = {
|
|
|
972
970
|
IBANRegistry: true,
|
|
973
971
|
SEPA: true,
|
|
974
972
|
bank_identifier: '0-7',
|
|
975
|
-
account_indentifier: '
|
|
973
|
+
account_indentifier: '12-22',
|
|
976
974
|
},
|
|
977
975
|
DJ: {
|
|
978
976
|
chars: 27,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ibantools",
|
|
3
|
-
"version": "4.5.
|
|
3
|
+
"version": "4.5.2",
|
|
4
4
|
"description": "Validation, extraction and creation of IBAN, BBAN, BIC/SWIFT numbers plus some other helpful stuff like ISO 3136-1 alpha 2 country list",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"IBAN",
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
"sideEffects": false,
|
|
14
14
|
"homepage": "https://github.com/Simplify/ibantools",
|
|
15
15
|
"bugs": "https://github.com/Simplify/ibantools/issues",
|
|
16
|
-
"main": "
|
|
16
|
+
"main": "jsnext/ibantools.js",
|
|
17
|
+
"type": "module",
|
|
17
18
|
"module": "jsnext/ibantools.js",
|
|
18
19
|
"jspm": {
|
|
19
20
|
"main": "jsnext/ibantools.js",
|
|
@@ -38,16 +39,15 @@
|
|
|
38
39
|
},
|
|
39
40
|
"scripts": {
|
|
40
41
|
"build": "npm run build-node && npm run build-bower && npm run build-module",
|
|
41
|
-
"build-node": "rm -rf build && npx tsc src/*.ts --declaration --target
|
|
42
|
-
"build-bower": "rm -rf dist && npx tsc src/*.ts --declaration --target
|
|
43
|
-
"build-module": "rm -rf jsnext && npx tsc src/*.ts --target
|
|
42
|
+
"build-node": "rm -rf build && npx tsc src/*.ts --declaration --target es2017 --module commonjs --outDir ./build/",
|
|
43
|
+
"build-bower": "rm -rf dist && npx tsc src/*.ts --declaration --target es2017 --module amd --outDir ./dist/",
|
|
44
|
+
"build-module": "rm -rf jsnext && npx tsc src/*.ts --target es2017 --module es2020 --outDir ./jsnext/",
|
|
44
45
|
"test": "npm run build && mocha 'test/**/*.js'",
|
|
45
|
-
"
|
|
46
|
-
"coverage": "nyc mocha && nyc report --reporter=text-lcov > test.lcov",
|
|
46
|
+
"coverage": "npm run build && c8 mocha && c8 report --reporter=text-lcov > test.lcov",
|
|
47
47
|
"lint": "eslint 'src/**/*.ts' 'test/**/*.js'",
|
|
48
48
|
"prepare": "npm run build-node",
|
|
49
49
|
"docs": "typedoc src/ibantools.ts",
|
|
50
|
-
"all": "npm run test && npm run lint && npm run
|
|
50
|
+
"all": "npm run test && npm run lint && npm run docs"
|
|
51
51
|
},
|
|
52
52
|
"author": {
|
|
53
53
|
"name": "Saša Jovanić",
|
|
@@ -55,25 +55,22 @@
|
|
|
55
55
|
},
|
|
56
56
|
"license": "MIT or MPL-2.0",
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@
|
|
59
|
-
"@
|
|
60
|
-
"
|
|
61
|
-
"
|
|
58
|
+
"@eslint/eslintrc": "^3.3.5",
|
|
59
|
+
"@eslint/js": "^10.0.1",
|
|
60
|
+
"@typescript-eslint/eslint-plugin": "^8.58",
|
|
61
|
+
"@typescript-eslint/parser": "^8.58",
|
|
62
|
+
"c8": "^10.1.2",
|
|
63
|
+
"chai": "^5.0.10",
|
|
64
|
+
"coveralls-next": "^6.0.1",
|
|
62
65
|
"docdash": "^2.0.0",
|
|
63
|
-
"eslint": "^
|
|
66
|
+
"eslint": "^10.0.0",
|
|
64
67
|
"eslint-config-prettier": "^9.0.0",
|
|
65
68
|
"eslint-plugin-prettier": "^5.0.0",
|
|
66
|
-
"
|
|
67
|
-
"karma": "^6.3.4",
|
|
68
|
-
"karma-chrome-launcher": "^3.1",
|
|
69
|
-
"karma-jasmine": "^5.0",
|
|
70
|
-
"karma-requirejs": "^1.1",
|
|
71
|
-
"mocha": "^10.0.0",
|
|
69
|
+
"mocha": "^11.0.1",
|
|
72
70
|
"mocha-lcov-reporter": "^1.2.0",
|
|
73
|
-
"nyc": "^15.1.0",
|
|
74
71
|
"prettier": "^3.0.3",
|
|
75
72
|
"requirejs": "^2.3.6",
|
|
76
|
-
"typedoc": "^0.
|
|
73
|
+
"typedoc": "^0.27.2",
|
|
77
74
|
"typescript": "^5.2"
|
|
78
75
|
},
|
|
79
76
|
"resolutions": {
|