Add regex for BIP44 Strings (#1035)

* Add regex check for BIP44 paths

* Add tests for BIP44 regex

* Remove '/config' from excluded paths in jest

* update path

* Update Validator tests & remove old dPathRegex tests

* Test hardcoded dpaths
This commit is contained in:
James Prado 2018-02-26 20:20:41 -05:00 committed by Daniel Ternyak
parent b3da25c3f7
commit 81d4444dff
7 changed files with 160 additions and 14 deletions

View File

@ -15,7 +15,7 @@ export const ETH_LEDGER: DPath = {
export const ETC_LEDGER: DPath = {
label: 'Ledger (ETC)',
value: "m/44'/60'/160720'/0'"
value: "m/44'/60'/160720'/0"
};
export const ETC_TREZOR: DPath = {
@ -43,5 +43,30 @@ export const ETH_SINGULAR: DPath = {
value: "m/0'/0'/0'"
};
export const DPaths: DPath[] = [
ETH_DEFAULT,
ETH_TREZOR,
ETH_LEDGER,
ETC_LEDGER,
ETC_TREZOR,
ETH_TESTNET,
EXP_DEFAULT,
UBQ_DEFAULT
];
// PATHS TO BE INCLUDED REGARDLESS OF WALLET FORMAT
export const EXTRA_PATHS = [ETH_SINGULAR];
// Full length deterministic wallet paths from BIP44
// https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
// normal path length is 4, ledger is the exception at 3
// m / purpose' / coin_type' / account' / change / address_index
// | | | | |
// | constant | index | index | 0 or 1 |
// |__________|____________|__________|________|
// whitespace strings are evaluated the same way as nospace strings, except they allow optional spaces between each portion of the string
// ie. "m / 44' / 0' / 0'" is valid, "m / 4 4' / 0' / 0'" is invalid
export const dPathRegex = /m\/44'\/[0-9]+\'\/[0-9]+(\'+$|\'+(\/[0-1]+$))/;
// export const whitespaceDPathRegex = /m\s*\/\s*44'\s*\/\s*[0-9]+\'\s*\/\s*[0-9]+(\'+$|\'+\s*(\/\s*[0-1]+$))/;

View File

@ -2,3 +2,4 @@ export * from './data';
export * from './bity';
export * from './addressMessages';
export * from './helpArticles';
export * from './dpaths';

View File

@ -11,6 +11,7 @@ import {
GAS_PRICE_GWEI_LOWER_BOUND,
GAS_PRICE_GWEI_UPPER_BOUND
} from 'config/constants';
import { dPathRegex } from 'config/dpaths';
// FIXME we probably want to do checksum checks sideways
export function isValidETHAddress(address: string): boolean {
@ -121,13 +122,8 @@ export function isPositiveIntegerOrZero(num: number): boolean {
return num >= 0 && parseInt(num.toString(), 10) === num;
}
// Full length deterministic wallet paths from BIP44
// https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
// normal path length is 4, ledger is the exception at 3
export function isValidPath(dPath: string) {
// TODO: use a regex to detect proper paths
const len = dPath.split("'/").length;
return len === 3 || len === 4;
return dPathRegex.test(dPath);
}
export const isValidValue = (value: string) =>

View File

@ -10,9 +10,9 @@
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$":
"<rootDir>/jest_config/__mocks__/fileMock.ts",
"\\.(css|scss|less)$": "<rootDir>/jest_config/__mocks__/styleMock.ts",
"\\.worker.ts":"<rootDir>/jest_config/__mocks__/workerMock.js"
"\\.worker.ts": "<rootDir>/jest_config/__mocks__/workerMock.js"
},
"testPathIgnorePatterns": ["<rootDir>/common/config"],
"testPathIgnorePatterns": [],
"setupFiles": [
"<rootDir>/jest_config/setupJest.js",
"<rootDir>/jest_config/__mocks__/localStorage.ts"

View File

@ -8,10 +8,10 @@
"moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json"],
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$":
"<rootDir>/jest_config/__mocks__/fileMock.ts",
"<rootDir>/jest_config/__mocks__/fileMock.ts",
"\\.(css|scss|less)$": "<rootDir>/jest_config/__mocks__/styleMock.ts"
},
"testPathIgnorePatterns": ["<rootDir>/common/config"],
"testPathIgnorePatterns": [],
"setupFiles": [
"<rootDir>/jest_config/setupJest.js",
"<rootDir>/jest_config/__mocks__/localStorage.ts"

View File

@ -4,6 +4,8 @@ import {
isValidPath,
isValidPrivKey
} from '../../common/libs/validators';
import { DPaths } from 'config/dpaths';
import { valid, invalid } from '../utils/testStrings';
const VALID_BTC_ADDRESS = '1MEWT2SGbqtz6mPCgFcnea8XmWV5Z4Wc6';
const VALID_ETH_ADDRESS = '0x7cB57B5A97eAbe94205C07890BE4c1aD31E486A8';
@ -26,9 +28,6 @@ describe('Validator', () => {
it('should validate incorrect ETH address as false', () => {
expect(isValidETHAddress('nonsense' + VALID_ETH_ADDRESS + 'nonsense')).toBeFalsy();
});
it('should validate a correct DPath as true', () => {
expect(isValidPath("m/44'/60'/0'/0")).toBeTruthy();
});
it('should validate an incorrect DPath as false', () => {
expect(isValidPath('m/44/60/0/0')).toBeFalsy();
});
@ -45,3 +44,21 @@ describe('Validator', () => {
expect(isValidPrivKey(VALID_ETH_PRIVATE_BUFFER)).toBeTruthy();
});
});
describe('Validator', () => {
it('should validate correct DPaths as true', () => {
valid.forEach(path => {
expect(isValidPath(path)).toBeTruthy();
});
});
it('should validate incorrect DPaths as false', () => {
invalid.forEach(path => {
expect(isValidPath(path)).toBeFalsy();
});
});
it('should validate hardcoded DPaths as true', () => {
DPaths.forEach(DPath => {
expect(isValidPath(DPath.value)).toBeTruthy();
});
});
});

107
spec/utils/testStrings.ts Normal file
View File

@ -0,0 +1,107 @@
// Deterministic Wallet Path test strings
// https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
// m / purpose' / coin_type' / account' / change / address_index
const length5 = [
"m/44'/0'/0'/0/0",
"m/44'/0'/0'/0/1",
"m/44'/0'/0'/1/0",
"m/44'/0'/0'/1/1",
"m/44'/0'/1'/0/0",
"m/44'/0'/1'/0/1",
"m/44'/0'/1'/1/0",
"m/44'/0'/1'/1/1",
"m/44'/1'/0'/0/0",
"m/44'/1'/0'/0/1",
"m/44'/1'/0'/1/0",
"m/44'/1'/0'/1/1",
"m/44'/1'/1'/0/0",
"m/44'/1'/1'/0/1",
"m/44'/1'/1'/1/0",
"m/44'/1'/1'/1/1"
];
const wsLength5 = [
"m / 44' / 0' / 0' / 0 / 0",
"m / 44' / 0' / 0' / 0 / 1",
"m / 44' / 0' / 0' / 1 / 0",
"m / 44' / 0' / 0' / 1 / 1",
"m / 44' / 0' / 1' / 0 / 0",
"m / 44' / 0' / 1' / 0 / 1",
"m / 44' / 0' / 1' / 1 / 0",
"m / 44' / 0' / 1' / 1 / 1",
"m / 44' / 1' / 0' / 0 / 0",
"m / 44' / 1' / 0' / 0 / 1",
"m / 44' / 1' / 0' / 1 / 0",
"m / 44' / 1' / 0' / 1 / 1",
"m / 44' / 1' / 1' / 0 / 0",
"m / 44' / 1' / 1' / 0 / 1",
"m / 44' / 1' / 1' / 1 / 0",
"m / 44' / 1' / 1' / 1 / 1"
];
// m / purpose' / coin_type' / account' / change
const length4 = [
"m/44'/0'/0'/0",
"m/44'/0'/0'/1",
"m/44'/0'/1'/0",
"m/44'/0'/1'/1",
"m/44'/1'/0'/0",
"m/44'/1'/0'/1",
"m/44'/1'/1'/0",
"m/44'/1'/1'/1"
];
const wsLength4 = [
"m / 44' / 0' / 0' / 0",
"m / 44' / 0' / 0' / 1",
"m / 44' / 0' / 1' / 0",
"m / 44' / 0' / 1' / 1",
"m / 44' / 1' / 0' / 0",
"m / 44' / 1' / 0' / 1",
"m / 44' / 1' / 1' / 0",
"m / 44' / 1' / 1' / 1"
];
// m / purpose' / coin_type' / account'
const length3 = ["m/44'/0'/0'", "m/44'/0'/1'", "m/44'/1'/0'", "m/44'/1'/1'"];
const wsLength3 = [
"m / 44' / 0' / 0'",
"m / 44' / 0' / 1'",
"m / 44' / 1' / 0'",
"m / 44' / 1' / 1'"
];
// 'coin_type' accepts an index (0 - infinity)
// https://github.com/satoshilabs/slips/blob/master/slip-0044.md
// m / purpose' / coin_type' / account' / change
const validCoinType = ["m/44'/3'/0'/0", "m/44'/60'/0'/0", "m/44'/37310'/0'/0"];
const invalidCoinType = ["m/44'/-1'/0'/0", "m/44'/3.2'/0'/0", "m/44'/twenty'/0'/0"];
// 'account' accepts an index (0 - infinity)
// m / purpose' / coin_type' / account' / change
const validAccount = ["m/44'/0'/3'/0", "m/44'/0'/30'/0", "m/44'/0'/97878'/0"];
const invalidAccount = ["m/44'/0'/-1'/0", "m/44'/0'/a'/0", "m/44'/0'/9.3'/0"];
// 'change' accepts a boolean (0 - 1)
// m / purpose' / coin_type' / account' / change
const validChange = ["m/44'/0'/0'/1", "m/44'/0'/0'/0"];
const inValidChange = ["m/44'/0'/0'/3", "m/44'/0'/0'/-1", "m/44'/0'/0'/0.5", "m/44'/0'/0'/a"];
const validPaths = [...validCoinType, ...validAccount, ...validChange];
const inValidPaths = [
...length5,
...wsLength5,
...invalidCoinType,
...invalidAccount,
...inValidChange
];
export const valid = [...length4, ...length3, ...validPaths];
export const invalid = [...wsLength4, ...wsLength3, ...inValidPaths];
// whitespace strings are evaluated the same way as nospace strings, except they allow optional spaces between each portion of the string
// ie. "m / 44' / 0' / 0'" is valid, "m / 4 4' / 0' / 0'" is invalid
export const whitespaceValid = [...wsLength4, ...wsLength3, ...valid];
export const whitespaceInvalid = [...invalid];