Skip to content

Commit

Permalink
feat: added VPA validation
Browse files Browse the repository at this point in the history
  • Loading branch information
mastermunj committed Apr 28, 2020
1 parent 2b42b0f commit d843c51
Show file tree
Hide file tree
Showing 13 changed files with 449 additions and 3 deletions.
28 changes: 26 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Format Utilities
# Format Validation Utilities

## Introduction

Utilities for validating various formats of Indian system codes like Mobile, PAN, AADHAR, UID and more!
Utilities for validating various formats of Indian system codes like Mobile, PAN, AADHAR, GST and more!

## Installation

Expand Down Expand Up @@ -221,3 +221,27 @@ let isValid = Validator.vehicleRegistration('DL4CAF4943');
isValid = Validator.vehicleRegistration('DL4CAF494G');
// isValid = false
```

### VPA (Virtual Payment Address)

A VPA / UPI (Unified Payment Interface) ID is a unique id generated for use of UPI in India.

#### Format
* VPA consists of alphabets, numbers, hyphen (`-`), underscore (`_`) and dot (`.`) as part of identification.
* The identification part is followed by `@` sign.
* The last part is the handle of the issuer bank or PSP (Payment Service Provider).
* The maximum length of VPA is 50 characters.

#### Options
| Option | Type | Default | Description |
| ------------- | ------------- | ------------- | ------------- |
| maxLength | number | 50 | Maximum length of the VPA address including `@` sign & the handle. |
| handles | boolean \| string[] | false | Whether to do additional check of verifying the handle. <br/>When it is `true` the handle part is checked against default handles listed in [vpa-handles.json](./src/vpa-handles.json). <br/>When it is `string[]` the handle part is checked against merged list of default handles listed in [vpa-handles.json](./src/vpa-handles.json) and the ones given as input. |

```js
let isValid = Validator.vpa('amazing-uid@upi');
// isValid = true

isValid = Validator.vpa('with@at@upi');
// isValid = false
```
13 changes: 13 additions & 0 deletions __tests__/validator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,3 +202,16 @@ describe('Vehicle Registration Number', () => {
expect(Validator.vehicleRegistration(value)).toBe(expected);
});
});

describe('VPA', () => {
const tests: [string, boolean][] = [
['amazing-uid@upi', true],
['random9999@upi', true],

['axisbank@bankaxis', false],
['very-long-upi-id-or-vpa-should-not-pass-the-validation@upi', false],
];
test.each(tests)(`Check %s => %s`, (value, expected) => {
expect(Validator.vpa(value)).toBe(expected);
});
});
87 changes: 87 additions & 0 deletions __tests__/vpa.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { VPA } from '../src/vpa';

describe('VPA', () => {
const tests: [string, boolean][] = [
['amazing-uid@upi', true],
['random9999@upi', true],
['vpa_with_underscore@upi', true],
['vpa-with-hyphen@upi', true],
['vpa.with.dot@upi', true],
['9876543210@upi', true],

['it@upi', false],
['with#hash@upi', false],
['with space@upi', false],
['with@at@upi', false],
['very-long-upi-id-or-vpa-should-not-pass-the-validation@upi', false],
];
test.each(tests)(`Check %s => %s`, (value, expected) => {
expect(VPA.validate(value)).toBe(expected);
});
});

describe('VPA with options: { maxLength: 20 }', () => {
const tests: [string, boolean][] = [
['amazing-uid@upi', true],
['random9999@upi', true],

['vpa_with_underscore@upi', false],
['very-long-upi-id-or-vpa-should-not-pass-the-validation@upi', false],
];
test.each(tests)(`Check %s => %s`, (value, expected) => {
expect(VPA.validate(value, { maxLength: 20 })).toBe(expected);
});
});

describe('VPA with options: { handles: true }', () => {
const tests: [string, boolean][] = [
['amazing-uid@upi', true],
['random9999@upi', true],
['yesbank@ybl', true],
['axisbank@okaxis', true],

['axisbank@bankaxis', false],
['very-long-upi-id-or-vpa-should-not-pass-the-validation@upi', false],
];
test.each(tests)(`Check %s => %s`, (value, expected) => {
expect(VPA.validate(value, { handles: true })).toBe(expected);
});
});

describe('VPA with options: { handles: ["bankaxis", "superbank"] }', () => {
const tests: [string, boolean][] = [
['amazing-uid@upi', true],
['random9999@upi', true],
['yesbank@ybl', true],
['axisbank@okaxis', true],
['axisbank@bankaxis', true],
['super-vpa@superbank', true],

['super-vpa@banksuper', false],
['very-long-upi-id-or-vpa-should-not-pass-the-validation@upi', false],
['very-long-upi-id-or-vpa-should-not-pass-the-validation@superbank', false],
];
const handles = ['bankaxis', 'superbank'];
test.each(tests)(`Check %s => %s`, (value, expected) => {
expect(VPA.validate(value, { handles })).toBe(expected);
});
});

describe('VPA with options: { maxLength: 20, handles: ["bankaxis", "superbank"] }', () => {
const tests: [string, boolean][] = [
['amazing-uid@upi', true],
['random9999@upi', true],
['yesbank@ybl', true],
['axisbank@okaxis', true],
['axisbank@bankaxis', true],
['super-vpa@superbank', true],

['super-vpa@banksuper', false],
['very-long-upi-id-or-vpa-should-not-pass-the-validation@upi', false],
['very-long-upi-id-or-vpa-should-not-pass-the-validation@superbank', false],
];
const handles = ['bankaxis', 'superbank'];
test.each(tests)(`Check %s => %s`, (value, expected) => {
expect(VPA.validate(value, { maxLength: 20, handles })).toBe(expected);
});
});
2 changes: 2 additions & 0 deletions dist/validator.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { VpaValidationOptions } from './vpa';
export declare class Validator {
static mobile(value: string): boolean;
static pincode(value: string | number): boolean;
Expand All @@ -12,4 +13,5 @@ export declare class Validator {
static gst(value: string): boolean;
static gstChecksum(value: string): boolean;
static vehicleRegistration(value: string): boolean;
static vpa(value: string, options?: VpaValidationOptions): boolean;
}
4 changes: 4 additions & 0 deletions dist/validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Object.defineProperty(exports, "__esModule", { value: true });
const luhn_1 = require("./luhn");
const verhoeff_1 = require("./verhoeff");
const vpa_1 = require("./vpa");
class Validator {
static mobile(value) {
return /^[6789]\d{9}$/.test(value);
Expand Down Expand Up @@ -62,5 +63,8 @@ class Validator {
const regex = /^[A-Z]{2}[\s-.]?[0-9]{1,2}[\s-.]?[0-9A-Z]{1,3}[\s-.]?[0-9]{1,4}$/i;
return regex.test(value);
}
static vpa(value, options) {
return vpa_1.VPA.validate(value, options);
}
}
exports.Validator = Validator;
112 changes: 112 additions & 0 deletions dist/vpa-handles.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
[
"abfspay",
"airtel",
"airtelpaymentsbank",
"albk",
"allahabadbank",
"allbank",
"andb",
"apb",
"apl",
"axis",
"axisb",
"axisbank",
"axisgo",
"bandhan",
"barodampay",
"barodapay",
"boi",
"cbin",
"cboi",
"centralbank",
"cmsidfc",
"cnrb",
"csbcash",
"csbpay",
"cub",
"dbs",
"dcb",
"dcbbank",
"denabank",
"dlb",
"eazypay",
"equitas",
"ezeepay",
"fbl",
"federal",
"finobank",
"hdfcbank",
"hdfcbankjd",
"hsbc",
"icici",
"idbi",
"idbibank",
"idfc",
"idfcbank",
"idfcnetc",
"ikwik",
"imobile",
"indbank",
"indianbank",
"indianbk",
"indus",
"indusind",
"iob",
"jkb",
"jsbp",
"karb",
"karurvysyabank",
"kaypay",
"kbl",
"kbl052",
"kmb",
"kmbl",
"kotak",
"kvb",
"kvbank",
"lime",
"lvb",
"lvbank",
"mahb",
"myicici",
"obc",
"okaxis",
"okhdfcbank",
"okicici",
"oksbi",
"paytm",
"payzapp",
"pingpay",
"pnb",
"pockets",
"psb",
"purz",
"rajgovhdfcbank",
"rbl",
"sbi",
"sc",
"scb",
"scbl",
"scmobile",
"sib",
"srcb",
"synd",
"syndbank",
"syndicate",
"tjsb",
"ubi",
"uboi",
"uco",
"unionbank",
"unionbankofindia",
"united",
"utbi",
"vijayabank",
"vijb",
"vjb",
"ybl",
"yesbank",
"yesbankltd",
"freecharge",
"upi"
]
9 changes: 9 additions & 0 deletions dist/vpa.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export declare type VpaValidationOptions = {
maxLength?: number;
handles?: boolean | string[];
};
export declare class VPA {
static defaultVpaHandles: string[] | undefined;
static validate(value: string, options?: VpaValidationOptions): boolean;
static getDefaultVpaHandles(): string[];
}
33 changes: 33 additions & 0 deletions dist/vpa.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const ValidationOptionsDefaults = {
maxLength: 50,
handles: true,
};
class VPA {
static validate(value, options) {
options = Object.assign({}, ValidationOptionsDefaults, options);
const regex = /^[a-z0-9_.-]{3,}@[a-z]{3,}$/i;
let isValidFormat = regex.test(value) && value.length <= options.maxLength;
if (!isValidFormat) {
return false;
}
if (options.handles) {
const defaultHandles = VPA.getDefaultVpaHandles();
options.handles = (options.handles === true
? defaultHandles
: [...options.handles, ...defaultHandles]);
const handle = value.split('@')[1];
isValidFormat = options.handles.indexOf(handle) >= 0;
}
return isValidFormat;
}
static getDefaultVpaHandles() {
if (VPA.defaultVpaHandles === undefined) {
VPA.defaultVpaHandles = require('./vpa-handles.json');
}
return VPA.defaultVpaHandles;
}
}
exports.VPA = VPA;
VPA.defaultVpaHandles = undefined;
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
"GST",
"GSTIN",
"vehicle registration",
"vpa",
"upi",
"upi id",
"india",
"validators",
"validation"
Expand Down
5 changes: 5 additions & 0 deletions src/validator.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Luhn } from './luhn';
import { Verhoeff } from './verhoeff';
import { VPA, VpaValidationOptions } from './vpa';

export class Validator {
static mobile(value: string): boolean {
Expand Down Expand Up @@ -73,4 +74,8 @@ export class Validator {
const regex = /^[A-Z]{2}[\s-.]?[0-9]{1,2}[\s-.]?[0-9A-Z]{1,3}[\s-.]?[0-9]{1,4}$/i;
return regex.test(value);
}

static vpa(value: string, options?: VpaValidationOptions): boolean {
return VPA.validate(value, options);
}
}

0 comments on commit d843c51

Please sign in to comment.