Fix some checks and add a CLI
This commit is contained in:
parent
b40c3eb8e5
commit
2a74f4e07b
8 changed files with 378 additions and 12 deletions
|
|
@ -2,6 +2,7 @@ const INVALID_SEEDS = [
|
|||
'',
|
||||
12,
|
||||
'947ee0115014a4d49a804e7fc7248e31690b80033ce7a6e3a07bdf93b2584ff',
|
||||
'947ee0115014a4d49a804e7fc7248e31690b80033ce7a6e3a07bdf93b2584ffff',
|
||||
'z947ee0115014a4d49a804e7fc7248e31690b80033ce7a6e3a07bdf93b2584ff',
|
||||
];
|
||||
|
||||
|
|
@ -11,6 +12,7 @@ const INVALID_SECRET_KEYS = [
|
|||
'',
|
||||
12,
|
||||
'3b5e95b4c4325ed5af109bfe4acde782dbab0163591d9052963723ae8e72a09',
|
||||
'3b5e95b4c4325ed5af109bfe4acde782dbab0163591d9052963723ae8e72a0999',
|
||||
'z3b5e95b4c4325ed5af109bfe4acde782dbab0163591d9052963723ae8e72a09',
|
||||
];
|
||||
|
||||
|
|
@ -18,6 +20,7 @@ const INVALID_PUBLIC_KEYS = [
|
|||
'',
|
||||
12,
|
||||
'd312f604f638adf19afac6308ecbbc5881e1b6cd6f53d382775c686bca7535b',
|
||||
'd312f604f638adf19afac6308ecbbc5881e1b6cd6f53d382775c686bca7535bbb',
|
||||
'zd312f604f638adf19afac6308ecbbc5881e1b6cd6f53d382775c686bca7535b',
|
||||
];
|
||||
|
||||
|
|
@ -25,14 +28,17 @@ const INVALID_HASHES = [
|
|||
'',
|
||||
12,
|
||||
'f7122e843b27524f4f1d6bd14aefd1c8f01d36ae8653d37417533c0d4bc2be6',
|
||||
'f7122e843b27524f4f1d6bd14aefd1c8f01d36ae8653d37417533c0d4bc2be666',
|
||||
'zf7122e843b27524f4f1d6bd14aefd1c8f01d36ae8653d37417533c0d4bc2be6',
|
||||
];
|
||||
|
||||
const INVALID_WORKS = ['', 12, '000000000995bc3', 'z000000000995bc3'];
|
||||
const INVALID_WORKS = ['', 12, '000000000995bc3', '000000000995bc333', 'z000000000995bc3'];
|
||||
|
||||
const INVALID_ADDRESSES = [
|
||||
'',
|
||||
12,
|
||||
'axrb_1mbj7xi6yrwcuwetzd5535pdqjea5rfpsoqo9nw4gxg8itycgntucp49i1n4',
|
||||
'xrb_1mbj7xi6yrwcuwetzd5535pdqjea5rfpsoqo9nw4gxg8itycgntucp49i1n44',
|
||||
'xrb_1mbj7xi6yrwcuwetzd5535pdqjea5rfpsoqo9nw4gxg8itycgntucp49i1n4', // bad checksum
|
||||
'zrb_1mbj7xi6yrwcuwetzd5535pdqjea5rfpsoqo9nw4gxg8itycgntucp49i1nz',
|
||||
'xrb_2mbj7xi6yrwcuwetzd5535pdqjea5rfpsoqo9nw4gxg8itycgntucp49i1nz',
|
||||
|
|
@ -44,6 +50,7 @@ const INVALID_AMOUNTS = [
|
|||
'',
|
||||
12,
|
||||
'bla',
|
||||
'0100',
|
||||
'1000000000000000000000000000000000000000',
|
||||
'-1',
|
||||
// a bit more than 2^128
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^10.0.4",
|
||||
"@types/yargs": "^11.0.0",
|
||||
"bundlesize": "^0.17.0",
|
||||
"cross-env": "^5.1.3",
|
||||
"cross-os": "^1.2.2",
|
||||
|
|
@ -42,7 +43,8 @@
|
|||
"tslint-config-prettier": "^1.12.0",
|
||||
"typedoc": "^0.11.1",
|
||||
"typedoc-plugin-internal-external": "^1.0.10",
|
||||
"typescript": "^2.8.3"
|
||||
"typescript": "^2.8.3",
|
||||
"yargs": "^11.0.0"
|
||||
},
|
||||
"files": [
|
||||
"dist/"
|
||||
|
|
@ -65,6 +67,9 @@
|
|||
"main": "dist/nanocurrency.cjs.js",
|
||||
"module": "dist/nanocurrency.esm.js",
|
||||
"types": "dist/types/index.d.ts",
|
||||
"bin": {
|
||||
"nanocurrency": "dist/bin/index.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/marvinroger/nanocurrency-js.git"
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import resolve from 'rollup-plugin-node-resolve';
|
|||
import commonjs from 'rollup-plugin-commonjs';
|
||||
import { terser } from 'rollup-plugin-terser';
|
||||
import license from 'rollup-plugin-license';
|
||||
|
||||
import pkg from './package.json';
|
||||
|
||||
const ENV = process.env.NODE_ENV;
|
||||
|
|
@ -33,6 +34,14 @@ const config = [
|
|||
],
|
||||
plugins: [resolve(), commonjs(), typescript({ useTsconfigDeclarationDir: true })],
|
||||
},
|
||||
{
|
||||
input: 'src/cli/index.ts',
|
||||
output: { file: pkg.bin.nanocurrency, format: 'cjs', banner: '#!/usr/bin/env node' },
|
||||
plugins: [resolve(), commonjs(), typescript({ useTsconfigDeclarationDir: true })],
|
||||
external(id) {
|
||||
return /^[\w-]+$/.test(id) || id === '../nanocurrency.cjs';
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
if (ENV === 'production') {
|
||||
|
|
|
|||
12
src/check.ts
12
src/check.ts
|
|
@ -36,11 +36,7 @@ export function checkNumber(candidate: any) {
|
|||
* @returns Valid
|
||||
*/
|
||||
export function checkAmount(amount: any) {
|
||||
if (!checkString(amount) || amount === '' || amount.length > 39) return false;
|
||||
|
||||
for (const char of amount) {
|
||||
if (char < '0' || char > '9') return false;
|
||||
}
|
||||
if (!checkString(amount) || !/^[1-9]{1}[0-9]{0,38}$/.test(amount)) return false;
|
||||
|
||||
const candidate = new BigNumber(amount);
|
||||
|
||||
|
|
@ -54,7 +50,7 @@ export function checkAmount(amount: any) {
|
|||
* @returns Valid
|
||||
*/
|
||||
export function checkSeed(seed: any) {
|
||||
return checkString(seed) && /[0-9a-fA-F]{64}/.test(seed);
|
||||
return checkString(seed) && /^[0-9a-fA-F]{64}$/.test(seed);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -96,7 +92,7 @@ export function checkAddress(address: any) {
|
|||
* @returns Valid
|
||||
*/
|
||||
export function checkWork(work: any) {
|
||||
return checkString(work) && /[0-9a-fA-F]{16}/.test(work);
|
||||
return checkString(work) && /^[0-9a-fA-F]{16}$/.test(work);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -106,5 +102,5 @@ export function checkWork(work: any) {
|
|||
* @returns Valid
|
||||
*/
|
||||
export function checkSignature(signature: any) {
|
||||
return checkString(signature) && /[0-9a-fA-F]{128}/.test(signature);
|
||||
return checkString(signature) && /^[0-9a-fA-F]{128}$/.test(signature);
|
||||
}
|
||||
|
|
|
|||
345
src/cli/index.ts
Normal file
345
src/cli/index.ts
Normal file
|
|
@ -0,0 +1,345 @@
|
|||
import * as yargs from 'yargs';
|
||||
|
||||
const nanocurrency = require('../nanocurrency.cjs');
|
||||
|
||||
const wrapSubcommand = (yargs: yargs.Argv) =>
|
||||
yargs
|
||||
.updateStrings({
|
||||
'Commands:': 'item:',
|
||||
})
|
||||
.demandCommand(1, 'Please specify an item')
|
||||
.help()
|
||||
.version(false)
|
||||
.wrap(null);
|
||||
|
||||
yargs
|
||||
.usage('usage: $0 <command>')
|
||||
.command('check', 'check a [seed|amount|hash|key|address|work|signature]', yargs => {
|
||||
return wrapSubcommand(
|
||||
yargs
|
||||
.usage('usage: $0 check <item>')
|
||||
.command(
|
||||
'seed',
|
||||
'check a seed',
|
||||
yargs => {
|
||||
return yargs.usage('usage: $0 check seed [options]').option('candidate', {
|
||||
demandOption: true,
|
||||
describe: 'candidate to check',
|
||||
type: 'string',
|
||||
});
|
||||
},
|
||||
argv => {
|
||||
const valid = nanocurrency.checkSeed(argv.candidate);
|
||||
console.log(valid);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
'amount',
|
||||
'check an amount',
|
||||
yargs => {
|
||||
return yargs.usage('usage: $0 check amount [options]').option('candidate', {
|
||||
demandOption: true,
|
||||
describe: 'candidate to check',
|
||||
type: 'string',
|
||||
});
|
||||
},
|
||||
argv => {
|
||||
const valid = nanocurrency.checkAmount(argv.candidate);
|
||||
console.log(valid);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
'hash',
|
||||
'check an hash',
|
||||
yargs => {
|
||||
return yargs.usage('usage: $0 check hash [options]').option('candidate', {
|
||||
demandOption: true,
|
||||
describe: 'candidate to check',
|
||||
type: 'string',
|
||||
});
|
||||
},
|
||||
argv => {
|
||||
const valid = nanocurrency.checkHash(argv.candidate);
|
||||
console.log(valid);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
'key',
|
||||
'check a public or private key',
|
||||
yargs => {
|
||||
return yargs.usage('usage: $0 check key [options]').option('candidate', {
|
||||
demandOption: true,
|
||||
describe: 'candidate to check',
|
||||
type: 'string',
|
||||
});
|
||||
},
|
||||
argv => {
|
||||
const valid = nanocurrency.checkKey(argv.candidate);
|
||||
console.log(valid);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
'address',
|
||||
'check an address',
|
||||
yargs => {
|
||||
return yargs.usage('usage: $0 check address [options]').option('candidate', {
|
||||
demandOption: true,
|
||||
describe: 'candidate to check',
|
||||
type: 'string',
|
||||
});
|
||||
},
|
||||
argv => {
|
||||
const valid = nanocurrency.checkAddress(argv.candidate);
|
||||
console.log(valid);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
'work',
|
||||
'check a work',
|
||||
yargs => {
|
||||
return yargs.usage('usage: $0 check work [options]').option('candidate', {
|
||||
demandOption: true,
|
||||
describe: 'candidate to check',
|
||||
type: 'string',
|
||||
});
|
||||
},
|
||||
argv => {
|
||||
const valid = nanocurrency.checkWork(argv.candidate);
|
||||
console.log(valid);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
'signature',
|
||||
'check a signature',
|
||||
yargs => {
|
||||
return yargs.usage('usage: $0 check signature [options]').option('candidate', {
|
||||
demandOption: true,
|
||||
describe: 'candidate to check',
|
||||
type: 'string',
|
||||
});
|
||||
},
|
||||
argv => {
|
||||
const valid = nanocurrency.checkSignature(argv.candidate);
|
||||
console.log(valid);
|
||||
}
|
||||
)
|
||||
);
|
||||
})
|
||||
.command('convert', 'convert an [amount]', yargs => {
|
||||
return wrapSubcommand(
|
||||
yargs.usage('usage: $0 convert <item>').command(
|
||||
'amount',
|
||||
'convert an amount',
|
||||
yargs => {
|
||||
return yargs
|
||||
.usage('usage: $0 convert amount [options]')
|
||||
.option('input', {
|
||||
demandOption: true,
|
||||
describe: 'input to convert',
|
||||
type: 'string',
|
||||
})
|
||||
.option('from', {
|
||||
demandOption: true,
|
||||
describe: 'source unit',
|
||||
type: 'string',
|
||||
})
|
||||
.option('to', {
|
||||
demandOption: true,
|
||||
describe: 'destination unit',
|
||||
type: 'string',
|
||||
});
|
||||
},
|
||||
async argv => {
|
||||
const converted = await nanocurrency.convert(argv.input, {
|
||||
from: argv.from,
|
||||
to: argv.to,
|
||||
});
|
||||
console.log(converted);
|
||||
}
|
||||
)
|
||||
);
|
||||
})
|
||||
.command('compute', 'compute a [work]', yargs => {
|
||||
return wrapSubcommand(
|
||||
yargs.usage('usage: $0 compute <item>').command(
|
||||
'work',
|
||||
'compute a work',
|
||||
yargs => {
|
||||
return yargs.usage('usage: $0 compute work [options]').option('hash', {
|
||||
demandOption: true,
|
||||
describe: 'block hash to compute a work for',
|
||||
type: 'string',
|
||||
});
|
||||
},
|
||||
async argv => {
|
||||
const work = await nanocurrency.computeWork(argv.hash);
|
||||
console.log(work);
|
||||
}
|
||||
)
|
||||
);
|
||||
})
|
||||
.command('sign', 'sign a [block]', yargs => {
|
||||
return wrapSubcommand(
|
||||
yargs.usage('usage: $0 sign <item>').command(
|
||||
'block',
|
||||
'sign a block',
|
||||
yargs => {
|
||||
return yargs
|
||||
.usage('usage: $0 sign block [options]')
|
||||
.option('secret', {
|
||||
demandOption: true,
|
||||
describe: 'secret key to sign the block with',
|
||||
type: 'string',
|
||||
})
|
||||
.option('hash', {
|
||||
demandOption: true,
|
||||
describe: 'hash of the block to sign',
|
||||
type: 'string',
|
||||
});
|
||||
},
|
||||
async argv => {
|
||||
const signature = await nanocurrency.signBlock({
|
||||
hash: argv.hash,
|
||||
secretKey: argv.secret,
|
||||
});
|
||||
console.log(signature);
|
||||
}
|
||||
)
|
||||
);
|
||||
})
|
||||
.command('verify', 'verify a [block]', yargs => {
|
||||
return wrapSubcommand(
|
||||
yargs.usage('usage: $0 verify <item>').command(
|
||||
'verify',
|
||||
'verify a block',
|
||||
yargs => {
|
||||
return yargs
|
||||
.usage('usage: $0 verify block [options]')
|
||||
.option('public', {
|
||||
demandOption: true,
|
||||
describe: 'public key to verify the signature against',
|
||||
type: 'string',
|
||||
})
|
||||
.option('hash', {
|
||||
demandOption: true,
|
||||
describe: 'hash of the block to verify',
|
||||
type: 'string',
|
||||
})
|
||||
.option('signature', {
|
||||
demandOption: true,
|
||||
describe: 'signature to verify',
|
||||
type: 'string',
|
||||
});
|
||||
},
|
||||
async argv => {
|
||||
const valid = await nanocurrency.verifyBlock({
|
||||
hash: argv.hash,
|
||||
publicKey: argv.public,
|
||||
signature: argv.signature,
|
||||
});
|
||||
console.log(valid);
|
||||
}
|
||||
)
|
||||
);
|
||||
})
|
||||
.command('validate', 'validate a [work]', yargs => {
|
||||
return wrapSubcommand(
|
||||
yargs.usage('usage: $0 validate <item>').command(
|
||||
'work',
|
||||
'validate a work',
|
||||
yargs => {
|
||||
return yargs
|
||||
.usage('usage: $0 validate work [options]')
|
||||
.option('hash', {
|
||||
demandOption: true,
|
||||
describe: 'hash to validate the work against',
|
||||
type: 'string',
|
||||
})
|
||||
.option('work', {
|
||||
demandOption: true,
|
||||
describe: 'work to validate',
|
||||
type: 'string',
|
||||
});
|
||||
},
|
||||
async argv => {
|
||||
const valid = await nanocurrency.validateWork({
|
||||
blockHash: argv.hash,
|
||||
work: argv.work,
|
||||
});
|
||||
console.log(valid);
|
||||
}
|
||||
)
|
||||
);
|
||||
})
|
||||
.command('generate', 'generate a [seed]', yargs => {
|
||||
return wrapSubcommand(
|
||||
yargs.usage('usage: $0 generate <item>').command('seed', 'generate a seed', {}, async () => {
|
||||
const seed = await nanocurrency.generateSeed();
|
||||
console.log(seed);
|
||||
})
|
||||
);
|
||||
})
|
||||
.command('derive', 'derive a [secret|public|address]', yargs => {
|
||||
return wrapSubcommand(
|
||||
yargs
|
||||
.usage('usage: $0 derive <item>')
|
||||
.command(
|
||||
'secret',
|
||||
'derive a secret key from a seed and an index',
|
||||
yargs => {
|
||||
return yargs
|
||||
.usage('usage: $0 derive secret [options]')
|
||||
.option('from', {
|
||||
demandOption: true,
|
||||
describe: 'seed to derive from',
|
||||
type: 'string',
|
||||
})
|
||||
.option('index', {
|
||||
demandOption: true,
|
||||
default: 0,
|
||||
describe: 'index to derive',
|
||||
type: 'number',
|
||||
});
|
||||
},
|
||||
argv => {
|
||||
const secretKey = nanocurrency.deriveSecretKey(argv.from, argv.index);
|
||||
console.log(secretKey);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
'public',
|
||||
'derive a public key from a secret key or an address',
|
||||
yargs => {
|
||||
return yargs.usage('usage: $0 derive public [options]').option('from', {
|
||||
demandOption: true,
|
||||
describe: 'secret key or address to derive from',
|
||||
type: 'string',
|
||||
});
|
||||
},
|
||||
argv => {
|
||||
const publicKey = nanocurrency.derivePublicKey(argv.from);
|
||||
console.log(publicKey);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
'address',
|
||||
'derive an address from a public key',
|
||||
yargs => {
|
||||
return yargs.usage('usage: $0 derive address [options]').option('from', {
|
||||
demandOption: true,
|
||||
describe: 'public key to derive from',
|
||||
type: 'string',
|
||||
});
|
||||
},
|
||||
argv => {
|
||||
const address = nanocurrency.deriveAddress(argv.from);
|
||||
console.log(address);
|
||||
}
|
||||
)
|
||||
);
|
||||
})
|
||||
.demandCommand(1, 'Please specify a command')
|
||||
.strict()
|
||||
.help()
|
||||
.epilogue('for more information, find the sources at http://git.io/nanocurrency-js')
|
||||
.wrap(null).argv;
|
||||
|
|
@ -70,7 +70,7 @@ export function convert(value: string, params: ConvertParams) {
|
|||
const valueNotValid = new Error('Value is not valid');
|
||||
if (!checkString) throw valueNotValid;
|
||||
if (params.from === 'hex') {
|
||||
if (!/[0-9a-fA-F]{32}/.test(value)) throw valueNotValid;
|
||||
if (!/^[0-9a-fA-F]{32}$/.test(value)) throw valueNotValid;
|
||||
} else {
|
||||
if (!checkNumber(value)) throw valueNotValid;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export interface ParseAddressResult {
|
|||
/** @hidden */
|
||||
export function parseAddress(address: any): ParseAddressResult {
|
||||
const invalid = { valid: false, publicKeyBytes: null };
|
||||
if (!checkString(address) || !/(xrb_|nano_)[13][0-9a-km-uw-z]{59}/.test(address)) {
|
||||
if (!checkString(address) || !/^(xrb_|nano_)[13][0-9a-km-uw-z]{59}$/.test(address)) {
|
||||
return invalid;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -177,6 +177,10 @@
|
|||
"@types/glob" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/yargs@^11.0.0":
|
||||
version "11.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-11.0.0.tgz#124b9ed9c65b7091cc36da59ae12cbd47d8745ea"
|
||||
|
||||
JSONStream@^1.0.4:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.2.tgz#c102371b6ec3a7cf3b847ca00c20bb0fce4c6dea"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue