Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

ibankit

Package Overview
Dependencies
Maintainers
1
Versions
34
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ibankit - npm Package Compare versions

Comparing version 0.1.2 to 1.0.0

src/ibanBuilder.ts

4

package.json
{
"name": "ibankit",
"version": "0.1.2",
"description": "IBAN utilities",
"version": "1.0.0",
"description": "IBAN and BIC utilities",
"main": "lib/index.js",

@@ -6,0 +6,0 @@ "types": "lib/index.d.ts",

@@ -9,4 +9,13 @@ # ibankit

This library provides full TypesScript support
#### Key Features
- Drop in replacable with iban-js
- Currently conformant with Version 80 of the IBAN registry
- Decodes bank, branch and account numbers from IBAN
- Supports random BBAN / IBAN generation for testing
- Has BIC validation as a bonus
- Supports validation of National Check Digits if part of BBAN format
- This library provides full TypesScript support
- No external dependancies
#### Iban quick examples:

@@ -53,2 +62,7 @@

### TODO
[ ] For random IBANs the National Check digits is random, rather than "valid"
[ ] Finish writing all national check digit validators (see Oracle spec)
#### References

@@ -58,3 +72,5 @@

- http://en.wikipedia.org/wiki/ISO_9362
- https://www.ecb.europa.eu/paym/retpaym/paymint/sepa/shared/pdf/iban_registry.pdf
- https://www.swift.com/resource/iban-registry-pdf
- https://docs.oracle.com/cd/E18727_01/doc.121/e13483/T359831T498954.htm
- https://en.bitcoinwiki.org/wiki/International_Bank_Account_Number

@@ -61,0 +77,0 @@ #### Credits

@@ -1,5 +0,45 @@

import { CharacterType, BbanStructurePart } from "./structurePart";
import { CharacterType, BbanStructurePart, PartType } from "./structurePart";
import { CountryCode } from "./country";
import { FormatException, FormatViolation } from "./exceptions";
/**
* MOD11 check digit computation
*/
function mod11(value: string, weights: number[]) {
return (
11 -
(value
.split("")
.reverse()
.reduce((acc, s, idx) => acc + parseInt(s, 10) * weights[idx], 0) %
11)
);
}
/*
** Return a function that is a MOD11 national check digit checker
*/
function nationalFactory(weights: number[]) {
return (checkdigit: string, bban: string, structure: BbanStructure) => {
const accountNumber = structure.extractValue(bban, PartType.ACCOUNT_NUMBER);
if (accountNumber === null) {
throw new FormatException(FormatViolation.NOT_EMPTY, "account number");
}
const actual = structure.extractValue(bban, PartType.NATIONAL_CHECK_DIGIT);
const digit = mod11(accountNumber, weights);
if (actual !== String(digit)) {
throw new FormatException(
FormatViolation.NATIONAL_CHECK_DIGIT,
`national check digit(s) don't match expect=[${digit}] actual=[${actual}]`,
String(digit),
String(actual),
);
}
};
}
/**
* Class which represents bban structure

@@ -30,2 +70,3 @@ *

// Provisional
[CountryCode.AO]: new BbanStructure(

@@ -58,2 +99,3 @@ BbanStructurePart.accountNumber(21, CharacterType.n),

// Provisional
[CountryCode.BF]: new BbanStructure(

@@ -75,2 +117,3 @@ BbanStructurePart.accountNumber(23, CharacterType.n),

// Provisional
[CountryCode.BI]: new BbanStructure(

@@ -80,2 +123,3 @@ BbanStructurePart.accountNumber(12, CharacterType.n),

// Provisional
[CountryCode.BJ]: new BbanStructure(

@@ -102,2 +146,13 @@ BbanStructurePart.bankCode(5, CharacterType.c),

// Provisional
[CountryCode.CG]: new BbanStructure(
BbanStructurePart.accountNumber(23, CharacterType.n),
),
[CountryCode.CH]: new BbanStructure(
BbanStructurePart.bankCode(5, CharacterType.n),
BbanStructurePart.accountNumber(12, CharacterType.c),
),
// Provisional
[CountryCode.CI]: new BbanStructure(

@@ -108,2 +163,3 @@ BbanStructurePart.bankCode(2, CharacterType.c),

// Provisional
[CountryCode.CM]: new BbanStructure(

@@ -118,2 +174,3 @@ BbanStructurePart.accountNumber(23, CharacterType.n),

// Provisional
[CountryCode.CV]: new BbanStructure(

@@ -129,7 +186,2 @@ BbanStructurePart.accountNumber(21, CharacterType.n),

[CountryCode.CH]: new BbanStructure(
BbanStructurePart.bankCode(5, CharacterType.n),
BbanStructurePart.accountNumber(12, CharacterType.c),
),
[CountryCode.CZ]: new BbanStructure(

@@ -155,2 +207,3 @@ BbanStructurePart.bankCode(4, CharacterType.n),

// Provisional
[CountryCode.DZ]: new BbanStructure(

@@ -167,2 +220,7 @@ BbanStructurePart.accountNumber(20, CharacterType.n),

// Provisional
[CountryCode.EG]: new BbanStructure(
BbanStructurePart.accountNumber(23, CharacterType.n),
),
[CountryCode.ES]: new BbanStructure(

@@ -194,2 +252,13 @@ BbanStructurePart.bankCode(4, CharacterType.n),

// Provisional
[CountryCode.GA]: new BbanStructure(
BbanStructurePart.accountNumber(23, CharacterType.n),
),
[CountryCode.GB]: new BbanStructure(
BbanStructurePart.bankCode(4, CharacterType.a),
BbanStructurePart.branchCode(6, CharacterType.n),
BbanStructurePart.accountNumber(8, CharacterType.n),
),
[CountryCode.GE]: new BbanStructure(

@@ -205,8 +274,2 @@ BbanStructurePart.bankCode(2, CharacterType.a),

[CountryCode.GB]: new BbanStructure(
BbanStructurePart.bankCode(4, CharacterType.a),
BbanStructurePart.branchCode(6, CharacterType.n),
BbanStructurePart.accountNumber(8, CharacterType.n),
),
[CountryCode.GL]: new BbanStructure(

@@ -225,3 +288,5 @@ BbanStructurePart.bankCode(4, CharacterType.n),

BbanStructurePart.bankCode(4, CharacterType.c),
BbanStructurePart.accountNumber(20, CharacterType.c),
BbanStructurePart.currencyType(2, CharacterType.n),
BbanStructurePart.accountType(2, CharacterType.n),
BbanStructurePart.accountNumber(16, CharacterType.c),
),

@@ -234,2 +299,8 @@

// Provisional
[CountryCode.HN]: new BbanStructure(
BbanStructurePart.bankCode(4, CharacterType.a),
BbanStructurePart.accountNumber(20, CharacterType.n),
),
[CountryCode.HU]: new BbanStructure(

@@ -260,2 +331,3 @@ BbanStructurePart.bankCode(3, CharacterType.n),

// Provisional
[CountryCode.IR]: new BbanStructure(

@@ -286,2 +358,7 @@ BbanStructurePart.bankCode(3, CharacterType.n),

// Provisional
[CountryCode.KM]: new BbanStructure(
BbanStructurePart.accountNumber(23, CharacterType.n),
),
[CountryCode.KW]: new BbanStructure(

@@ -327,2 +404,7 @@ BbanStructurePart.bankCode(4, CharacterType.a),

// Provisional
[CountryCode.MA]: new BbanStructure(
BbanStructurePart.accountNumber(24, CharacterType.n),
),
[CountryCode.MC]: new BbanStructure(

@@ -346,2 +428,3 @@ BbanStructurePart.bankCode(5, CharacterType.n),

// Provisional
[CountryCode.MG]: new BbanStructure(

@@ -360,2 +443,3 @@ BbanStructurePart.bankCode(5, CharacterType.n),

// Provisional
[CountryCode.ML]: new BbanStructure(

@@ -385,2 +469,3 @@ BbanStructurePart.bankCode(1, CharacterType.a),

// Provisional
[CountryCode.MZ]: new BbanStructure(

@@ -390,2 +475,14 @@ BbanStructurePart.accountNumber(21, CharacterType.n),

// Provisional
[CountryCode.NE]: new BbanStructure(
BbanStructurePart.bankCode(2, CharacterType.a),
BbanStructurePart.accountNumber(22, CharacterType.n),
),
// Provisional
[CountryCode.NI]: new BbanStructure(
BbanStructurePart.bankCode(4, CharacterType.a),
BbanStructurePart.accountNumber(24, CharacterType.n),
),
[CountryCode.NL]: new BbanStructure(

@@ -399,3 +496,7 @@ BbanStructurePart.bankCode(4, CharacterType.a),

BbanStructurePart.accountNumber(6, CharacterType.n),
BbanStructurePart.nationalCheckDigit(1, CharacterType.n),
BbanStructurePart.nationalCheckDigit(
1,
CharacterType.n,
nationalFactory([5, 4, 3, 2, 7, 6, 5, 4, 3, 2]),
),
),

@@ -452,3 +553,3 @@

BbanStructurePart.accountNumber(16, CharacterType.n),
BbanStructurePart.accountNumber(3, CharacterType.a),
BbanStructurePart.currencyType(3, CharacterType.a),
),

@@ -480,2 +581,3 @@

// Provisional
[CountryCode.SN]: new BbanStructure(

@@ -498,2 +600,13 @@ BbanStructurePart.bankCode(1, CharacterType.a),

// Provisional
[CountryCode.TG]: new BbanStructure(
BbanStructurePart.bankCode(2, CharacterType.a),
BbanStructurePart.accountNumber(22, CharacterType.n),
),
// Provisional
[CountryCode.TD]: new BbanStructure(
BbanStructurePart.accountNumber(23, CharacterType.n),
),
[CountryCode.TL]: new BbanStructure(

@@ -522,2 +635,7 @@ BbanStructurePart.bankCode(3, CharacterType.n),

[CountryCode.VA]: new BbanStructure(
BbanStructurePart.bankCode(3, CharacterType.c),
BbanStructurePart.accountNumber(15, CharacterType.n),
),
[CountryCode.VG]: new BbanStructure(

@@ -545,2 +663,27 @@ BbanStructurePart.bankCode(4, CharacterType.c),

validate(bban: string) {
this.validateBbanLength(bban);
this.validateBbanEntries(bban);
}
extractValue(bban: string, partType: PartType): string | null {
let bbanPartOffset = 0;
let result = null;
for (let part of this.getParts()) {
const partLength = part.getLength();
const partValue = bban.substring(
bbanPartOffset,
bbanPartOffset + partLength,
);
bbanPartOffset = bbanPartOffset + partLength;
if (part.getPartType() == partType) {
result = (result || "") + partValue;
}
}
return result;
}
/**

@@ -575,2 +718,65 @@ * @param countryCode the country code.

}
private validateBbanLength(bban: string) {
const expectedBbanLength = this.getBbanLength();
const bbanLength = bban.length;
if (expectedBbanLength != bbanLength) {
throw new FormatException(
FormatViolation.BBAN_LENGTH,
`[${bban}] length is ${bbanLength}, expected BBAN length is: ${expectedBbanLength}`,
String(bbanLength),
String(expectedBbanLength),
);
}
}
private validateBbanEntries(bban: string) {
let offset = 0;
for (let part of this.getParts()) {
const partLength = part.getLength();
const entryValue = bban.substring(offset, offset + partLength);
offset = offset + partLength;
// validate character type
this.validateBbanEntryCharacterType(bban, part, entryValue);
}
}
private validateBbanEntryCharacterType(
bban: string,
part: BbanStructurePart,
entryValue: string,
) {
if (part.validate(entryValue)) {
if (part.validateValue) {
part.validateValue(entryValue, bban, this);
}
return;
}
switch (part.getCharacterType()) {
case CharacterType.a:
throw new FormatException(
FormatViolation.BBAN_ONLY_UPPER_CASE_LETTERS,
`[${entryValue}] must contain only upper case letters.`,
entryValue,
);
case CharacterType.c:
throw new FormatException(
FormatViolation.BBAN_ONLY_DIGITS_OR_LETTERS,
`[${entryValue}] must contain only digits or letters.`,
entryValue,
);
case CharacterType.n:
throw new FormatException(
FormatViolation.BBAN_ONLY_DIGITS,
`[${entryValue}] must contain only digits.`,
entryValue,
);
}
}
}
import {
UnsupportedCountryException,
BicFormatException,
FormatException,
FormatViolation,

@@ -27,3 +27,3 @@ } from "./exceptions";

* @param bic to be validated.
* @throws BicFormatException if bic is invalid.
* @throws FormatException if bic is invalid.
* UnsupportedCountryException if bic's country is not supported.

@@ -46,3 +46,3 @@ */

if (bic == null) {
throw new BicFormatException(
throw new FormatException(
FormatViolation.NOT_NULL,

@@ -54,3 +54,3 @@ "Null can't be a valid Bic.",

if (bic.length === 0) {
throw new BicFormatException(
throw new FormatException(
FormatViolation.NOT_EMPTY,

@@ -64,3 +64,3 @@ "Empty string can't be a valid Bic.",

if (bic.length !== BIC8_LENGTH && bic.length !== BIC11_LENGTH) {
throw new BicFormatException(
throw new FormatException(
FormatViolation.BIC_LENGTH_8_OR_11,

@@ -74,3 +74,3 @@ `Bic length must be ${BIC8_LENGTH} or ${BIC11_LENGTH}`,

if (bic !== bic.toUpperCase()) {
throw new BicFormatException(
throw new FormatException(
FormatViolation.BIC_ONLY_UPPER_CASE_LETTERS,

@@ -86,3 +86,3 @@ "Bic must contain only upper case letters.",

if (!ucRegex.test(bankCode)) {
throw new BicFormatException(
throw new FormatException(
FormatViolation.BANK_CODE_ONLY_LETTERS,

@@ -103,3 +103,3 @@ "Bank code must contain only letters.",

) {
throw new BicFormatException(
throw new FormatException(
FormatViolation.COUNTRY_CODE_ONLY_UPPER_CASE_LETTERS,

@@ -123,3 +123,3 @@ "Bic country code must contain upper case letters",

if (!ucnumRegex.test(locationCode)) {
throw new BicFormatException(
throw new FormatException(
FormatViolation.LOCATION_CODE_ONLY_LETTERS_OR_DIGITS,

@@ -136,3 +136,3 @@ "Location code must contain only letters or digits.",

if (!ucnumRegex.test(branchCode)) {
throw new BicFormatException(
throw new FormatException(
FormatViolation.BRANCH_CODE_ONLY_LETTERS_OR_DIGITS,

@@ -139,0 +139,0 @@ "Branch code must contain only letters or digits.",

@@ -528,9 +528,13 @@ /**

let info;
if (code.length === 3) {
return by3code[code][0];
info = by3code[code];
} else if (code.length === 2) {
return by2code[code][0];
info = by2code[code];
}
if (info) {
return info[0];
}
return null;
}

@@ -18,2 +18,4 @@ export enum FormatViolation {

NATIONAL_CHECK_DIGIT,
// IBAN Specific

@@ -34,3 +36,3 @@ CHECK_DIGIT_TWO_DIGITS,

export class BicFormatException extends Error {
export class FormatException extends Error {
formatViolation: FormatViolation;

@@ -54,21 +56,2 @@ actual?: string;

export class IbanFormatException extends Error {
formatViolation: FormatViolation;
actual?: string;
expected?: string;
constructor(
formatViolation: FormatViolation,
msg: string,
expected?: string,
actual?: string,
) {
super(msg);
this.formatViolation = formatViolation;
this.expected = expected;
this.actual = actual;
}
}
export class UnsupportedCountryException extends Error {

@@ -75,0 +58,0 @@ actual?: string;

import * as ibanUtil from "./ibanUtil";
import { countryByCode, CountryCode } from "./country";
import {
FormatViolation,
IbanFormatException,
UnsupportedCountryException,
} from "./exceptions";
import { BbanStructure } from "./bbanStructure";
import { PartType } from "./structurePart";
import { IBANBuilder } from "./ibanBuilder";
function randInt(maxVal: number, minVal: number = 0) {
return Math.floor(Math.random() * maxVal) + minVal;
}
/**
* Iban Builder Class
*/
export class IBANBuilder {
private countryCodeValue?: CountryCode;
private bankCodeValue?: string;
private branchCodeValue?: string;
private nationalCheckDigitValue?: string;
private accountTypeValue?: string;
private accountNumberValue?: string;
private ownerAccountTypeValue?: string;
private identificationNumberValue?: string;
/**
* Creates an Iban Builder instance.
*/
public constructor() {}
/**
* Sets iban's country code.
*
* @param countryCode CountryCode
* @return builder Builder
*/
countryCode(countryCode: CountryCode): IBANBuilder {
this.countryCodeValue = countryCode;
return this;
}
/**
* Sets iban's bank code.
*
* @param bankCode String
* @return builder Builder
*/
bankCode(bankCode: string): IBANBuilder {
this.bankCodeValue = bankCode;
return this;
}
/**
* Sets iban's branch code.
*
* @param branchCode String
* @return builder Builder
*/
branchCode(branchCode: string): IBANBuilder {
this.branchCodeValue = branchCode;
return this;
}
/**
* Sets iban's account number.
*
* @param accountNumber String
* @return builder Builder
*/
accountNumber(accountNumber: string): IBANBuilder {
this.accountNumberValue = accountNumber;
return this;
}
/**
* Sets iban's national check digit.
*
* @param nationalCheckDigit String
* @return builder Builder
*/
nationalCheckDigit(nationalCheckDigit: string): IBANBuilder {
this.nationalCheckDigitValue = nationalCheckDigit;
return this;
}
/**
* Sets iban's account type.
*
* @param accountType String
* @return builder Builder
*/
accountType(accountType: string): IBANBuilder {
this.accountTypeValue = accountType;
return this;
}
/**
* Sets iban's owner account type.
*
* @param ownerAccountType String
* @return builder Builder
*/
ownerAccountType(ownerAccountType: string): IBANBuilder {
this.ownerAccountTypeValue = ownerAccountType;
return this;
}
/**
* Sets iban's identification number.
*
* @param identificationNumber String
* @return builder Builder
*/
identificationNumber(identificationNumber: string): IBANBuilder {
this.identificationNumberValue = identificationNumber;
return this;
}
/**
* Builds new iban instance.
*
* @param validate boolean indicates if the generated IBAN needs to be
* validated after generation
* @return new iban instance.
* @exception IbanFormatException if values are not parsable by Iban Specification
* <a href="http://en.wikipedia.org/wiki/ISO_13616">ISO_13616</a>
* @exception UnsupportedCountryException if country is not supported
*/
build(validate: boolean = true): IBAN {
// null checks
this.require(
this.countryCodeValue,
this.bankCodeValue,
this.accountNumberValue,
);
// iban is formatted with default check digit.
const formattedIban = this.formatIban();
const checkDigit = ibanUtil.calculateCheckDigit(formattedIban);
// replace default check digit with calculated check digit
const ibanValue = ibanUtil.replaceCheckDigit(formattedIban, checkDigit);
if (validate) {
ibanUtil.validate(ibanValue);
}
return new IBAN(ibanValue);
}
/**
* Builds random iban instance.
*
* @return random iban instance.
* @exception IbanFormatException if values are not parsable by Iban Specification
* <a href="http://en.wikipedia.org/wiki/ISO_13616">ISO_13616</a>
* @exception UnsupportedCountryException if country is not supported
*
*/
public buildRandom(): IBAN {
if (this.countryCodeValue == null) {
const countryCodes = BbanStructure.supportedCountries();
this.countryCodeValue = countryCodes[randInt(countryCodes.length)];
}
this.fillMissingFieldsRandomly();
return this.build();
}
/**
* Returns formatted bban string.
*/
private formatBban(): string {
const parts: string[] = [];
const structure = BbanStructure.forCountry(this.countryCodeValue);
if (structure === null) {
throw new UnsupportedCountryException(
"Country code is not supported.",
this.countryCodeValue,
);
}
for (const part of structure.getParts()) {
switch (part.getPartType()) {
case PartType.BANK_CODE:
parts.push(this.bankCodeValue!);
break;
case PartType.BRANCH_CODE:
parts.push(this.branchCodeValue!);
break;
case PartType.ACCOUNT_NUMBER:
parts.push(this.accountNumberValue!);
break;
case PartType.NATIONAL_CHECK_DIGIT:
parts.push(this.nationalCheckDigitValue!);
break;
case PartType.ACCOUNT_TYPE:
parts.push(this.accountTypeValue!);
break;
case PartType.OWNER_ACCOUNT_NUMBER:
parts.push(this.ownerAccountTypeValue!);
break;
case PartType.IDENTIFICATION_NUMBER:
parts.push(this.identificationNumberValue!);
break;
}
}
return parts.join();
}
/**
* Returns formatted iban string with default check digit.
*/
private formatIban(): string {
return `${this.countryCodeValue}${
ibanUtil.DEFAULT_CHECK_DIGIT
}${this.formatBban()}`;
}
private require(
countryCode: CountryCode | undefined,
bankCode: string | undefined,
accountNumber: string | undefined,
) {
if (countryCode == null) {
throw new IbanFormatException(
FormatViolation.COUNTRY_CODE_NOT_NULL,
"countryCode is required; it cannot be null",
);
}
if (bankCode == null) {
throw new IbanFormatException(
FormatViolation.BANK_CODE_NOT_NULL,
"bankCode is required; it cannot be null",
);
}
if (accountNumber == null) {
throw new IbanFormatException(
FormatViolation.ACCOUNT_NUMBER_NOT_NULL,
"accountNumber is required; it cannot be null",
);
}
}
private fillMissingFieldsRandomly() {
const structure = BbanStructure.forCountry(this.countryCodeValue);
if (structure == null) {
throw new UnsupportedCountryException(
"Country code is not supported.",
this.countryCodeValue,
);
}
for (const entry of structure.getParts()) {
switch (entry.getPartType()) {
case PartType.BANK_CODE:
if (!this.bankCodeValue) {
this.bankCodeValue = entry.getRandom();
}
break;
case PartType.BRANCH_CODE:
if (!this.branchCodeValue) {
this.branchCodeValue = entry.getRandom();
}
break;
case PartType.ACCOUNT_NUMBER:
if (!this.accountNumberValue) {
this.accountNumberValue = entry.getRandom();
}
break;
case PartType.NATIONAL_CHECK_DIGIT:
if (!this.nationalCheckDigitValue) {
this.nationalCheckDigitValue = entry.getRandom();
}
break;
case PartType.ACCOUNT_TYPE:
if (!this.accountTypeValue) {
this.accountTypeValue = entry.getRandom();
}
break;
case PartType.OWNER_ACCOUNT_NUMBER:
if (!this.ownerAccountTypeValue) {
this.ownerAccountTypeValue = entry.getRandom();
}
break;
case PartType.IDENTIFICATION_NUMBER:
if (!this.identificationNumberValue) {
this.identificationNumberValue = entry.getRandom();
}
break;
}
}
}
}
/**
* International Bank Account Number

@@ -311,3 +11,2 @@ *

export class IBAN {
// Cache string value of the iban
private value: string;

@@ -319,3 +18,3 @@

* @param iban the String to be parsed, any spaces are removed.
* @throws IbanFormatException if the String doesn't contain parsable Iban
* @throws FormatException if the String doesn't contain parsable Iban
* InvalidCheckDigitException if Iban has invalid check digit

@@ -390,2 +89,11 @@ * UnsupportedCountryException if Iban's Country is not supported.

/**
* Returns iban's currency type if encoded separate from account number
*
* @return nationalCheckDigit String
*/
public getCurrencyType(): string | null {
return ibanUtil.getCurrencyType(this.value);
}
/**
* Returns iban's account type.

@@ -432,3 +140,3 @@ *

* @return an Iban object holding the value represented by the string argument.
* @throws IbanFormatException if the String doesn't contain parsable Iban
* @throws FormatException if the String doesn't contain parsable Iban
* InvalidCheckDigitException if Iban has invalid check digit

@@ -435,0 +143,0 @@ * UnsupportedCountryException if Iban's Country is not supported.

import { CountryCode, countryByCode } from "./country";
import { BbanStructure } from "./bbanStructure";
import { PartType, CharacterType, BbanStructurePart } from "./structurePart";
import { PartType } from "./structurePart";
import {
InvalidCheckDigitException,
IbanFormatException,
FormatViolation,
FormatException,
UnsupportedCountryException,

@@ -63,5 +63,7 @@ } from "./exceptions";

validateBbanLength(iban, structure);
validateBbanEntries(iban, structure);
structure.validate(getBban(iban));
// validateBbanLength(iban, structure);
// validateBbanEntries(iban, structure);
validateCheckDigit(iban);

@@ -186,2 +188,12 @@ }

/**
* Returns iban's currency type
*
* @param iban String
* @return nationalCheckDigit String
*/
export function getCurrencyType(iban: string): string | null {
return extractBbanEntry(iban, PartType.CURRENCY_TYPE);
}
/**
* Returns iban's account type.

@@ -256,3 +268,3 @@ *

if (iban == null) {
throw new IbanFormatException(
throw new FormatException(
FormatViolation.NOT_NULL,

@@ -264,3 +276,3 @@ "Null can't be a valid Iban.",

if (iban.length === 0) {
throw new IbanFormatException(
throw new FormatException(
FormatViolation.NOT_EMPTY,

@@ -275,3 +287,3 @@ "Empty string can't be a valid Iban.",

if (iban.length < COUNTRY_CODE_LENGTH) {
throw new IbanFormatException(
throw new FormatException(
FormatViolation.COUNTRY_CODE_TWO_LETTERS,

@@ -287,3 +299,3 @@ "Iban must contain 2 char country code.",

if (countryCode !== countryCode.toUpperCase() || !ucRegex.test(countryCode)) {
throw new IbanFormatException(
throw new FormatException(
FormatViolation.COUNTRY_CODE_ONLY_UPPER_CASE_LETTERS,

@@ -297,3 +309,3 @@ "Iban country code must contain upper case letters.",

if (country == null) {
throw new IbanFormatException(
throw new FormatException(
FormatViolation.COUNTRY_CODE_EXISTS,

@@ -318,3 +330,3 @@ "Iban contains non existing country code.",

if (iban.length < COUNTRY_CODE_LENGTH + CHECK_DIGIT_LENGTH) {
throw new IbanFormatException(
throw new FormatException(
FormatViolation.CHECK_DIGIT_TWO_DIGITS,

@@ -330,3 +342,3 @@ "Iban must contain 2 digit check digit.",

if (!numRegex.test(checkDigit)) {
throw new IbanFormatException(
throw new FormatException(
FormatViolation.CHECK_DIGIT_ONLY_DIGITS,

@@ -339,63 +351,2 @@ "Iban's check digit should contain only digits.",

function validateBbanLength(iban: string, structure: BbanStructure) {
const expectedBbanLength = structure.getBbanLength();
const bban = getBban(iban);
const bbanLength = bban.length;
if (expectedBbanLength != bbanLength) {
throw new IbanFormatException(
FormatViolation.BBAN_LENGTH,
`[${bban}] length is ${bbanLength}, expected BBAN length is: ${expectedBbanLength}`,
String(bbanLength),
String(expectedBbanLength),
);
}
}
function validateBbanEntries(iban: string, structure: BbanStructure) {
const bban = getBban(iban);
let offset = 0;
for (let part of structure.getParts()) {
const partLength = part.getLength();
const entryValue = bban.substring(offset, offset + partLength);
offset = offset + partLength;
// validate character type
validateBbanEntryCharacterType(part, entryValue);
}
}
function validateBbanEntryCharacterType(
part: BbanStructurePart,
entryValue: string,
) {
if (part.validate(entryValue)) {
return;
}
switch (part.getCharacterType()) {
case CharacterType.a:
throw new IbanFormatException(
FormatViolation.BBAN_ONLY_UPPER_CASE_LETTERS,
`[${entryValue}] must contain only upper case letters.`,
entryValue,
);
case CharacterType.c:
throw new IbanFormatException(
FormatViolation.BBAN_ONLY_DIGITS_OR_LETTERS,
`[${entryValue}] must contain only digits or letters.`,
entryValue,
);
case CharacterType.n:
throw new IbanFormatException(
FormatViolation.BBAN_ONLY_DIGITS,
`[${entryValue}] must contain only digits.`,
entryValue,
);
}
}
/**

@@ -449,3 +400,3 @@ * Calculates

} else {
throw new IbanFormatException(
throw new FormatException(
FormatViolation.IBAN_VALID_CHARACTERS,

@@ -485,19 +436,3 @@ `Invalid Character[${ch}] = '${code}'`,

let bbanPartOffset = 0;
let result = null;
for (let part of structure.getParts()) {
const partLength = part.getLength();
const partValue = bban.substring(
bbanPartOffset,
bbanPartOffset + partLength,
);
bbanPartOffset = bbanPartOffset + partLength;
if (part.getPartType() == partType) {
result = (result || "") + partValue;
}
}
return result;
return structure.extractValue(bban, partType);
}
export { CountryCode } from "./country";
export { BbanStructure } from "./bbanStructure";
export { IBAN, IBANBuilder } from "./iban";
export { IBAN } from "./iban";
export { IBANBuilder } from "./ibanBuilder";
export { BIC } from "./bic";

@@ -0,1 +1,4 @@

import { randInt } from "./randInt";
import { BbanStructure } from "./bbanStructure";
export enum PartType {

@@ -6,2 +9,3 @@ BANK_CODE,

NATIONAL_CHECK_DIGIT,
CURRENCY_TYPE,
ACCOUNT_TYPE,

@@ -28,10 +32,24 @@ OWNER_ACCOUNT_NUMBER,

c,
/**
* Blank space
*/
e,
}
const charByCharacterType: Record<CharacterType, string[]> = {
[CharacterType.n]: "0123456789".split(""),
[CharacterType.a]: "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""),
[CharacterType.c]: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""),
// Use by random string generation
const charByCharacterType: Record<CharacterType, string> = {
[CharacterType.n]: "0123456789",
[CharacterType.a]: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
[CharacterType.c]: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",
[CharacterType.e]: " ",
};
// Used by validation
const charByCharacterRE: Record<CharacterType, RegExp> = {
[CharacterType.n]: /^[0-9]+$/,
[CharacterType.a]: /^[A-Z]+$/,
[CharacterType.c]: /^[0-9A-Za-z]+$/,
[CharacterType.e]: /^ +$/,
};
export class BbanStructurePart {

@@ -42,2 +60,4 @@ private entryType: PartType;

validateValue?(value: string, bban: string, structure: BbanStructure): void;
private constructor(

@@ -47,2 +67,3 @@ entryType: PartType,

length: number,
validate?: (value: string, bban: string, structure: BbanStructure) => void,
) {

@@ -52,2 +73,3 @@ this.entryType = entryType;

this.length = length;
this.validateValue = validate;
}

@@ -83,2 +105,3 @@

characterType: CharacterType,
validate?: (value: string, bban: string, structure: BbanStructure) => void,
): BbanStructurePart {

@@ -89,2 +112,3 @@ return new BbanStructurePart(

length,
validate,
);

@@ -100,2 +124,9 @@ }

static currencyType(
length: number,
characterType: CharacterType,
): BbanStructurePart {
return new BbanStructurePart(PartType.CURRENCY_TYPE, characterType, length);
}
static ownerAccountNumber(

@@ -136,8 +167,5 @@ length: number,

getRandom(): string {
const charChoices: string[] = charByCharacterType[this.characterType];
const charChoices = charByCharacterType[this.characterType];
let s: string[] = [];
const randInt = (maxVal: number, minVal: number = 0) =>
Math.floor(Math.random() * maxVal) + minVal;
for (let i = 0; i < this.getLength(); i += 1) {

@@ -154,6 +182,4 @@ s.push(charChoices[randInt(charChoices.length)]);

validate(value: string): boolean {
const validValues = charByCharacterType[this.characterType];
return value.split("").find(v => !validValues.includes(v)) === undefined;
return charByCharacterRE[this.characterType].test(value);
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc