ibantools 3.3.1 → 4.1.1

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/ChangeLog CHANGED
@@ -1,3 +1,52 @@
1
+ 2021-12-05 Saša Jovanić <sasa@simplify.ba>
2
+ * Added Hungarian (HU) BBAN validation
3
+
4
+ 2021-12-01 Saša Jovanić <sasa@simplify.ba>
5
+ * Improve test coverage
6
+
7
+ 2021-11-30 Saša Jovanić <sasa@simplify.ba>
8
+ * Added Estonian (EE) BBAN validation
9
+ * Added Finland (FI) BBAN validation
10
+ * Aland Islands (AX) uses BBAN valkidation from Finland
11
+ * Added French (FR) and Monaco (MC) BBAN validation
12
+
13
+ 2021-11-28 Saša Jovanić <sasa@simplify.ba>
14
+ * Added Czech (CZ) BBAN validation
15
+
16
+ 2021-11-27 Saša Jovanić <sasa@simplify.ba>
17
+ * Added Croatian (HR) BBAN validation
18
+
19
+ 2021-11-25 Saša Jovanić <sasa@simplify.ba>
20
+ * Version 4.1.0
21
+ * Added Belgian (BE) extra BBAN validation
22
+ * Added mod97/10 BBAN validation for countries that do it that way: BA, ME, MK, PT, RS and SI
23
+
24
+ 2021-11-24 Saša Jovanić <sasa@simplify.ba>
25
+ * Added Netherlands (NL) extra BBAN validation
26
+ * Added extra error code when validating IBAN `WrongAccountBankBranchChecksum` that indicates when checksum for account number or bank or branch code is incorrect
27
+
28
+ 2021-11-23 Saša Jovanić <sasa@simplify.ba>
29
+ * Version 4.0.1
30
+ * Fixed bug when validating Spain IBAN
31
+
32
+ 2021-11-18 Saša Jovanić <sasa@simplify.ba>
33
+ * Updated README with new and updated badges
34
+ * Fixed documentation on GH pages
35
+ * Added dependabot dependency updates and merged some created dependency pull requests
36
+ * Added Node 17 to build version on GitHub actions
37
+ * Added GitHub CodeQL workflow
38
+
39
+ 2021-11-17 Saša Jovanić <sasa@simplify.ba>
40
+ * Version 4.0.0
41
+ * Fixed Senegal (SN) regular expression
42
+ * Updated Burundi (BI) specification
43
+ * Added Spain (ES) extra BBAN validation
44
+ * Added Poland (PL) extra BBAN validation
45
+ * Added test to check for extra BBAN validation function
46
+
47
+ 2021-09-30 Simen Mailund Svendsen <simen.m.s@hotmail.com>
48
+ * Fix invalid norwegian BBANS (failing MOD11 check) being incorrectly returned as valid
49
+
1
50
  2021-07-24 Saša Jovanić <sasa@simplify.ba>
2
51
  * Version 3.3.1
3
52
  * Fixed issue not showing AD and BG as SEPA countries
package/README.md CHANGED
@@ -1,16 +1,27 @@
1
1
  # IBANTools
2
2
 
3
- [![License](https://img.shields.io/badge/license-MPL%202.0-green.svg?dummy)](https://github.com/Simplify/ibantools/blob/master/LICENSE)
3
+ [![License](https://img.shields.io/github/license/Simplify/ibantools)](https://github.com/Simplify/ibantools/blob/master/LICENSE)
4
4
 
5
5
  [![Bower version](https://badge.fury.io/bo/ibantools.svg)](https://badge.fury.io/bo/ibantools)
6
6
  [![npm version](https://badge.fury.io/js/ibantools.svg)](https://badge.fury.io/js/ibantools)
7
+ [![NPM downloads](https://img.shields.io/npm/dw/ibantools)](https://www.npmjs.com/package/ibantools)
8
+ ![Dependents (via libraries.io)](https://img.shields.io/librariesio/dependents/npm/ibantools)
7
9
 
8
10
  ![Build CI](https://github.com/Simplify/ibantools/workflows/Build%20CI%20(Master)/badge.svg?branch=master)
9
11
  ![ESLint & Prettier CI](https://github.com/Simplify/ibantools/workflows/ESLint%20&%20Prettier/badge.svg?branch=master)
10
12
  [![Coverage Status](https://coveralls.io/repos/github/Simplify/ibantools/badge.svg?branch=master)](https://coveralls.io/github/Simplify/ibantools?branch=master)
11
13
 
12
- [![devDependency Status](https://david-dm.org/simplify/ibantools/dev-status.svg)](https://david-dm.org/simplify/ibantools#info=devDependencies)
13
- [![Dependency Status](https://david-dm.org/simplify/ibantools.svg)](https://david-dm.org/simplify/ibantools)
14
+ ![GitHub last commit](https://img.shields.io/github/last-commit/Simplify/IBANtools)
15
+ ![GitHub contributors](https://img.shields.io/github/contributors/Simplify/IBANTools)
16
+ ![GitHub issues](https://img.shields.io/github/issues/Simplify/ibantools)
17
+ ![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/Simplify/ibantools)
18
+ ![GitHub pull requests](https://img.shields.io/github/issues-pr/Simplify/ibantools)
19
+ ![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed/Simplify/IBANTools)
20
+
21
+ ![No deps](https://img.shields.io/badge/dependencies-0-brightgreen)
22
+ ![dev deps](https://img.shields.io/librariesio/github/Simplify/IBANTools?label=devDependencies)
23
+
24
+ ## About
14
25
 
15
26
  IBANTools is TypeScript/JavaScript library for validation, creation and extraction of IBAN, BBAN and BIC/SWIFT numbers.
16
27
 
@@ -19,7 +30,7 @@ For more information about IBAN/BBAN see [wikipedia page](https://en.wikipedia.o
19
30
 
20
31
  For more information about BIC/SWIFT see [this wikipedia page](https://en.wikipedia.org/wiki/ISO_9362).
21
32
 
22
- ## Installation and usage
33
+ ## Installation
23
34
 
24
35
  ### Node (Common JS ES5 and ES6)
25
36
 
@@ -13,7 +13,7 @@
13
13
  * // returns false
14
14
  * ibantools.isValidIBAN("NL92ABNA0517164300");
15
15
  * ```
16
- v */
16
+ */
17
17
  export declare function isValidIBAN(iban: string): boolean;
18
18
  /**
19
19
  * IBAM validation errors
@@ -24,7 +24,8 @@ export declare enum ValidationErrorsIBAN {
24
24
  WrongBBANLength = 2,
25
25
  WrongBBANFormat = 3,
26
26
  ChecksumNotNumber = 4,
27
- WrongIBANChecksum = 5
27
+ WrongIBANChecksum = 5,
28
+ WrongAccountBankBranchChecksum = 6
28
29
  }
29
30
  /**
30
31
  * Interface for ValidateIBAN result
@@ -227,6 +228,7 @@ export interface CountryMap {
227
228
  interface CountrySpecInternal {
228
229
  chars?: number;
229
230
  bban_regexp?: string;
231
+ bban_validation_func?: (bban: string) => boolean;
230
232
  IBANRegistry?: boolean;
231
233
  SEPA?: boolean;
232
234
  }
@@ -5,10 +5,10 @@
5
5
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
6
  /**
7
7
  * Validation, extraction and creation of IBAN, BBAN, BIC/SWIFT numbers plus some other helpful stuff
8
- * @packageDocumentation
8
+ * @package Documentation
9
9
  * @author Saša Jovanić
10
10
  * @module ibantools
11
- * @version 3.3.1
11
+ * @version 4.1.1
12
12
  * @license MPL-2.0
13
13
  * @preferred
14
14
  */
@@ -25,7 +25,7 @@ exports.countrySpecs = exports.extractBIC = exports.validateBIC = exports.Valida
25
25
  * // returns false
26
26
  * ibantools.isValidIBAN("NL92ABNA0517164300");
27
27
  * ```
28
- v */
28
+ */
29
29
  function isValidIBAN(iban) {
30
30
  if (iban !== undefined && iban !== null) {
31
31
  var reg = new RegExp('^[0-9]{2}$', '');
@@ -36,7 +36,7 @@ function isValidIBAN(iban) {
36
36
  spec.chars &&
37
37
  spec.chars === iban.length &&
38
38
  reg.test(iban.slice(2, 4)) &&
39
- checkFormatBBAN(iban.slice(4), spec.bban_regexp) &&
39
+ isValidBBAN(iban.slice(4), iban.slice(0, 2)) &&
40
40
  isValidIBANChecksum(iban)) {
41
41
  return true;
42
42
  }
@@ -55,6 +55,7 @@ var ValidationErrorsIBAN;
55
55
  ValidationErrorsIBAN[ValidationErrorsIBAN["WrongBBANFormat"] = 3] = "WrongBBANFormat";
56
56
  ValidationErrorsIBAN[ValidationErrorsIBAN["ChecksumNotNumber"] = 4] = "ChecksumNotNumber";
57
57
  ValidationErrorsIBAN[ValidationErrorsIBAN["WrongIBANChecksum"] = 5] = "WrongIBANChecksum";
58
+ ValidationErrorsIBAN[ValidationErrorsIBAN["WrongAccountBankBranchChecksum"] = 6] = "WrongAccountBankBranchChecksum";
58
59
  })(ValidationErrorsIBAN = exports.ValidationErrorsIBAN || (exports.ValidationErrorsIBAN = {}));
59
60
  /**
60
61
  * validateIBAN
@@ -79,6 +80,10 @@ function validateIBAN(iban) {
79
80
  result.valid = false;
80
81
  result.errorCodes.push(ValidationErrorsIBAN.WrongBBANFormat);
81
82
  }
83
+ if (spec && spec.bban_validation_func && !spec.bban_validation_func(iban.slice(4))) {
84
+ result.valid = false;
85
+ result.errorCodes.push(ValidationErrorsIBAN.WrongAccountBankBranchChecksum);
86
+ }
82
87
  var reg = new RegExp('^[0-9]{2}$', '');
83
88
  if (!reg.test(iban.slice(2, 4))) {
84
89
  result.valid = false;
@@ -119,6 +124,9 @@ function isValidBBAN(bban, countryCode) {
119
124
  spec.chars !== null &&
120
125
  spec.chars - 4 === bban.length &&
121
126
  checkFormatBBAN(bban, spec.bban_regexp)) {
127
+ if (spec.bban_validation_func) {
128
+ return spec.bban_validation_func(bban.replace(/[\s.]+/g, ''));
129
+ }
122
130
  return true;
123
131
  }
124
132
  }
@@ -168,7 +176,7 @@ function composeIBAN(params) {
168
176
  spec.bban_regexp &&
169
177
  spec.bban_regexp !== null &&
170
178
  checkFormatBBAN(formated_bban, spec.bban_regexp)) {
171
- var checksom = mod9710(params.countryCode + '00' + formated_bban);
179
+ var checksom = mod9710Iban(params.countryCode + '00' + formated_bban);
172
180
  return params.countryCode + ('0' + (98 - checksom)).slice(-2) + formated_bban;
173
181
  }
174
182
  return null;
@@ -278,7 +286,7 @@ function isValidIBANChecksum(iban) {
278
286
  *
279
287
  * @ignore
280
288
  */
281
- function mod9710(iban) {
289
+ function mod9710Iban(iban) {
282
290
  iban = iban.slice(3) + iban.slice(0, 4);
283
291
  var validationString = '';
284
292
  for (var n = 1; n < iban.length; n++) {
@@ -290,11 +298,7 @@ function mod9710(iban) {
290
298
  validationString += iban[n];
291
299
  }
292
300
  }
293
- while (validationString.length > 2) {
294
- var part = validationString.slice(0, 6);
295
- validationString = (parseInt(part, 10) % 97).toString() + validationString.slice(part.length);
296
- }
297
- return parseInt(validationString, 10) % 97;
301
+ return mod9710(validationString);
298
302
  }
299
303
  /**
300
304
  * Returns specifications for all countries, even those who are not
@@ -421,6 +425,325 @@ function extractBIC(inputBic) {
421
425
  return result;
422
426
  }
423
427
  exports.extractBIC = extractBIC;
428
+ /**
429
+ * Used for Norway BBAN check
430
+ *
431
+ * @ignore
432
+ */
433
+ var checkNorwayBBAN = function (bban) {
434
+ var weights = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2];
435
+ var bbanWithoutSpacesAndPeriods = bban.replace(/[\s.]+/g, '');
436
+ var controlDigit = parseInt(bbanWithoutSpacesAndPeriods.charAt(10), 10);
437
+ var bbanWithoutControlDigit = bbanWithoutSpacesAndPeriods.substring(0, 10);
438
+ var sum = 0;
439
+ for (var index = 0; index < 10; index++) {
440
+ sum += parseInt(bbanWithoutControlDigit.charAt(index), 10) * weights[index];
441
+ }
442
+ var remainder = sum % 11;
443
+ return controlDigit === (remainder === 0 ? 0 : 11 - remainder);
444
+ };
445
+ /**
446
+ * Used for Netherlands BBAN check
447
+ *
448
+ * @ignore
449
+ */
450
+ var checkDutchBBAN = function (bban) {
451
+ var bbanWithoutSpacesAndPeriods = bban.replace(/[\s.]+/g, '');
452
+ var accountNumber = bbanWithoutSpacesAndPeriods.substring(4, 14);
453
+ if (accountNumber.startsWith('000')) {
454
+ return true; // Postbank account, no `elfproef` possible
455
+ }
456
+ var sum = 0;
457
+ for (var index = 0; index < 10; index++) {
458
+ sum += parseInt(accountNumber.charAt(index), 10) * (10 - index);
459
+ }
460
+ return sum % 11 === 0;
461
+ };
462
+ /**
463
+ * Used for Belgian BBAN check
464
+ *
465
+ * @ignore
466
+ */
467
+ var checkBelgianBBAN = function (bban) {
468
+ var stripped = bban.replace(/[\s.]+/g, '');
469
+ var checkingPart = parseInt(stripped.substring(0, stripped.length - 2), 10);
470
+ var checksum = parseInt(stripped.substring(stripped.length - 2, stripped.length), 10);
471
+ var remainder = checkingPart % 97 === 0 ? 97 : checkingPart % 97;
472
+ return remainder === checksum;
473
+ };
474
+ /**
475
+ * Mod 97/10 calculation
476
+ *
477
+ * @ignore
478
+ */
479
+ var mod9710 = function (validationString) {
480
+ while (validationString.length > 2) {
481
+ var part = validationString.slice(0, 6);
482
+ validationString = (parseInt(part, 10) % 97).toString() + validationString.slice(part.length);
483
+ }
484
+ return parseInt(validationString, 10) % 97;
485
+ };
486
+ /**
487
+ * Check BBAN based on Mod97/10 calculation for countries that support it:
488
+ * BA, ME, MK, PT, RS, SI
489
+ *
490
+ * @ignore
491
+ */
492
+ var checkMod9710BBAN = function (bban) {
493
+ var stripped = bban.replace(/[\s.]+/g, '');
494
+ var reminder = mod9710(stripped);
495
+ return reminder === 1;
496
+ };
497
+ /**
498
+ * Used for Poland BBAN check
499
+ *
500
+ * @ignore
501
+ */
502
+ var checkPolandBBAN = function (bban) {
503
+ var weights = [3, 9, 7, 1, 3, 9, 7];
504
+ var controlDigit = parseInt(bban.charAt(7), 10);
505
+ var toCheck = bban.substring(0, 7);
506
+ var sum = 0;
507
+ for (var index = 0; index < 7; index++) {
508
+ sum += parseInt(toCheck.charAt(index), 10) * weights[index];
509
+ }
510
+ var remainder = sum % 10;
511
+ return controlDigit === (remainder === 0 ? 0 : 10 - remainder);
512
+ };
513
+ /**
514
+ * Spain (ES) BBAN check
515
+ *
516
+ * @ignore
517
+ */
518
+ var checkSpainBBAN = function (bban) {
519
+ var weightsBankBranch = [4, 8, 5, 10, 9, 7, 3, 6];
520
+ var weightsAccount = [1, 2, 4, 8, 5, 10, 9, 7, 3, 6];
521
+ var controlBankBranch = parseInt(bban.charAt(8), 10);
522
+ var controlAccount = parseInt(bban.charAt(9), 10);
523
+ var bankBranch = bban.substring(0, 8);
524
+ var account = bban.substring(10, 20);
525
+ var sum = 0;
526
+ for (var index = 0; index < 8; index++) {
527
+ sum += parseInt(bankBranch.charAt(index), 10) * weightsBankBranch[index];
528
+ }
529
+ var remainder = sum % 11;
530
+ if (controlBankBranch !== (remainder === 0 ? 0 : remainder === 1 ? 1 : 11 - remainder)) {
531
+ return false;
532
+ }
533
+ sum = 0;
534
+ for (var index = 0; index < 10; index++) {
535
+ sum += parseInt(account.charAt(index), 10) * weightsAccount[index];
536
+ }
537
+ remainder = sum % 11;
538
+ return controlAccount === (remainder === 0 ? 0 : remainder === 1 ? 1 : 11 - remainder);
539
+ };
540
+ /**
541
+ * Mod 11/10 check
542
+ *
543
+ * @ignore
544
+ */
545
+ var checkMod1110 = function (toCheck, control) {
546
+ var nr = 10;
547
+ for (var index = 0; index < toCheck.length; index++) {
548
+ nr += parseInt(toCheck.charAt(index), 10);
549
+ if (nr % 10 !== 0) {
550
+ nr = nr % 10;
551
+ }
552
+ nr = nr * 2;
553
+ nr = nr % 11;
554
+ }
555
+ return control === (11 - nr === 10 ? 0 : 11 - nr);
556
+ };
557
+ /**
558
+ * Croatian (HR) BBAN check
559
+ *
560
+ * @ignore
561
+ */
562
+ var checkCroatianBBAN = function (bban) {
563
+ var controlBankBranch = parseInt(bban.charAt(6), 10);
564
+ var controlAccount = parseInt(bban.charAt(16), 10);
565
+ var bankBranch = bban.substring(0, 6);
566
+ var account = bban.substring(7, 16);
567
+ return checkMod1110(bankBranch, controlBankBranch) && checkMod1110(account, controlAccount);
568
+ };
569
+ /**
570
+ * Czech (CZ) BBAN check
571
+ *
572
+ * @ignore
573
+ */
574
+ var checkCzechBBAN = function (bban) {
575
+ var weightsPrefix = [10, 5, 8, 4, 2, 1];
576
+ var weightsSuffix = [6, 3, 7, 9, 10, 5, 8, 4, 2, 1];
577
+ var controlPrefix = parseInt(bban.charAt(9), 10);
578
+ var controlSuffix = parseInt(bban.charAt(19), 10);
579
+ var prefix = bban.substring(4, 9);
580
+ var suffix = bban.substring(10, 19);
581
+ var sum = 0;
582
+ for (var index = 0; index < prefix.length; index++) {
583
+ sum += parseInt(prefix.charAt(index), 10) * weightsPrefix[index];
584
+ }
585
+ var remainder = sum % 11;
586
+ if (controlPrefix !== (remainder === 0 ? 0 : remainder === 1 ? 1 : 11 - remainder)) {
587
+ return false;
588
+ }
589
+ sum = 0;
590
+ for (var index = 0; index < suffix.length; index++) {
591
+ sum += parseInt(suffix.charAt(index), 10) * weightsSuffix[index];
592
+ }
593
+ remainder = sum % 11;
594
+ return controlSuffix === (remainder === 0 ? 0 : remainder === 1 ? 1 : 11 - remainder);
595
+ };
596
+ /**
597
+ * Estonian (EE) BBAN check
598
+ *
599
+ * @ignore
600
+ */
601
+ var checkEstonianBBAN = function (bban) {
602
+ var weights = [7, 1, 3, 7, 1, 3, 7, 1, 3, 7, 1, 3, 7];
603
+ var controlDigit = parseInt(bban.charAt(15), 10);
604
+ var toCheck = bban.substring(2, 15);
605
+ var sum = 0;
606
+ for (var index = 0; index < toCheck.length; index++) {
607
+ sum += parseInt(toCheck.charAt(index), 10) * weights[index];
608
+ }
609
+ var remainder = sum % 10;
610
+ return controlDigit === (remainder === 0 ? 0 : 10 - remainder);
611
+ };
612
+ /**
613
+ * Finland (FI) BBAN check
614
+ *
615
+ * @ignore
616
+ */
617
+ var checkFinlandBBAN = function (bban) {
618
+ var weightsMethod1 = [2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2];
619
+ var weightsMethod2 = [0, 0, 0, 0, 0, 0, 0, 1, 3, 7, 1, 3, 7];
620
+ var controlDigit = parseInt(bban.charAt(13), 10);
621
+ var toCheck = bban.substring(0, 13);
622
+ var sum = 0;
623
+ if (toCheck.startsWith('88')) {
624
+ for (var index = 0; index < toCheck.length; index++) {
625
+ sum += parseInt(toCheck.charAt(index), 10) * weightsMethod2[index];
626
+ }
627
+ var remainder = sum % 10;
628
+ return controlDigit === (remainder === 0 ? 0 : 10 - remainder);
629
+ }
630
+ else {
631
+ for (var index = 0; index < toCheck.length; index++) {
632
+ if (weightsMethod1[index] === 1) {
633
+ sum += parseInt(toCheck.charAt(index), 10) * weightsMethod1[index];
634
+ }
635
+ else {
636
+ var value = parseInt(toCheck.charAt(index), 10) * weightsMethod1[index];
637
+ sum += Math.floor(value / 10) + (value % 10);
638
+ }
639
+ }
640
+ var extraSum = sum + controlDigit;
641
+ var multiDigit = Math.floor(extraSum / 10);
642
+ var result = multiDigit * 10;
643
+ var remainder = result - sum;
644
+ return remainder === controlDigit;
645
+ }
646
+ };
647
+ /**
648
+ * Check French (FR) BBAN
649
+ * Also for Monaco (MC)
650
+ *
651
+ * @ignore
652
+ */
653
+ var checkFrenchBBAN = function (bban) {
654
+ var stripped = bban.replace(/[\s.]+/g, '');
655
+ var normalized = Array.from(stripped);
656
+ for (var index = 0; index < stripped.length; index++) {
657
+ var c = normalized[index].charCodeAt(0);
658
+ if (c >= 65) {
659
+ switch (c) {
660
+ case 65:
661
+ case 74:
662
+ normalized[index] = '1';
663
+ break;
664
+ case 66:
665
+ case 75:
666
+ case 83:
667
+ normalized[index] = '2';
668
+ break;
669
+ case 67:
670
+ case 76:
671
+ case 84:
672
+ normalized[index] = '3';
673
+ break;
674
+ case 68:
675
+ case 77:
676
+ case 85:
677
+ normalized[index] = '4';
678
+ break;
679
+ case 69:
680
+ case 78:
681
+ case 86:
682
+ normalized[index] = '5';
683
+ break;
684
+ case 70:
685
+ case 79:
686
+ case 87:
687
+ normalized[index] = '6';
688
+ break;
689
+ case 71:
690
+ case 80:
691
+ case 88:
692
+ normalized[index] = '7';
693
+ break;
694
+ case 72:
695
+ case 81:
696
+ case 89:
697
+ normalized[index] = '8';
698
+ break;
699
+ case 73:
700
+ case 82:
701
+ case 90:
702
+ normalized[index] = '9';
703
+ break;
704
+ }
705
+ }
706
+ }
707
+ var remainder = mod9710(normalized.join(''));
708
+ return remainder === 0;
709
+ };
710
+ /**
711
+ * Hungarian (HU) BBAN check
712
+ *
713
+ * @ignore
714
+ */
715
+ var checkHungarianBBAN = function (bban) {
716
+ var weights = [9, 7, 3, 1, 9, 7, 3, 1, 9, 7, 3, 1, 9, 7, 3];
717
+ var controlDigitBankBranch = parseInt(bban.charAt(7), 10);
718
+ var toCheckBankBranch = bban.substring(0, 7);
719
+ var sum = 0;
720
+ for (var index = 0; index < toCheckBankBranch.length; index++) {
721
+ sum += parseInt(toCheckBankBranch.charAt(index), 10) * weights[index];
722
+ }
723
+ var remainder = sum % 10;
724
+ if (controlDigitBankBranch !== (remainder === 0 ? 0 : 10 - remainder)) {
725
+ return false;
726
+ }
727
+ sum = 0;
728
+ if (bban.endsWith('00000000')) {
729
+ var toCheckAccount = bban.substring(8, 15);
730
+ var controlDigitAccount = parseInt(bban.charAt(15), 10);
731
+ for (var index = 0; index < toCheckAccount.length; index++) {
732
+ sum += parseInt(toCheckAccount.charAt(index), 10) * weights[index];
733
+ }
734
+ var remainder_1 = sum % 10;
735
+ return controlDigitAccount === (remainder_1 === 0 ? 0 : 10 - remainder_1);
736
+ }
737
+ else {
738
+ var toCheckAccount = bban.substring(8, 23);
739
+ var controlDigitAccount = parseInt(bban.charAt(23), 10);
740
+ for (var index = 0; index < toCheckAccount.length; index++) {
741
+ sum += parseInt(toCheckAccount.charAt(index), 10) * weights[index];
742
+ }
743
+ var remainder_2 = sum % 10;
744
+ return controlDigitAccount === (remainder_2 === 0 ? 0 : 10 - remainder_2);
745
+ }
746
+ };
424
747
  /**
425
748
  * Country specifications
426
749
  */
@@ -458,6 +781,7 @@ exports.countrySpecs = {
458
781
  AX: {
459
782
  chars: 18,
460
783
  bban_regexp: '^[0-9]{14}$',
784
+ bban_validation_func: checkFinlandBBAN,
461
785
  IBANRegistry: true,
462
786
  },
463
787
  AZ: {
@@ -468,11 +792,12 @@ exports.countrySpecs = {
468
792
  BA: {
469
793
  chars: 20,
470
794
  bban_regexp: '^[0-9]{16}$',
795
+ bban_validation_func: checkMod9710BBAN,
471
796
  IBANRegistry: true,
472
797
  },
473
798
  BB: {},
474
799
  BD: {},
475
- BE: { chars: 16, bban_regexp: '^[0-9]{12}$', IBANRegistry: true, SEPA: true },
800
+ BE: { chars: 16, bban_regexp: '^[0-9]{12}$', bban_validation_func: checkBelgianBBAN, IBANRegistry: true, SEPA: true },
476
801
  BF: {
477
802
  chars: 28,
478
803
  bban_regexp: '^[A-Z0-9]{2}[0-9]{22}$',
@@ -489,8 +814,8 @@ exports.countrySpecs = {
489
814
  IBANRegistry: true,
490
815
  },
491
816
  BI: {
492
- chars: 16,
493
- bban_regexp: '^[0-9]{12}$',
817
+ chars: 27,
818
+ bban_regexp: '^[0-9]{23}$',
494
819
  },
495
820
  BJ: {
496
821
  chars: 28,
@@ -564,7 +889,13 @@ exports.countrySpecs = {
564
889
  IBANRegistry: true,
565
890
  SEPA: true,
566
891
  },
567
- CZ: { chars: 24, bban_regexp: '^[0-9]{20}$', IBANRegistry: true, SEPA: true },
892
+ CZ: {
893
+ chars: 24,
894
+ bban_regexp: '^[0-9]{20}$',
895
+ bban_validation_func: checkCzechBBAN,
896
+ IBANRegistry: true,
897
+ SEPA: true,
898
+ },
568
899
  DE: { chars: 22, bban_regexp: '^[0-9]{18}$', IBANRegistry: true, SEPA: true },
569
900
  DJ: {
570
901
  chars: 27,
@@ -582,13 +913,31 @@ exports.countrySpecs = {
582
913
  bban_regexp: '^[0-9]{22}$',
583
914
  },
584
915
  EC: {},
585
- EE: { chars: 20, bban_regexp: '^[0-9]{16}$', IBANRegistry: true, SEPA: true },
916
+ EE: {
917
+ chars: 20,
918
+ bban_regexp: '^[0-9]{16}$',
919
+ bban_validation_func: checkEstonianBBAN,
920
+ IBANRegistry: true,
921
+ SEPA: true,
922
+ },
586
923
  EG: { chars: 29, bban_regexp: '^[0-9]{25}', IBANRegistry: true },
587
924
  EH: {},
588
925
  ER: {},
589
- ES: { chars: 24, bban_regexp: '^[0-9]{20}$', IBANRegistry: true, SEPA: true },
926
+ ES: {
927
+ chars: 24,
928
+ bban_validation_func: checkSpainBBAN,
929
+ bban_regexp: '^[0-9]{20}$',
930
+ IBANRegistry: true,
931
+ SEPA: true,
932
+ },
590
933
  ET: {},
591
- FI: { chars: 18, bban_regexp: '^[0-9]{14}$', IBANRegistry: true, SEPA: true },
934
+ FI: {
935
+ chars: 18,
936
+ bban_regexp: '^[0-9]{14}$',
937
+ bban_validation_func: checkFinlandBBAN,
938
+ IBANRegistry: true,
939
+ SEPA: true,
940
+ },
592
941
  FJ: {},
593
942
  FK: {},
594
943
  FM: {},
@@ -596,6 +945,7 @@ exports.countrySpecs = {
596
945
  FR: {
597
946
  chars: 27,
598
947
  bban_regexp: '^[0-9]{10}[A-Z0-9]{11}[0-9]{2}$',
948
+ bban_validation_func: checkFrenchBBAN,
599
949
  IBANRegistry: true,
600
950
  SEPA: true,
601
951
  },
@@ -664,9 +1014,21 @@ exports.countrySpecs = {
664
1014
  chars: 28,
665
1015
  bban_regexp: '^[A-Z]{4}[0-9]{20}$',
666
1016
  },
667
- HR: { chars: 21, bban_regexp: '^[0-9]{17}$', IBANRegistry: true, SEPA: true },
1017
+ HR: {
1018
+ chars: 21,
1019
+ bban_regexp: '^[0-9]{17}$',
1020
+ bban_validation_func: checkCroatianBBAN,
1021
+ IBANRegistry: true,
1022
+ SEPA: true,
1023
+ },
668
1024
  HT: {},
669
- HU: { chars: 28, bban_regexp: '^[0-9]{24}$', IBANRegistry: true, SEPA: true },
1025
+ HU: {
1026
+ chars: 28,
1027
+ bban_regexp: '^[0-9]{24}$',
1028
+ bban_validation_func: checkHungarianBBAN,
1029
+ IBANRegistry: true,
1030
+ SEPA: true,
1031
+ },
670
1032
  ID: {},
671
1033
  IE: {
672
1034
  chars: 22,
@@ -773,6 +1135,7 @@ exports.countrySpecs = {
773
1135
  MC: {
774
1136
  chars: 27,
775
1137
  bban_regexp: '^[0-9]{10}[A-Z0-9]{11}[0-9]{2}$',
1138
+ bban_validation_func: checkFrenchBBAN,
776
1139
  IBANRegistry: true,
777
1140
  SEPA: true,
778
1141
  },
@@ -784,6 +1147,7 @@ exports.countrySpecs = {
784
1147
  ME: {
785
1148
  chars: 22,
786
1149
  bban_regexp: '^[0-9]{18}$',
1150
+ bban_validation_func: checkMod9710BBAN,
787
1151
  IBANRegistry: true,
788
1152
  },
789
1153
  MF: {
@@ -799,6 +1163,7 @@ exports.countrySpecs = {
799
1163
  MK: {
800
1164
  chars: 19,
801
1165
  bban_regexp: '^[0-9]{3}[A-Z0-9]{10}[0-9]{2}$',
1166
+ bban_validation_func: checkMod9710BBAN,
802
1167
  IBANRegistry: true,
803
1168
  },
804
1169
  ML: {
@@ -858,10 +1223,11 @@ exports.countrySpecs = {
858
1223
  NL: {
859
1224
  chars: 18,
860
1225
  bban_regexp: '^[A-Z]{4}[0-9]{10}$',
1226
+ bban_validation_func: checkDutchBBAN,
861
1227
  IBANRegistry: true,
862
1228
  SEPA: true,
863
1229
  },
864
- NO: { chars: 15, bban_regexp: '^[0-9]{11}$', IBANRegistry: true, SEPA: true },
1230
+ NO: { chars: 15, bban_regexp: '^[0-9]{11}$', bban_validation_func: checkNorwayBBAN, IBANRegistry: true, SEPA: true },
865
1231
  NP: {},
866
1232
  NR: {},
867
1233
  NU: {},
@@ -881,7 +1247,7 @@ exports.countrySpecs = {
881
1247
  bban_regexp: '^[A-Z0-9]{4}[0-9]{16}$',
882
1248
  IBANRegistry: true,
883
1249
  },
884
- PL: { chars: 28, bban_regexp: '^[0-9]{24}$', IBANRegistry: true, SEPA: true },
1250
+ PL: { chars: 28, bban_validation_func: checkPolandBBAN, bban_regexp: '^[0-9]{24}$', IBANRegistry: true, SEPA: true },
885
1251
  PM: {
886
1252
  chars: 27,
887
1253
  bban_regexp: '^[0-9]{10}[A-Z0-9]{11}[0-9]{2}$',
@@ -894,7 +1260,7 @@ exports.countrySpecs = {
894
1260
  bban_regexp: '^[A-Z0-9]{4}[0-9]{21}$',
895
1261
  IBANRegistry: true,
896
1262
  },
897
- PT: { chars: 25, bban_regexp: '^[0-9]{21}$', IBANRegistry: true, SEPA: true },
1263
+ PT: { chars: 25, bban_regexp: '^[0-9]{21}$', bban_validation_func: checkMod9710BBAN, IBANRegistry: true, SEPA: true },
898
1264
  PW: {},
899
1265
  PY: {},
900
1266
  QA: {
@@ -916,6 +1282,7 @@ exports.countrySpecs = {
916
1282
  RS: {
917
1283
  chars: 22,
918
1284
  bban_regexp: '^[0-9]{18}$',
1285
+ bban_validation_func: checkMod9710BBAN,
919
1286
  IBANRegistry: true,
920
1287
  },
921
1288
  RU: {},
@@ -935,7 +1302,13 @@ exports.countrySpecs = {
935
1302
  SE: { chars: 24, bban_regexp: '^[0-9]{20}$', IBANRegistry: true, SEPA: true },
936
1303
  SG: {},
937
1304
  SH: {},
938
- SI: { chars: 19, bban_regexp: '^[0-9]{15}$', IBANRegistry: true, SEPA: true },
1305
+ SI: {
1306
+ chars: 19,
1307
+ bban_regexp: '^[0-9]{15}$',
1308
+ bban_validation_func: checkMod9710BBAN,
1309
+ IBANRegistry: true,
1310
+ SEPA: true,
1311
+ },
939
1312
  SJ: {},
940
1313
  SK: { chars: 24, bban_regexp: '^[0-9]{20}$', IBANRegistry: true, SEPA: true },
941
1314
  SL: {},
@@ -947,7 +1320,7 @@ exports.countrySpecs = {
947
1320
  },
948
1321
  SN: {
949
1322
  chars: 28,
950
- bban_regexp: '^[A-Z]{1}[0-9]{23}$',
1323
+ bban_regexp: '^[A-Z]{2}[0-9]{22}$',
951
1324
  },
952
1325
  SO: {},
953
1326
  SR: {},
@@ -5,10 +5,10 @@
5
5
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
6
  /**
7
7
  * Validation, extraction and creation of IBAN, BBAN, BIC/SWIFT numbers plus some other helpful stuff
8
- * @packageDocumentation
8
+ * @package Documentation
9
9
  * @author Saša Jovanić
10
10
  * @module ibantools
11
- * @version 3.3.1
11
+ * @version 4.1.1
12
12
  * @license MPL-2.0
13
13
  * @preferred
14
14
  */
@@ -23,7 +23,7 @@
23
23
  * // returns false
24
24
  * ibantools.isValidIBAN("NL92ABNA0517164300");
25
25
  * ```
26
- v */
26
+ */
27
27
  export function isValidIBAN(iban) {
28
28
  if (iban !== undefined && iban !== null) {
29
29
  var reg = new RegExp('^[0-9]{2}$', '');
@@ -34,7 +34,7 @@ export function isValidIBAN(iban) {
34
34
  spec.chars &&
35
35
  spec.chars === iban.length &&
36
36
  reg.test(iban.slice(2, 4)) &&
37
- checkFormatBBAN(iban.slice(4), spec.bban_regexp) &&
37
+ isValidBBAN(iban.slice(4), iban.slice(0, 2)) &&
38
38
  isValidIBANChecksum(iban)) {
39
39
  return true;
40
40
  }
@@ -52,6 +52,7 @@ export var ValidationErrorsIBAN;
52
52
  ValidationErrorsIBAN[ValidationErrorsIBAN["WrongBBANFormat"] = 3] = "WrongBBANFormat";
53
53
  ValidationErrorsIBAN[ValidationErrorsIBAN["ChecksumNotNumber"] = 4] = "ChecksumNotNumber";
54
54
  ValidationErrorsIBAN[ValidationErrorsIBAN["WrongIBANChecksum"] = 5] = "WrongIBANChecksum";
55
+ ValidationErrorsIBAN[ValidationErrorsIBAN["WrongAccountBankBranchChecksum"] = 6] = "WrongAccountBankBranchChecksum";
55
56
  })(ValidationErrorsIBAN || (ValidationErrorsIBAN = {}));
56
57
  /**
57
58
  * validateIBAN
@@ -76,6 +77,10 @@ export function validateIBAN(iban) {
76
77
  result.valid = false;
77
78
  result.errorCodes.push(ValidationErrorsIBAN.WrongBBANFormat);
78
79
  }
80
+ if (spec && spec.bban_validation_func && !spec.bban_validation_func(iban.slice(4))) {
81
+ result.valid = false;
82
+ result.errorCodes.push(ValidationErrorsIBAN.WrongAccountBankBranchChecksum);
83
+ }
79
84
  var reg = new RegExp('^[0-9]{2}$', '');
80
85
  if (!reg.test(iban.slice(2, 4))) {
81
86
  result.valid = false;
@@ -115,6 +120,9 @@ export function isValidBBAN(bban, countryCode) {
115
120
  spec.chars !== null &&
116
121
  spec.chars - 4 === bban.length &&
117
122
  checkFormatBBAN(bban, spec.bban_regexp)) {
123
+ if (spec.bban_validation_func) {
124
+ return spec.bban_validation_func(bban.replace(/[\s.]+/g, ''));
125
+ }
118
126
  return true;
119
127
  }
120
128
  }
@@ -162,7 +170,7 @@ export function composeIBAN(params) {
162
170
  spec.bban_regexp &&
163
171
  spec.bban_regexp !== null &&
164
172
  checkFormatBBAN(formated_bban, spec.bban_regexp)) {
165
- var checksom = mod9710(params.countryCode + '00' + formated_bban);
173
+ var checksom = mod9710Iban(params.countryCode + '00' + formated_bban);
166
174
  return params.countryCode + ('0' + (98 - checksom)).slice(-2) + formated_bban;
167
175
  }
168
176
  return null;
@@ -268,7 +276,7 @@ function isValidIBANChecksum(iban) {
268
276
  *
269
277
  * @ignore
270
278
  */
271
- function mod9710(iban) {
279
+ function mod9710Iban(iban) {
272
280
  iban = iban.slice(3) + iban.slice(0, 4);
273
281
  var validationString = '';
274
282
  for (var n = 1; n < iban.length; n++) {
@@ -280,11 +288,7 @@ function mod9710(iban) {
280
288
  validationString += iban[n];
281
289
  }
282
290
  }
283
- while (validationString.length > 2) {
284
- var part = validationString.slice(0, 6);
285
- validationString = (parseInt(part, 10) % 97).toString() + validationString.slice(part.length);
286
- }
287
- return parseInt(validationString, 10) % 97;
291
+ return mod9710(validationString);
288
292
  }
289
293
  /**
290
294
  * Returns specifications for all countries, even those who are not
@@ -407,6 +411,325 @@ export function extractBIC(inputBic) {
407
411
  }
408
412
  return result;
409
413
  }
414
+ /**
415
+ * Used for Norway BBAN check
416
+ *
417
+ * @ignore
418
+ */
419
+ var checkNorwayBBAN = function (bban) {
420
+ var weights = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2];
421
+ var bbanWithoutSpacesAndPeriods = bban.replace(/[\s.]+/g, '');
422
+ var controlDigit = parseInt(bbanWithoutSpacesAndPeriods.charAt(10), 10);
423
+ var bbanWithoutControlDigit = bbanWithoutSpacesAndPeriods.substring(0, 10);
424
+ var sum = 0;
425
+ for (var index = 0; index < 10; index++) {
426
+ sum += parseInt(bbanWithoutControlDigit.charAt(index), 10) * weights[index];
427
+ }
428
+ var remainder = sum % 11;
429
+ return controlDigit === (remainder === 0 ? 0 : 11 - remainder);
430
+ };
431
+ /**
432
+ * Used for Netherlands BBAN check
433
+ *
434
+ * @ignore
435
+ */
436
+ var checkDutchBBAN = function (bban) {
437
+ var bbanWithoutSpacesAndPeriods = bban.replace(/[\s.]+/g, '');
438
+ var accountNumber = bbanWithoutSpacesAndPeriods.substring(4, 14);
439
+ if (accountNumber.startsWith('000')) {
440
+ return true; // Postbank account, no `elfproef` possible
441
+ }
442
+ var sum = 0;
443
+ for (var index = 0; index < 10; index++) {
444
+ sum += parseInt(accountNumber.charAt(index), 10) * (10 - index);
445
+ }
446
+ return sum % 11 === 0;
447
+ };
448
+ /**
449
+ * Used for Belgian BBAN check
450
+ *
451
+ * @ignore
452
+ */
453
+ var checkBelgianBBAN = function (bban) {
454
+ var stripped = bban.replace(/[\s.]+/g, '');
455
+ var checkingPart = parseInt(stripped.substring(0, stripped.length - 2), 10);
456
+ var checksum = parseInt(stripped.substring(stripped.length - 2, stripped.length), 10);
457
+ var remainder = checkingPart % 97 === 0 ? 97 : checkingPart % 97;
458
+ return remainder === checksum;
459
+ };
460
+ /**
461
+ * Mod 97/10 calculation
462
+ *
463
+ * @ignore
464
+ */
465
+ var mod9710 = function (validationString) {
466
+ while (validationString.length > 2) {
467
+ var part = validationString.slice(0, 6);
468
+ validationString = (parseInt(part, 10) % 97).toString() + validationString.slice(part.length);
469
+ }
470
+ return parseInt(validationString, 10) % 97;
471
+ };
472
+ /**
473
+ * Check BBAN based on Mod97/10 calculation for countries that support it:
474
+ * BA, ME, MK, PT, RS, SI
475
+ *
476
+ * @ignore
477
+ */
478
+ var checkMod9710BBAN = function (bban) {
479
+ var stripped = bban.replace(/[\s.]+/g, '');
480
+ var reminder = mod9710(stripped);
481
+ return reminder === 1;
482
+ };
483
+ /**
484
+ * Used for Poland BBAN check
485
+ *
486
+ * @ignore
487
+ */
488
+ var checkPolandBBAN = function (bban) {
489
+ var weights = [3, 9, 7, 1, 3, 9, 7];
490
+ var controlDigit = parseInt(bban.charAt(7), 10);
491
+ var toCheck = bban.substring(0, 7);
492
+ var sum = 0;
493
+ for (var index = 0; index < 7; index++) {
494
+ sum += parseInt(toCheck.charAt(index), 10) * weights[index];
495
+ }
496
+ var remainder = sum % 10;
497
+ return controlDigit === (remainder === 0 ? 0 : 10 - remainder);
498
+ };
499
+ /**
500
+ * Spain (ES) BBAN check
501
+ *
502
+ * @ignore
503
+ */
504
+ var checkSpainBBAN = function (bban) {
505
+ var weightsBankBranch = [4, 8, 5, 10, 9, 7, 3, 6];
506
+ var weightsAccount = [1, 2, 4, 8, 5, 10, 9, 7, 3, 6];
507
+ var controlBankBranch = parseInt(bban.charAt(8), 10);
508
+ var controlAccount = parseInt(bban.charAt(9), 10);
509
+ var bankBranch = bban.substring(0, 8);
510
+ var account = bban.substring(10, 20);
511
+ var sum = 0;
512
+ for (var index = 0; index < 8; index++) {
513
+ sum += parseInt(bankBranch.charAt(index), 10) * weightsBankBranch[index];
514
+ }
515
+ var remainder = sum % 11;
516
+ if (controlBankBranch !== (remainder === 0 ? 0 : remainder === 1 ? 1 : 11 - remainder)) {
517
+ return false;
518
+ }
519
+ sum = 0;
520
+ for (var index = 0; index < 10; index++) {
521
+ sum += parseInt(account.charAt(index), 10) * weightsAccount[index];
522
+ }
523
+ remainder = sum % 11;
524
+ return controlAccount === (remainder === 0 ? 0 : remainder === 1 ? 1 : 11 - remainder);
525
+ };
526
+ /**
527
+ * Mod 11/10 check
528
+ *
529
+ * @ignore
530
+ */
531
+ var checkMod1110 = function (toCheck, control) {
532
+ var nr = 10;
533
+ for (var index = 0; index < toCheck.length; index++) {
534
+ nr += parseInt(toCheck.charAt(index), 10);
535
+ if (nr % 10 !== 0) {
536
+ nr = nr % 10;
537
+ }
538
+ nr = nr * 2;
539
+ nr = nr % 11;
540
+ }
541
+ return control === (11 - nr === 10 ? 0 : 11 - nr);
542
+ };
543
+ /**
544
+ * Croatian (HR) BBAN check
545
+ *
546
+ * @ignore
547
+ */
548
+ var checkCroatianBBAN = function (bban) {
549
+ var controlBankBranch = parseInt(bban.charAt(6), 10);
550
+ var controlAccount = parseInt(bban.charAt(16), 10);
551
+ var bankBranch = bban.substring(0, 6);
552
+ var account = bban.substring(7, 16);
553
+ return checkMod1110(bankBranch, controlBankBranch) && checkMod1110(account, controlAccount);
554
+ };
555
+ /**
556
+ * Czech (CZ) BBAN check
557
+ *
558
+ * @ignore
559
+ */
560
+ var checkCzechBBAN = function (bban) {
561
+ var weightsPrefix = [10, 5, 8, 4, 2, 1];
562
+ var weightsSuffix = [6, 3, 7, 9, 10, 5, 8, 4, 2, 1];
563
+ var controlPrefix = parseInt(bban.charAt(9), 10);
564
+ var controlSuffix = parseInt(bban.charAt(19), 10);
565
+ var prefix = bban.substring(4, 9);
566
+ var suffix = bban.substring(10, 19);
567
+ var sum = 0;
568
+ for (var index = 0; index < prefix.length; index++) {
569
+ sum += parseInt(prefix.charAt(index), 10) * weightsPrefix[index];
570
+ }
571
+ var remainder = sum % 11;
572
+ if (controlPrefix !== (remainder === 0 ? 0 : remainder === 1 ? 1 : 11 - remainder)) {
573
+ return false;
574
+ }
575
+ sum = 0;
576
+ for (var index = 0; index < suffix.length; index++) {
577
+ sum += parseInt(suffix.charAt(index), 10) * weightsSuffix[index];
578
+ }
579
+ remainder = sum % 11;
580
+ return controlSuffix === (remainder === 0 ? 0 : remainder === 1 ? 1 : 11 - remainder);
581
+ };
582
+ /**
583
+ * Estonian (EE) BBAN check
584
+ *
585
+ * @ignore
586
+ */
587
+ var checkEstonianBBAN = function (bban) {
588
+ var weights = [7, 1, 3, 7, 1, 3, 7, 1, 3, 7, 1, 3, 7];
589
+ var controlDigit = parseInt(bban.charAt(15), 10);
590
+ var toCheck = bban.substring(2, 15);
591
+ var sum = 0;
592
+ for (var index = 0; index < toCheck.length; index++) {
593
+ sum += parseInt(toCheck.charAt(index), 10) * weights[index];
594
+ }
595
+ var remainder = sum % 10;
596
+ return controlDigit === (remainder === 0 ? 0 : 10 - remainder);
597
+ };
598
+ /**
599
+ * Finland (FI) BBAN check
600
+ *
601
+ * @ignore
602
+ */
603
+ var checkFinlandBBAN = function (bban) {
604
+ var weightsMethod1 = [2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2];
605
+ var weightsMethod2 = [0, 0, 0, 0, 0, 0, 0, 1, 3, 7, 1, 3, 7];
606
+ var controlDigit = parseInt(bban.charAt(13), 10);
607
+ var toCheck = bban.substring(0, 13);
608
+ var sum = 0;
609
+ if (toCheck.startsWith('88')) {
610
+ for (var index = 0; index < toCheck.length; index++) {
611
+ sum += parseInt(toCheck.charAt(index), 10) * weightsMethod2[index];
612
+ }
613
+ var remainder = sum % 10;
614
+ return controlDigit === (remainder === 0 ? 0 : 10 - remainder);
615
+ }
616
+ else {
617
+ for (var index = 0; index < toCheck.length; index++) {
618
+ if (weightsMethod1[index] === 1) {
619
+ sum += parseInt(toCheck.charAt(index), 10) * weightsMethod1[index];
620
+ }
621
+ else {
622
+ var value = parseInt(toCheck.charAt(index), 10) * weightsMethod1[index];
623
+ sum += Math.floor(value / 10) + (value % 10);
624
+ }
625
+ }
626
+ var extraSum = sum + controlDigit;
627
+ var multiDigit = Math.floor(extraSum / 10);
628
+ var result = multiDigit * 10;
629
+ var remainder = result - sum;
630
+ return remainder === controlDigit;
631
+ }
632
+ };
633
+ /**
634
+ * Check French (FR) BBAN
635
+ * Also for Monaco (MC)
636
+ *
637
+ * @ignore
638
+ */
639
+ var checkFrenchBBAN = function (bban) {
640
+ var stripped = bban.replace(/[\s.]+/g, '');
641
+ var normalized = Array.from(stripped);
642
+ for (var index = 0; index < stripped.length; index++) {
643
+ var c = normalized[index].charCodeAt(0);
644
+ if (c >= 65) {
645
+ switch (c) {
646
+ case 65:
647
+ case 74:
648
+ normalized[index] = '1';
649
+ break;
650
+ case 66:
651
+ case 75:
652
+ case 83:
653
+ normalized[index] = '2';
654
+ break;
655
+ case 67:
656
+ case 76:
657
+ case 84:
658
+ normalized[index] = '3';
659
+ break;
660
+ case 68:
661
+ case 77:
662
+ case 85:
663
+ normalized[index] = '4';
664
+ break;
665
+ case 69:
666
+ case 78:
667
+ case 86:
668
+ normalized[index] = '5';
669
+ break;
670
+ case 70:
671
+ case 79:
672
+ case 87:
673
+ normalized[index] = '6';
674
+ break;
675
+ case 71:
676
+ case 80:
677
+ case 88:
678
+ normalized[index] = '7';
679
+ break;
680
+ case 72:
681
+ case 81:
682
+ case 89:
683
+ normalized[index] = '8';
684
+ break;
685
+ case 73:
686
+ case 82:
687
+ case 90:
688
+ normalized[index] = '9';
689
+ break;
690
+ }
691
+ }
692
+ }
693
+ var remainder = mod9710(normalized.join(''));
694
+ return remainder === 0;
695
+ };
696
+ /**
697
+ * Hungarian (HU) BBAN check
698
+ *
699
+ * @ignore
700
+ */
701
+ var checkHungarianBBAN = function (bban) {
702
+ var weights = [9, 7, 3, 1, 9, 7, 3, 1, 9, 7, 3, 1, 9, 7, 3];
703
+ var controlDigitBankBranch = parseInt(bban.charAt(7), 10);
704
+ var toCheckBankBranch = bban.substring(0, 7);
705
+ var sum = 0;
706
+ for (var index = 0; index < toCheckBankBranch.length; index++) {
707
+ sum += parseInt(toCheckBankBranch.charAt(index), 10) * weights[index];
708
+ }
709
+ var remainder = sum % 10;
710
+ if (controlDigitBankBranch !== (remainder === 0 ? 0 : 10 - remainder)) {
711
+ return false;
712
+ }
713
+ sum = 0;
714
+ if (bban.endsWith('00000000')) {
715
+ var toCheckAccount = bban.substring(8, 15);
716
+ var controlDigitAccount = parseInt(bban.charAt(15), 10);
717
+ for (var index = 0; index < toCheckAccount.length; index++) {
718
+ sum += parseInt(toCheckAccount.charAt(index), 10) * weights[index];
719
+ }
720
+ var remainder_1 = sum % 10;
721
+ return controlDigitAccount === (remainder_1 === 0 ? 0 : 10 - remainder_1);
722
+ }
723
+ else {
724
+ var toCheckAccount = bban.substring(8, 23);
725
+ var controlDigitAccount = parseInt(bban.charAt(23), 10);
726
+ for (var index = 0; index < toCheckAccount.length; index++) {
727
+ sum += parseInt(toCheckAccount.charAt(index), 10) * weights[index];
728
+ }
729
+ var remainder_2 = sum % 10;
730
+ return controlDigitAccount === (remainder_2 === 0 ? 0 : 10 - remainder_2);
731
+ }
732
+ };
410
733
  /**
411
734
  * Country specifications
412
735
  */
@@ -444,6 +767,7 @@ export var countrySpecs = {
444
767
  AX: {
445
768
  chars: 18,
446
769
  bban_regexp: '^[0-9]{14}$',
770
+ bban_validation_func: checkFinlandBBAN,
447
771
  IBANRegistry: true,
448
772
  },
449
773
  AZ: {
@@ -454,11 +778,12 @@ export var countrySpecs = {
454
778
  BA: {
455
779
  chars: 20,
456
780
  bban_regexp: '^[0-9]{16}$',
781
+ bban_validation_func: checkMod9710BBAN,
457
782
  IBANRegistry: true,
458
783
  },
459
784
  BB: {},
460
785
  BD: {},
461
- BE: { chars: 16, bban_regexp: '^[0-9]{12}$', IBANRegistry: true, SEPA: true },
786
+ BE: { chars: 16, bban_regexp: '^[0-9]{12}$', bban_validation_func: checkBelgianBBAN, IBANRegistry: true, SEPA: true },
462
787
  BF: {
463
788
  chars: 28,
464
789
  bban_regexp: '^[A-Z0-9]{2}[0-9]{22}$',
@@ -475,8 +800,8 @@ export var countrySpecs = {
475
800
  IBANRegistry: true,
476
801
  },
477
802
  BI: {
478
- chars: 16,
479
- bban_regexp: '^[0-9]{12}$',
803
+ chars: 27,
804
+ bban_regexp: '^[0-9]{23}$',
480
805
  },
481
806
  BJ: {
482
807
  chars: 28,
@@ -550,7 +875,13 @@ export var countrySpecs = {
550
875
  IBANRegistry: true,
551
876
  SEPA: true,
552
877
  },
553
- CZ: { chars: 24, bban_regexp: '^[0-9]{20}$', IBANRegistry: true, SEPA: true },
878
+ CZ: {
879
+ chars: 24,
880
+ bban_regexp: '^[0-9]{20}$',
881
+ bban_validation_func: checkCzechBBAN,
882
+ IBANRegistry: true,
883
+ SEPA: true,
884
+ },
554
885
  DE: { chars: 22, bban_regexp: '^[0-9]{18}$', IBANRegistry: true, SEPA: true },
555
886
  DJ: {
556
887
  chars: 27,
@@ -568,13 +899,31 @@ export var countrySpecs = {
568
899
  bban_regexp: '^[0-9]{22}$',
569
900
  },
570
901
  EC: {},
571
- EE: { chars: 20, bban_regexp: '^[0-9]{16}$', IBANRegistry: true, SEPA: true },
902
+ EE: {
903
+ chars: 20,
904
+ bban_regexp: '^[0-9]{16}$',
905
+ bban_validation_func: checkEstonianBBAN,
906
+ IBANRegistry: true,
907
+ SEPA: true,
908
+ },
572
909
  EG: { chars: 29, bban_regexp: '^[0-9]{25}', IBANRegistry: true },
573
910
  EH: {},
574
911
  ER: {},
575
- ES: { chars: 24, bban_regexp: '^[0-9]{20}$', IBANRegistry: true, SEPA: true },
912
+ ES: {
913
+ chars: 24,
914
+ bban_validation_func: checkSpainBBAN,
915
+ bban_regexp: '^[0-9]{20}$',
916
+ IBANRegistry: true,
917
+ SEPA: true,
918
+ },
576
919
  ET: {},
577
- FI: { chars: 18, bban_regexp: '^[0-9]{14}$', IBANRegistry: true, SEPA: true },
920
+ FI: {
921
+ chars: 18,
922
+ bban_regexp: '^[0-9]{14}$',
923
+ bban_validation_func: checkFinlandBBAN,
924
+ IBANRegistry: true,
925
+ SEPA: true,
926
+ },
578
927
  FJ: {},
579
928
  FK: {},
580
929
  FM: {},
@@ -582,6 +931,7 @@ export var countrySpecs = {
582
931
  FR: {
583
932
  chars: 27,
584
933
  bban_regexp: '^[0-9]{10}[A-Z0-9]{11}[0-9]{2}$',
934
+ bban_validation_func: checkFrenchBBAN,
585
935
  IBANRegistry: true,
586
936
  SEPA: true,
587
937
  },
@@ -650,9 +1000,21 @@ export var countrySpecs = {
650
1000
  chars: 28,
651
1001
  bban_regexp: '^[A-Z]{4}[0-9]{20}$',
652
1002
  },
653
- HR: { chars: 21, bban_regexp: '^[0-9]{17}$', IBANRegistry: true, SEPA: true },
1003
+ HR: {
1004
+ chars: 21,
1005
+ bban_regexp: '^[0-9]{17}$',
1006
+ bban_validation_func: checkCroatianBBAN,
1007
+ IBANRegistry: true,
1008
+ SEPA: true,
1009
+ },
654
1010
  HT: {},
655
- HU: { chars: 28, bban_regexp: '^[0-9]{24}$', IBANRegistry: true, SEPA: true },
1011
+ HU: {
1012
+ chars: 28,
1013
+ bban_regexp: '^[0-9]{24}$',
1014
+ bban_validation_func: checkHungarianBBAN,
1015
+ IBANRegistry: true,
1016
+ SEPA: true,
1017
+ },
656
1018
  ID: {},
657
1019
  IE: {
658
1020
  chars: 22,
@@ -759,6 +1121,7 @@ export var countrySpecs = {
759
1121
  MC: {
760
1122
  chars: 27,
761
1123
  bban_regexp: '^[0-9]{10}[A-Z0-9]{11}[0-9]{2}$',
1124
+ bban_validation_func: checkFrenchBBAN,
762
1125
  IBANRegistry: true,
763
1126
  SEPA: true,
764
1127
  },
@@ -770,6 +1133,7 @@ export var countrySpecs = {
770
1133
  ME: {
771
1134
  chars: 22,
772
1135
  bban_regexp: '^[0-9]{18}$',
1136
+ bban_validation_func: checkMod9710BBAN,
773
1137
  IBANRegistry: true,
774
1138
  },
775
1139
  MF: {
@@ -785,6 +1149,7 @@ export var countrySpecs = {
785
1149
  MK: {
786
1150
  chars: 19,
787
1151
  bban_regexp: '^[0-9]{3}[A-Z0-9]{10}[0-9]{2}$',
1152
+ bban_validation_func: checkMod9710BBAN,
788
1153
  IBANRegistry: true,
789
1154
  },
790
1155
  ML: {
@@ -844,10 +1209,11 @@ export var countrySpecs = {
844
1209
  NL: {
845
1210
  chars: 18,
846
1211
  bban_regexp: '^[A-Z]{4}[0-9]{10}$',
1212
+ bban_validation_func: checkDutchBBAN,
847
1213
  IBANRegistry: true,
848
1214
  SEPA: true,
849
1215
  },
850
- NO: { chars: 15, bban_regexp: '^[0-9]{11}$', IBANRegistry: true, SEPA: true },
1216
+ NO: { chars: 15, bban_regexp: '^[0-9]{11}$', bban_validation_func: checkNorwayBBAN, IBANRegistry: true, SEPA: true },
851
1217
  NP: {},
852
1218
  NR: {},
853
1219
  NU: {},
@@ -867,7 +1233,7 @@ export var countrySpecs = {
867
1233
  bban_regexp: '^[A-Z0-9]{4}[0-9]{16}$',
868
1234
  IBANRegistry: true,
869
1235
  },
870
- PL: { chars: 28, bban_regexp: '^[0-9]{24}$', IBANRegistry: true, SEPA: true },
1236
+ PL: { chars: 28, bban_validation_func: checkPolandBBAN, bban_regexp: '^[0-9]{24}$', IBANRegistry: true, SEPA: true },
871
1237
  PM: {
872
1238
  chars: 27,
873
1239
  bban_regexp: '^[0-9]{10}[A-Z0-9]{11}[0-9]{2}$',
@@ -880,7 +1246,7 @@ export var countrySpecs = {
880
1246
  bban_regexp: '^[A-Z0-9]{4}[0-9]{21}$',
881
1247
  IBANRegistry: true,
882
1248
  },
883
- PT: { chars: 25, bban_regexp: '^[0-9]{21}$', IBANRegistry: true, SEPA: true },
1249
+ PT: { chars: 25, bban_regexp: '^[0-9]{21}$', bban_validation_func: checkMod9710BBAN, IBANRegistry: true, SEPA: true },
884
1250
  PW: {},
885
1251
  PY: {},
886
1252
  QA: {
@@ -902,6 +1268,7 @@ export var countrySpecs = {
902
1268
  RS: {
903
1269
  chars: 22,
904
1270
  bban_regexp: '^[0-9]{18}$',
1271
+ bban_validation_func: checkMod9710BBAN,
905
1272
  IBANRegistry: true,
906
1273
  },
907
1274
  RU: {},
@@ -921,7 +1288,13 @@ export var countrySpecs = {
921
1288
  SE: { chars: 24, bban_regexp: '^[0-9]{20}$', IBANRegistry: true, SEPA: true },
922
1289
  SG: {},
923
1290
  SH: {},
924
- SI: { chars: 19, bban_regexp: '^[0-9]{15}$', IBANRegistry: true, SEPA: true },
1291
+ SI: {
1292
+ chars: 19,
1293
+ bban_regexp: '^[0-9]{15}$',
1294
+ bban_validation_func: checkMod9710BBAN,
1295
+ IBANRegistry: true,
1296
+ SEPA: true,
1297
+ },
925
1298
  SJ: {},
926
1299
  SK: { chars: 24, bban_regexp: '^[0-9]{20}$', IBANRegistry: true, SEPA: true },
927
1300
  SL: {},
@@ -933,7 +1306,7 @@ export var countrySpecs = {
933
1306
  },
934
1307
  SN: {
935
1308
  chars: 28,
936
- bban_regexp: '^[A-Z]{1}[0-9]{23}$',
1309
+ bban_regexp: '^[A-Z]{2}[0-9]{22}$',
937
1310
  },
938
1311
  SO: {},
939
1312
  SR: {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ibantools",
3
- "version": "3.3.1",
3
+ "version": "4.1.1",
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",
@@ -58,7 +58,7 @@
58
58
  "docdash": "^1.2.0",
59
59
  "eslint": "^7.31.0",
60
60
  "eslint-config-prettier": "^8.3.0",
61
- "eslint-plugin-prettier": "^3.4.0",
61
+ "eslint-plugin-prettier": "^4.0.0",
62
62
  "gulp": "^4.0.2",
63
63
  "gulp-mocha": "^8.0",
64
64
  "gulp-rename": "^2.0",
@@ -75,7 +75,7 @@
75
75
  "nyc": "^15.1.0",
76
76
  "prettier": "^2.3.2",
77
77
  "requirejs": "^2.3.6",
78
- "typedoc": "^0.21.4",
78
+ "typedoc": "^0.22.9",
79
79
  "typescript": "^4.3.5"
80
80
  }
81
81
  }