Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ Validator | Description
**isVariableWidth(str)** | check if the string contains a mixture of full and half-width chars.
**isVAT(str, countryCode)** | checks that the string is a [valid VAT number](https://en.wikipedia.org/wiki/VAT_identification_number) if validation is available for the given country code matching [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2). <br/><br/>Available country codes: `[ 'GB', 'IT' ]`.
**isWhitelisted(str, chars)** | checks characters if they appear in the whitelist.
**isXRPAddress(str, [, options])** | check if string is valid XRP address. <br/><br/><i>options</i> object is optional. With options object, we can specify format of xrp address (classic and/or xAddress). In case of xAddress, user must also specify if we should check if address is valid on test/dev network, or on main network, because format of xAddress depends on network. <br/><br/>Example: `{ classicAddress: true, xAddress: { test: false } }`<br/><br/><i>Note: This does not verify checksum of address. This checks only the format of address.</i>
**matches(str, pattern [, modifiers])** | check if string matches the pattern.<br/><br/>Either `matches('foo', /foo/i)` or `matches('foo', 'foo', 'i')`.

## Sanitizers
Expand Down
3 changes: 3 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ import isMimeType from './lib/isMimeType';
import isLatLong from './lib/isLatLong';
import isPostalCode, { locales as isPostalCodeLocales } from './lib/isPostalCode';

import isXRPAddress from './lib/isXRPAddress';

import ltrim from './lib/ltrim';
import rtrim from './lib/rtrim';
import trim from './lib/trim';
Expand Down Expand Up @@ -222,6 +224,7 @@ const validator = {
isDate,
isLicensePlate,
isVAT,
isXRPAddress,
};

export default validator;
30 changes: 30 additions & 0 deletions src/lib/isXRPAddress.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import assertString from './util/assertString';

const classicAddressRegex = /^r[A-HJ-NP-Za-km-z1-9]{24,35}$/;
const xAddressMainnetRegex = /^X[A-HJ-NP-Za-km-z1-9]{46,}$/;
const xAddressNonMainnetRegex = /^T[A-HJ-NP-Za-km-z1-9]{46,}$/;

export default function isXRPAddress(address, options) {
assertString(address);

if (typeof (options) !== 'object') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can say, even typeof (null) === object.
One of the best ways to check object type is to check its prototype ie.
Object.prototype.toString.call(option).toLowerCase(), most of the case is that the second part after space is the type.
I think I will add a validator to check the type

// only check for classic address
return classicAddressRegex.test(address);
}

if (typeof (options.xAddress) !== 'object') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have written that help us make a robust code here, #1648

// just passthrough if user does not want to check anything
return options.classicAddress ? classicAddressRegex.test(address) : true;
}

let xAddressRegex = xAddressMainnetRegex;
if (options.xAddress.test) {
xAddressRegex = xAddressNonMainnetRegex;
}

if (options.classicAddress) {
return xAddressRegex.test(address) || classicAddressRegex.test(address);
}

return xAddressRegex.test(address);
}
158 changes: 157 additions & 1 deletion test/validators.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import assert from 'assert';
import fs from 'fs';
import { format } from 'util';
import fs from 'fs';
import vm from 'vm';
import validator from '../src/index';

Expand Down Expand Up @@ -8589,6 +8589,162 @@ describe('Validators', () => {
});
});

it('should validate XRP addresses', () => {
test({
validator: 'isXRPAddress',
valid: [
'rAAAAAAAAAAAAAAAAAAAAAAAAA',
'rUfkLWGb7UwFgpci24kBpu7eCR',
'r4zkbgzeQriVB1iFeZj8rTT1q3oTnpLxUG',
],
invalid: [
'r4zkbgzeQriVB1iFeZj8rTT1',
'r4zkbgzeQriVB1iFeZj8rTT1q3oInpLxUG',
'r4zkbgzeQriVB1iFeZj8rTT1q3oOnpLxUG',
'r4zkbgzeQriVB1iFeZj8rTT1q3olnpLxUG',
'r4zkbgzeQriVB1iFeZj8rTT1q3o+npLxUG',
'r4zkbgzeQriVB1iFeZj8rTT1q3o/npLxUG',
'4zkbgzeQriVB1iFeZj8rTT1q3oTnpLxUGr',
'r4zkbgzeQriVB1iFeZj8rTT1q3oTnpLxUGGGG',
],
});

test({
validator: 'isXRPAddress',
args: [
{
classicAddress: false,
},
],
valid: [
'a',
'xyz',
],
});

test({
validator: 'isXRPAddress',
args: [
{
classicAddress: true,
},
],
valid: [
'rAAAAAAAAAAAAAAAAAAAAAAAAA',
'rUfkLWGb7UwFgpci24kBpu7eCR',
'r4zkbgzeQriVB1iFeZj8rTT1q3oTnpLxUG',
],
invalid: [
'r4zkbgzeQriVB1iFeZj8rTT1',
'r4zkbgzeQriVB1iFeZj8rTT1q3oInpLxUG',
'r4zkbgzeQriVB1iFeZj8rTT1q3oOnpLxUG',
'r4zkbgzeQriVB1iFeZj8rTT1q3olnpLxUG',
'r4zkbgzeQriVB1iFeZj8rTT1q3o+npLxUG',
'r4zkbgzeQriVB1iFeZj8rTT1q3o/npLxUG',
'4zkbgzeQriVB1iFeZj8rTT1q3oTnpLxUGr',
'r4zkbgzeQriVB1iFeZj8rTT1q3oTnpLxUGGGG',
],
});

test({
validator: 'isXRPAddress',
args: [
{
xAddress: {
test: false,
},
},
],
valid: [
'X7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cqZ',
'XV5sbjUmgPpvXv4ixFWZ5ptAYZ6PD2gYsjNFQLKYW33DzBm',
'XV5sbjUmgPpvXv4ixFWZ5ptAYZ6PD28Sq49uo34VyjnmK5H',
],
invalid: [
'rAAAAAAAAAAAAAAAAAAAAAAAAA',
'rUfkLWGb7UwFgpci24kBpu7eCR',
'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
'r4zkbgzeQriVB1iFeZj8rTT1q3oTnpLxUG',
'T7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cqZ',
],
});

test({
validator: 'isXRPAddress',
args: [
{
xAddress: {
test: true,
},
},
],
valid: [
'T7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cqZ',
],
invalid: [
'rAAAAAAAAAAAAAAAAAAAAAAAAA',
'rUfkLWGb7UwFgpci24kBpu7eCR',
'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
'r4zkbgzeQriVB1iFeZj8rTT1q3oTnpLxUG',
'T7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cq',
'X7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cqZ',
],
});

test({
validator: 'isXRPAddress',
args: [
{
classicAddress: true,
xAddress: {
test: true,
},
},
],
valid: [
'rAAAAAAAAAAAAAAAAAAAAAAAAA',
'rUfkLWGb7UwFgpci24kBpu7eCR',
'r4zkbgzeQriVB1iFeZj8rTT1q3oTnpLxUG',
'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
'T7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cqZ',
],
invalid: [
'T7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cq',
'X7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cqZ',
],
});

test({
validator: 'isXRPAddress',
args: [
{
classicAddress: true,
xAddress: {
test: false,
},
},
],
valid: [
'rAAAAAAAAAAAAAAAAAAAAAAAAA',
'rUfkLWGb7UwFgpci24kBpu7eCR',
'r4zkbgzeQriVB1iFeZj8rTT1q3oTnpLxUG',
'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
'X7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cqZ',
],
invalid: [
'r4zkbgzeQriVB1iFeZj8rTT1',
'r4zkbgzeQriVB1iFeZj8rTT1q3oInpLxUG',
'r4zkbgzeQriVB1iFeZj8rTT1q3oOnpLxUG',
'r4zkbgzeQriVB1iFeZj8rTT1q3olnpLxUG',
'r4zkbgzeQriVB1iFeZj8rTT1q3o+npLxUG',
'r4zkbgzeQriVB1iFeZj8rTT1q3o/npLxUG',
'4zkbgzeQriVB1iFeZj8rTT1q3oTnpLxUGr',
'r4zkbgzeQriVB1iFeZj8rTT1q3oTnpLxUGGGG',
'T7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cq',
],
});
});

it('should validate booleans', () => {
test({
validator: 'isBoolean',
Expand Down