wallet/http: improve validation.

This commit is contained in:
Christopher Jeffrey 2017-10-20 08:15:04 -07:00
parent 645cafe653
commit fc3b31836b
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
12 changed files with 591 additions and 323 deletions

View File

@ -181,4 +181,6 @@ HD.HD = HD;
HD.Mnemonic = Mnemonic;
HD.PrivateKey = HDPrivateKey;
HD.PublicKey = HDPublicKey;
HD.HDPrivateKey = HDPrivateKey;
HD.HDPublicKey = HDPublicKey;
HD.wordlist = wordlist;

View File

@ -1329,10 +1329,6 @@ Request.prototype.rewrite = function rewrite(url) {
return req;
};
Request.prototype.valid = function valid() {
return new Validator([this.query, this.params, this.body]);
};
Request.prototype.pipe = function pipe(dest) {
return this.req.pipe(dest);
};

View File

@ -250,7 +250,7 @@ RPC.prototype.addNode = async function addNode(args, help) {
if (help || args.length !== 2)
throw new RPCError(errs.MISC_ERROR, 'addnode "node" "add|remove|onetry"');
const valid = new Validator([args]);
const valid = new Validator(args);
const node = valid.str(0, '');
const cmd = valid.str(1, '');
@ -282,7 +282,7 @@ RPC.prototype.disconnectNode = async function disconnectNode(args, help) {
if (help || args.length !== 1)
throw new RPCError(errs.MISC_ERROR, 'disconnectnode "node"');
const valid = new Validator([args]);
const valid = new Validator(args);
const str = valid.str(0, '');
const addr = parseIP(str, this.network);
@ -299,7 +299,7 @@ RPC.prototype.getAddedNodeInfo = async function getAddedNodeInfo(args, help) {
throw new RPCError(errs.MISC_ERROR, 'getaddednodeinfo ( "node" )');
const hosts = this.pool.hosts;
const valid = new Validator([args]);
const valid = new Validator(args);
const addr = valid.str(0, '');
let target;
@ -438,7 +438,7 @@ RPC.prototype.ping = async function ping(args, help) {
};
RPC.prototype.setBan = async function setBan(args, help) {
const valid = new Validator([args]);
const valid = new Validator(args);
const str = valid.str(0, '');
const action = valid.str(1, '');
@ -533,8 +533,8 @@ RPC.prototype.getBlock = async function getBlock(args, help) {
if (help || args.length < 1 || args.length > 3)
throw new RPCError(errs.MISC_ERROR, 'getblock "hash" ( verbose )');
const valid = new Validator([args]);
const hash = valid.hash(0);
const valid = new Validator(args);
const hash = valid.rhash(0);
const verbose = valid.bool(1, true);
const details = valid.bool(2, false);
@ -570,7 +570,7 @@ RPC.prototype.getBlockByHeight = async function getBlockByHeight(args, help) {
'getblockbyheight "height" ( verbose )');
}
const valid = new Validator([args]);
const valid = new Validator(args);
const height = valid.u32(0, -1);
const verbose = valid.bool(1, true);
const details = valid.bool(2, false);
@ -605,7 +605,7 @@ RPC.prototype.getBlockHash = async function getBlockHash(args, help) {
if (help || args.length !== 1)
throw new RPCError(errs.MISC_ERROR, 'getblockhash index');
const valid = new Validator([args]);
const valid = new Validator(args);
const height = valid.u32(0);
if (height == null || height > this.chain.height)
@ -623,8 +623,8 @@ RPC.prototype.getBlockHeader = async function getBlockHeader(args, help) {
if (help || args.length < 1 || args.length > 2)
throw new RPCError(errs.MISC_ERROR, 'getblockheader "hash" ( verbose )');
const valid = new Validator([args]);
const hash = valid.hash(0);
const valid = new Validator(args);
const hash = valid.rhash(0);
const verbose = valid.bool(1, true);
if (!hash)
@ -694,8 +694,8 @@ RPC.prototype.getMempoolAncestors = async function getMempoolAncestors(args, hel
if (help || args.length < 1 || args.length > 2)
throw new RPCError(errs.MISC_ERROR, 'getmempoolancestors txid (verbose)');
const valid = new Validator([args]);
const hash = valid.hash(0);
const valid = new Validator(args);
const hash = valid.rhash(0);
const verbose = valid.bool(1, false);
if (!this.mempool)
@ -727,8 +727,8 @@ RPC.prototype.getMempoolDescendants = async function getMempoolDescendants(args,
if (help || args.length < 1 || args.length > 2)
throw new RPCError(errs.MISC_ERROR, 'getmempooldescendants txid (verbose)');
const valid = new Validator([args]);
const hash = valid.hash(0);
const valid = new Validator(args);
const hash = valid.rhash(0);
const verbose = valid.bool(1, false);
if (!this.mempool)
@ -760,8 +760,8 @@ RPC.prototype.getMempoolEntry = async function getMempoolEntry(args, help) {
if (help || args.length !== 1)
throw new RPCError(errs.MISC_ERROR, 'getmempoolentry txid');
const valid = new Validator([args]);
const hash = valid.hash(0);
const valid = new Validator(args);
const hash = valid.rhash(0);
if (!this.mempool)
throw new RPCError(errs.MISC_ERROR, 'No mempool available.');
@ -781,7 +781,7 @@ RPC.prototype.getRawMempool = async function getRawMempool(args, help) {
if (help || args.length > 1)
throw new RPCError(errs.MISC_ERROR, 'getrawmempool ( verbose )');
const valid = new Validator([args]);
const valid = new Validator(args);
const verbose = valid.bool(0, false);
if (!this.mempool)
@ -805,8 +805,8 @@ RPC.prototype.getTXOut = async function getTXOut(args, help) {
if (help || args.length < 2 || args.length > 3)
throw new RPCError(errs.MISC_ERROR, 'gettxout "txid" n ( includemempool )');
const valid = new Validator([args]);
const hash = valid.hash(0);
const valid = new Validator(args);
const hash = valid.rhash(0);
const index = valid.u32(1);
const mempool = valid.bool(2, true);
@ -848,9 +848,9 @@ RPC.prototype.getTXOutProof = async function getTXOutProof(args, help) {
'gettxoutproof ["txid",...] ( blockhash )');
}
const valid = new Validator([args]);
const valid = new Validator(args);
const txids = valid.array(0);
const hash = valid.hash(1);
const hash = valid.rhash(1);
if (this.chain.options.spv)
throw new RPCError(errs.MISC_ERROR, 'Cannot get coins in SPV mode.');
@ -861,14 +861,14 @@ RPC.prototype.getTXOutProof = async function getTXOutProof(args, help) {
if (!txids || txids.length === 0)
throw new RPCError(errs.INVALID_PARAMETER, 'Invalid TXIDs.');
const items = new Validator([txids]);
const items = new Validator(txids);
const set = new Set();
const hashes = [];
let last = null;
for (let i = 0; i < txids.length; i++) {
const hash = items.hash(i);
const hash = items.rhash(i);
if (!hash)
throw new RPCError(errs.TYPE_ERROR, 'Invalid TXID.');
@ -915,7 +915,7 @@ RPC.prototype.verifyTXOutProof = async function verifyTXOutProof(args, help) {
if (help || args.length !== 1)
throw new RPCError(errs.MISC_ERROR, 'verifytxoutproof "proof"');
const valid = new Validator([args]);
const valid = new Validator(args);
const data = valid.buf(0);
if (!data)
@ -982,7 +982,7 @@ RPC.prototype.verifyChain = async function verifyChain(args, help) {
if (help || args.length > 2)
throw new RPCError(errs.MISC_ERROR, 'verifychain ( checklevel numblocks )');
const valid = new Validator([args]);
const valid = new Validator(args);
const level = valid.u32(0);
const blocks = valid.u32(1);
@ -1115,7 +1115,7 @@ RPC.prototype.getWork = async function getWork(args, help) {
throw new RPCError(errs.MISC_ERROR, 'getwork ( "data" )');
if (args.length === 1) {
const valid = new Validator([args]);
const valid = new Validator(args);
const data = valid.buf(0);
if (!data)
@ -1133,7 +1133,7 @@ RPC.prototype.submitBlock = async function submitBlock(args, help) {
'submitblock "hexdata" ( "jsonparametersobject" )');
}
const valid = new Validator([args]);
const valid = new Validator(args);
const data = valid.buf(0);
const block = Block.fromRaw(data);
@ -1147,9 +1147,9 @@ RPC.prototype.getBlockTemplate = async function getBlockTemplate(args, help) {
'getblocktemplate ( "jsonrequestobject" )');
}
const validator = new Validator([args]);
const validator = new Validator(args);
const options = validator.obj(0, {});
const valid = new Validator([options]);
const valid = new Validator(options);
const mode = valid.str('mode', 'template');
if (mode !== 'template' && mode !== 'proposal')
@ -1487,7 +1487,7 @@ RPC.prototype.getNetworkHashPS = async function getNetworkHashPS(args, help) {
if (help || args.length > 2)
throw new RPCError(errs.MISC_ERROR, 'getnetworkhashps ( blocks height )');
const valid = new Validator([args]);
const valid = new Validator(args);
const lookup = valid.u32(0, 120);
const height = valid.u32(1);
@ -1500,8 +1500,8 @@ RPC.prototype.prioritiseTransaction = async function prioritiseTransaction(args,
'prioritisetransaction <txid> <priority delta> <fee delta>');
}
const valid = new Validator([args]);
const hash = valid.hash(0);
const valid = new Validator(args);
const hash = valid.rhash(0);
const pri = valid.i64(1);
const fee = valid.i64(2);
@ -1528,7 +1528,7 @@ RPC.prototype.verifyBlock = async function verifyBlock(args, help) {
if (help || args.length !== 1)
throw new RPCError(errs.MISC_ERROR, 'verifyblock "block-hex"');
const valid = new Validator([args]);
const valid = new Validator(args);
const data = valid.buf(0);
if (!data)
@ -1564,7 +1564,7 @@ RPC.prototype.setGenerate = async function setGenerate(args, help) {
if (help || args.length < 1 || args.length > 2)
throw new RPCError(errs.MISC_ERROR, 'setgenerate mine ( proclimit )');
const valid = new Validator([args]);
const valid = new Validator(args);
const mine = valid.bool(0, false);
const limit = valid.u32(1, 0);
@ -1590,7 +1590,7 @@ RPC.prototype.generate = async function generate(args, help) {
if (help || args.length < 1 || args.length > 2)
throw new RPCError(errs.MISC_ERROR, 'generate numblocks ( maxtries )');
const valid = new Validator([args]);
const valid = new Validator(args);
const blocks = valid.u32(0, 1);
const tries = valid.u32(1);
@ -1608,7 +1608,7 @@ RPC.prototype.generateToAddress = async function generateToAddress(args, help) {
'generatetoaddress numblocks address ( maxtries )');
}
const valid = new Validator([args]);
const valid = new Validator(args);
const blocks = valid.u32(0, 1);
const str = valid.str(1, '');
const tries = valid.u32(2);
@ -1631,7 +1631,7 @@ RPC.prototype.createRawTransaction = async function createRawTransaction(args, h
+ ' ( locktime )');
}
const valid = new Validator([args]);
const valid = new Validator(args);
const inputs = valid.array(0);
const sendTo = valid.obj(1);
const locktime = valid.u32(2);
@ -1647,8 +1647,8 @@ RPC.prototype.createRawTransaction = async function createRawTransaction(args, h
tx.locktime = locktime;
for (const obj of inputs) {
const valid = new Validator([obj]);
const hash = valid.hash('txid');
const valid = new Validator(obj);
const hash = valid.rhash('txid');
const index = valid.u32('vout');
let sequence = valid.u32('sequence', 0xffffffff);
@ -1666,7 +1666,7 @@ RPC.prototype.createRawTransaction = async function createRawTransaction(args, h
tx.inputs.push(input);
}
const sends = new Validator([sendTo]);
const sends = new Validator(sendTo);
const uniq = new Set();
for (const key of Object.keys(sendTo)) {
@ -1711,7 +1711,7 @@ RPC.prototype.decodeRawTransaction = async function decodeRawTransaction(args, h
if (help || args.length !== 1)
throw new RPCError(errs.MISC_ERROR, 'decoderawtransaction "hexstring"');
const valid = new Validator([args]);
const valid = new Validator(args);
const data = valid.buf(0);
if (!data)
@ -1726,7 +1726,7 @@ RPC.prototype.decodeScript = async function decodeScript(args, help) {
if (help || args.length !== 1)
throw new RPCError(errs.MISC_ERROR, 'decodescript "hex"');
const valid = new Validator([args]);
const valid = new Validator(args);
const data = valid.buf(0);
let script = new Script();
@ -1746,8 +1746,8 @@ RPC.prototype.getRawTransaction = async function getRawTransaction(args, help) {
if (help || args.length < 1 || args.length > 2)
throw new RPCError(errs.MISC_ERROR, 'getrawtransaction "txid" ( verbose )');
const valid = new Validator([args]);
const hash = valid.hash(0);
const valid = new Validator(args);
const hash = valid.rhash(0);
const verbose = valid.bool(1, false);
if (!hash)
@ -1780,7 +1780,7 @@ RPC.prototype.sendRawTransaction = async function sendRawTransaction(args, help)
'sendrawtransaction "hexstring" ( allowhighfees )');
}
const valid = new Validator([args]);
const valid = new Validator(args);
const data = valid.buf(0);
if (!data)
@ -1803,7 +1803,7 @@ RPC.prototype.signRawTransaction = async function signRawTransaction(args, help)
+ ' sighashtype )');
}
const valid = new Validator([args]);
const valid = new Validator(args);
const data = valid.buf(0);
const prevout = valid.array(1);
const secrets = valid.array(2);
@ -1822,7 +1822,7 @@ RPC.prototype.signRawTransaction = async function signRawTransaction(args, help)
const keys = [];
if (secrets) {
const valid = new Validator([secrets]);
const valid = new Validator(secrets);
for (let i = 0; i < secrets.length; i++) {
const secret = valid.str(i, '');
const key = parseSecret(secret, this.network);
@ -1833,8 +1833,8 @@ RPC.prototype.signRawTransaction = async function signRawTransaction(args, help)
if (prevout) {
for (const prev of prevout) {
const valid = new Validator([prev]);
const hash = valid.hash('txid');
const valid = new Validator(prev);
const hash = valid.rhash('txid');
const index = valid.u32('vout');
const scriptRaw = valid.buf('scriptPubKey');
const value = valid.ufixed('amount', 8);
@ -1914,7 +1914,7 @@ RPC.prototype.createMultisig = async function createMultisig(args, help) {
if (help || args.length < 2 || args.length > 2)
throw new RPCError(errs.MISC_ERROR, 'createmultisig nrequired ["key",...]');
const valid = new Validator([args]);
const valid = new Validator(args);
const keys = valid.array(1, []);
const m = valid.u32(0, 0);
const n = keys.length;
@ -1922,7 +1922,7 @@ RPC.prototype.createMultisig = async function createMultisig(args, help) {
if (m < 1 || n < m || n > 16)
throw new RPCError(errs.INVALID_PARAMETER, 'Invalid m and n values.');
const items = new Validator([keys]);
const items = new Validator(keys);
for (let i = 0; i < keys.length; i++) {
const key = items.buf(i);
@ -1953,7 +1953,7 @@ RPC.prototype.createWitnessAddress = async function createWitnessAddress(args, h
if (help || args.length !== 1)
throw new RPCError(errs.MISC_ERROR, 'createwitnessaddress "script"');
const valid = new Validator([args]);
const valid = new Validator(args);
const raw = valid.buf(0);
if (!raw)
@ -1973,7 +1973,7 @@ RPC.prototype.validateAddress = async function validateAddress(args, help) {
if (help || args.length !== 1)
throw new RPCError(errs.MISC_ERROR, 'validateaddress "bitcoinaddress"');
const valid = new Validator([args]);
const valid = new Validator(args);
const str = valid.str(0, '');
let addr;
@ -2002,7 +2002,7 @@ RPC.prototype.verifyMessage = async function verifyMessage(args, help) {
'verifymessage "bitcoinaddress" "signature" "message"');
}
const valid = new Validator([args]);
const valid = new Validator(args);
const b58 = valid.str(0, '');
const sig = valid.buf(1, null, 'base64');
const str = valid.str(2);
@ -2028,7 +2028,7 @@ RPC.prototype.signMessageWithPrivkey = async function signMessageWithPrivkey(arg
'signmessagewithprivkey "privkey" "message"');
}
const valid = new Validator([args]);
const valid = new Validator(args);
const wif = valid.str(0, '');
const str = valid.str(1, '');
@ -2044,7 +2044,7 @@ RPC.prototype.estimateFee = async function estimateFee(args, help) {
if (help || args.length !== 1)
throw new RPCError(errs.MISC_ERROR, 'estimatefee nblocks');
const valid = new Validator([args]);
const valid = new Validator(args);
const blocks = valid.u32(0, 1);
if (!this.fees)
@ -2062,7 +2062,7 @@ RPC.prototype.estimatePriority = async function estimatePriority(args, help) {
if (help || args.length !== 1)
throw new RPCError(errs.MISC_ERROR, 'estimatepriority nblocks');
const valid = new Validator([args]);
const valid = new Validator(args);
const blocks = valid.u32(0, 1);
if (!this.fees)
@ -2075,7 +2075,7 @@ RPC.prototype.estimateSmartFee = async function estimateSmartFee(args, help) {
if (help || args.length !== 1)
throw new RPCError(errs.MISC_ERROR, 'estimatesmartfee nblocks');
const valid = new Validator([args]);
const valid = new Validator(args);
const blocks = valid.u32(0, 1);
if (!this.fees)
@ -2098,7 +2098,7 @@ RPC.prototype.estimateSmartPriority = async function estimateSmartPriority(args,
if (help || args.length !== 1)
throw new RPCError(errs.MISC_ERROR, 'estimatesmartpriority nblocks');
const valid = new Validator([args]);
const valid = new Validator(args);
const blocks = valid.u32(0, 1);
if (!this.fees)
@ -2116,8 +2116,8 @@ RPC.prototype.invalidateBlock = async function invalidateBlock(args, help) {
if (help || args.length !== 1)
throw new RPCError(errs.MISC_ERROR, 'invalidateblock "hash"');
const valid = new Validator([args]);
const hash = valid.hash(0);
const valid = new Validator(args);
const hash = valid.rhash(0);
if (!hash)
throw new RPCError(errs.TYPE_ERROR, 'Invalid block hash.');
@ -2131,8 +2131,8 @@ RPC.prototype.reconsiderBlock = async function reconsiderBlock(args, help) {
if (help || args.length !== 1)
throw new RPCError(errs.MISC_ERROR, 'reconsiderblock "hash"');
const valid = new Validator([args]);
const hash = valid.hash(0);
const valid = new Validator(args);
const hash = valid.rhash(0);
if (!hash)
throw new RPCError(errs.TYPE_ERROR, 'Invalid block hash.');
@ -2146,7 +2146,7 @@ RPC.prototype.setMockTime = async function setMockTime(args, help) {
if (help || args.length !== 1)
throw new RPCError(errs.MISC_ERROR, 'setmocktime timestamp');
const valid = new Validator([args]);
const valid = new Validator(args);
const time = valid.u32(0);
if (time == null)
@ -2172,7 +2172,7 @@ RPC.prototype.setLogLevel = async function setLogLevel(args, help) {
if (help || args.length !== 1)
throw new RPCError(errs.MISC_ERROR, 'setloglevel "level"');
const valid = new Validator([args]);
const valid = new Validator(args);
const level = valid.str(0, '');
this.logger.setLevel(level);

View File

@ -141,7 +141,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// UTXO by address
this.get('/coin/address/:address', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const address = valid.str('address');
enforce(address, 'Address is required.');
@ -158,8 +158,8 @@ HTTPServer.prototype.initRouter = function initRouter() {
// UTXO by id
this.get('/coin/:hash/:index', async (req, res) => {
const valid = req.valid();
const hash = valid.hash('hash');
const valid = Validator.fromRequest(req);
const hash = valid.rhash('hash');
const index = valid.u32('index');
enforce(hash, 'Hash is required.');
@ -178,7 +178,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Bulk read UTXOs
this.post('/coin/address', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const address = valid.array('addresses');
enforce(address, 'Address is required.');
@ -195,8 +195,8 @@ HTTPServer.prototype.initRouter = function initRouter() {
// TX by hash
this.get('/tx/:hash', async (req, res) => {
const valid = req.valid();
const hash = valid.hash('hash');
const valid = Validator.fromRequest(req);
const hash = valid.rhash('hash');
enforce(hash, 'Hash is required.');
enforce(!this.chain.options.spv, 'Cannot get TX in SPV mode.');
@ -215,7 +215,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// TX by address
this.get('/tx/address/:address', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const address = valid.str('address');
enforce(address, 'Address is required.');
@ -234,7 +234,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Bulk read TXs
this.post('/tx/address', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const address = valid.array('addresses');
enforce(address, 'Address is required.');
@ -253,17 +253,12 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Block by hash/height
this.get('/block/:block', async (req, res) => {
const valid = req.valid();
let hash = valid.get('block');
const valid = Validator.fromRequest(req);
const hash = valid.uintrhash('block');
enforce(typeof hash === 'string', 'Hash or height required.');
enforce(hash != null, 'Hash or height required.');
enforce(!this.chain.options.spv, 'Cannot get block in SPV mode.');
if (hash.length === 64)
hash = util.revHex(hash);
else
hash = parseInt(hash, 10);
const block = await this.chain.getBlock(hash);
if (!block) {
@ -298,7 +293,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Broadcast TX
this.post('/broadcast', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const raw = valid.buf('tx');
enforce(raw, 'TX is required.');
@ -312,7 +307,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Estimate fee
this.get('/fee', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const blocks = valid.u32('blocks');
if (!this.fees) {
@ -327,7 +322,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Reset chain
this.post('/reset', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const height = valid.u32('height');
enforce(height != null, 'Height is required.');
@ -364,7 +359,7 @@ HTTPServer.prototype.handleSocket = function handleSocket(socket) {
throw new Error('Already authed.');
if (!this.options.noAuth) {
const valid = new Validator([args]);
const valid = new Validator(args);
const key = valid.str(0, '');
if (key.length > 255)
@ -419,7 +414,7 @@ HTTPServer.prototype.handleAuth = function handleAuth(socket) {
});
socket.hook('set filter', (args) => {
const valid = new Validator([args]);
const valid = new Validator(args);
const data = valid.buf(0);
if (!data)
@ -435,8 +430,8 @@ HTTPServer.prototype.handleAuth = function handleAuth(socket) {
});
socket.hook('get entry', async (args) => {
const valid = new Validator([args]);
const block = valid.numhash(0);
const valid = new Validator(args);
const block = valid.uintrhash(0);
if (block == null)
throw new Error('Invalid parameter.');
@ -453,7 +448,7 @@ HTTPServer.prototype.handleAuth = function handleAuth(socket) {
});
socket.hook('get hashes', async (args) => {
const valid = new Validator([args]);
const valid = new Validator(args);
const start = valid.i32(0, -1);
const end = valid.i32(1, -1);
@ -461,7 +456,7 @@ HTTPServer.prototype.handleAuth = function handleAuth(socket) {
});
socket.hook('add filter', (args) => {
const valid = new Validator([args]);
const valid = new Validator(args);
const chunks = valid.array(0);
if (!chunks)
@ -470,7 +465,7 @@ HTTPServer.prototype.handleAuth = function handleAuth(socket) {
if (!socket.filter)
throw new Error('No filter set.');
const items = new Validator([chunks]);
const items = new Validator(chunks);
for (let i = 0; i < chunks.length; i++) {
const data = items.buf(i);
@ -493,7 +488,7 @@ HTTPServer.prototype.handleAuth = function handleAuth(socket) {
});
socket.hook('estimate fee', (args) => {
const valid = new Validator([args]);
const valid = new Validator(args);
const blocks = valid.u32(0);
if (!this.fees)
@ -503,7 +498,7 @@ HTTPServer.prototype.handleAuth = function handleAuth(socket) {
});
socket.hook('send', (args) => {
const valid = new Validator([args]);
const valid = new Validator(args);
const data = valid.buf(0);
if (!data)
@ -517,8 +512,8 @@ HTTPServer.prototype.handleAuth = function handleAuth(socket) {
});
socket.hook('rescan', (args) => {
const valid = new Validator([args]);
const start = valid.numhash(0);
const valid = new Validator(args);
const start = valid.uintrhash(0);
if (start == null)
throw new Error('Invalid parameter.');

View File

@ -285,7 +285,7 @@ Config.prototype.str = function str(key, fallback) {
*/
Config.prototype.int = function int(key, fallback) {
let value = this.get(key);
const value = this.get(key);
if (fallback === undefined)
fallback = null;
@ -306,12 +306,12 @@ Config.prototype.int = function int(key, fallback) {
if (!/^\-?\d+$/.test(value))
throw new Error(`${fmt(key)} must be an int.`);
value = parseInt(value, 10);
const num = parseInt(value, 10);
if (!Number.isSafeInteger(value))
if (!Number.isSafeInteger(num))
throw new Error(`${fmt(key)} must be an int.`);
return value;
return num;
};
/**
@ -344,7 +344,7 @@ Config.prototype.uint = function uint(key, fallback) {
*/
Config.prototype.float = function float(key, fallback) {
let value = this.get(key);
const value = this.get(key);
if (fallback === undefined)
fallback = null;
@ -368,12 +368,12 @@ Config.prototype.float = function float(key, fallback) {
if (!/\d/.test(value))
throw new Error(`${fmt(key)} must be a float.`);
value = parseFloat(value);
const num = parseFloat(value);
if (!isFinite(value))
if (!isFinite(num))
throw new Error(`${fmt(key)} must be a float.`);
return value;
return num;
};
/**
@ -569,7 +569,7 @@ Config.prototype.obj = function obj(key, fallback) {
if (value === null)
return fallback;
if (typeof value !== 'object')
if (typeof value !== 'object' || Array.isArray(value))
throw new Error(`${fmt(key)} must be an object.`);
return value;
@ -613,6 +613,9 @@ Config.prototype.path = function path(key, fallback) {
if (value === null)
return fallback;
if (value.length === 0)
return fallback;
switch (value[0]) {
case '~': // home dir
value = Path.join(HOME, value.substring(1));

View File

@ -27,16 +27,16 @@ const bech32 = require('../utils/bech32');
* @property {Number} version
*/
function Address(options) {
function Address(options, network) {
if (!(this instanceof Address))
return new Address(options);
return new Address(options, network);
this.type = Address.types.PUBKEYHASH;
this.version = -1;
this.hash = encoding.ZERO_HASH160;
if (options)
this.fromOptions(options);
this.fromOptions(options, network);
}
/**
@ -63,9 +63,9 @@ Address.typesByVal = util.reverse(Address.types);
* @param {Object} options
*/
Address.prototype.fromOptions = function fromOptions(options) {
Address.prototype.fromOptions = function fromOptions(options, network) {
if (typeof options === 'string')
return this.fromString(options);
return this.fromString(options, network);
return this.fromHash(options.hash, options.type, options.version);
};
@ -76,8 +76,8 @@ Address.prototype.fromOptions = function fromOptions(options) {
* @returns {Address}
*/
Address.fromOptions = function fromOptions(options) {
return new Address().fromOptions(options);
Address.fromOptions = function fromOptions(options, network) {
return new Address().fromOptions(options, network);
};
/**

View File

@ -10,6 +10,7 @@
* @module utils/base32
*/
const assert = require('assert');
const base32 = 'abcdefghijklmnopqrstuvwxyz234567';
const padding = [0, 6, 4, 3, 1];
const unbase32 = {};
@ -24,6 +25,8 @@ for (let i = 0; i < base32.length; i++)
*/
exports.encode = function encode(data) {
assert(Buffer.isBuffer(data));
let str = '';
let mode = 0;
let left = 0;
@ -77,6 +80,8 @@ exports.encode = function encode(data) {
*/
exports.decode = function decode(str) {
assert(typeof str === 'string');
const data = Buffer.allocUnsafe(str.length * 5 / 8 | 0);
let mode = 0;
let left = 0;

View File

@ -36,6 +36,8 @@ for (let i = 0; i < base58.length; i++)
*/
exports.encode = function encode(data) {
assert(Buffer.isBuffer(data));
let zeroes = 0;
let i = 0;
@ -93,6 +95,8 @@ if (native)
*/
exports.decode = function decode(str) {
assert(typeof str === 'string');
let zeroes = 0;
let i = 0;

View File

@ -29,6 +29,7 @@
'use strict';
const assert = require('assert');
const native = require('../native').binding;
/**
@ -261,6 +262,10 @@ function convert(data, output, frombits, tobits, pad, off) {
*/
function encode(hrp, version, hash) {
assert(typeof hrp === 'string');
assert((version & 0xff) === version);
assert(Buffer.isBuffer(hash));
const output = POOL65;
if (version < 0 || version > 16)
@ -284,6 +289,8 @@ if (native)
*/
function decode(str) {
assert(typeof str === 'string');
const [hrp, data] = deserialize(str);
if (data.length === 0 || data.length > 65)

View File

@ -13,32 +13,53 @@ const util = require('../utils/util');
* Validator
* @alias module:utils.Validator
* @constructor
* @param {Object} options
* @param {Object} map
* @param {Boolean} [loose=false]
*/
function Validator(data) {
function Validator(map, loose) {
if (!(this instanceof Validator))
return new Validator(data);
return new Validator(map, loose);
this.data = [];
if (!map || typeof map !== 'object')
throw new ValidationError('map', 'object');
if (data)
this.init(data);
this.map = map;
this.loose = loose || false;
}
/**
* Initialize the validator.
* @private
* @param {Object} data
* Create a multi validator.
* @param {Object[]} maps
* @param {Boolean} [loose=false]
* @returns {MultiValidator}
*/
Validator.prototype.init = function init(data) {
assert(data && typeof data === 'object');
Validator.multi = function multi(maps, loose) {
return new MultiValidator(maps, loose);
};
if (!Array.isArray(data))
data = [data];
/**
* Create a multi validator from an http request.
* @param {Object} req
* @returns {MultiValidator}
*/
this.data = data;
Validator.fromRequest = function fromRequest(req) {
const query = new Validator(req.query, true);
const params = new Validator(req.params, true);
const body = new Validator(req.body, false);
return new MultiValidator([query, params, body]);
};
/**
* Create a child validator.
* @param {String} key
* @returns {Validator}
*/
Validator.prototype.child = function child(key) {
return new Validator(this.get(key));
};
/**
@ -48,16 +69,7 @@ Validator.prototype.init = function init(data) {
*/
Validator.prototype.has = function has(key) {
assert(typeof key === 'string' || typeof key === 'number',
'Key must be a string or number.');
for (const map of this.data) {
const value = map[key];
if (value != null)
return true;
}
return false;
return this.get(key) != null;
};
/**
@ -84,15 +96,10 @@ Validator.prototype.get = function get(key, fallback) {
assert(typeof key === 'string' || typeof key === 'number',
'Key must be a string or number.');
for (const map of this.data) {
if (!map || typeof map !== 'object')
throw new ValidationError('data', 'object');
const value = this.map[key];
const value = map[key];
if (value != null)
return value;
}
if (value != null)
return value;
return fallback;
};
@ -142,7 +149,7 @@ Validator.prototype.str = function str(key, fallback) {
*/
Validator.prototype.int = function int(key, fallback) {
let value = this.get(key);
const value = this.get(key);
if (fallback === undefined)
fallback = null;
@ -160,15 +167,18 @@ Validator.prototype.int = function int(key, fallback) {
return value;
}
if (!this.loose)
throw new ValidationError(key, 'int');
if (!/^\-?\d+$/.test(value))
throw new ValidationError(key, 'int');
value = parseInt(value, 10);
const num = parseInt(value, 10);
if (!Number.isSafeInteger(value))
if (!Number.isSafeInteger(num))
throw new ValidationError(key, 'int');
return value;
return num;
};
/**
@ -201,7 +211,7 @@ Validator.prototype.uint = function uint(key, fallback) {
*/
Validator.prototype.float = function float(key, fallback) {
let value = this.get(key);
const value = this.get(key);
if (fallback === undefined)
fallback = null;
@ -219,18 +229,21 @@ Validator.prototype.float = function float(key, fallback) {
return value;
}
if (!this.loose)
throw new ValidationError(key, 'float');
if (!/^\-?\d*(?:\.\d*)?$/.test(value))
throw new ValidationError(key, 'float');
if (!/\d/.test(value))
throw new ValidationError(key, 'float');
value = parseFloat(value);
const num = parseFloat(value);
if (!isFinite(value))
if (!isFinite(num))
throw new ValidationError(key, 'float');
return value;
return num;
};
/**
@ -482,6 +495,68 @@ Validator.prototype.hash = function hash(key, fallback) {
return value.toString('hex');
}
if (value.length !== 64)
throw new ValidationError(key, 'hex string');
if (!/^[0-9a-f]+$/i.test(value))
throw new ValidationError(key, 'hex string');
return value.toLowerCase();
};
/**
* Get a value (as a number or hash).
* @param {String} key
* @param {Object?} fallback
* @returns {Number|Hash|null}
*/
Validator.prototype.uinthash = function uinthash(key, fallback) {
const value = this.get(key);
if (fallback == null)
fallback = null;
if (value == null)
return fallback;
if (Buffer.isBuffer(value))
return this.hash(key, fallback);
if (typeof value === 'string') {
if (!this.loose || value.length === 64)
return this.hash(key, fallback);
}
return this.uint(key, fallback);
};
/**
* Get a value (as a reverse hash).
* @param {String} key
* @param {Object?} fallback
* @returns {Hash|null}
*/
Validator.prototype.rhash = function rhash(key, fallback) {
const value = this.get(key);
if (fallback === undefined)
fallback = null;
if (value === null)
return fallback;
if (typeof value !== 'string') {
if (!Buffer.isBuffer(value))
throw new ValidationError(key, 'hash');
if (value.length !== 32)
throw new ValidationError(key, 'hash');
return value.toString('hex');
}
if (value.length !== 64)
throw new ValidationError(key, 'hex string');
@ -493,7 +568,7 @@ Validator.prototype.hash = function hash(key, fallback) {
for (let i = 0; i < value.length; i += 2)
out = value.slice(i, i + 2) + out;
return out;
return out.toLowerCase();
};
/**
@ -503,9 +578,23 @@ Validator.prototype.hash = function hash(key, fallback) {
* @returns {Number|Hash|null}
*/
Validator.prototype.numhash = function numhash(key, fallback) {
if (this.typeOf(key) === 'string')
return this.hash(key, fallback);
Validator.prototype.uintrhash = function uintrhash(key, fallback) {
const value = this.get(key);
if (fallback == null)
fallback = null;
if (value == null)
return fallback;
if (Buffer.isBuffer(value))
return this.rhash(key, fallback);
if (typeof value === 'string') {
if (!this.loose || value.length === 64)
return this.rhash(key, fallback);
}
return this.uint(key, fallback);
};
@ -540,6 +629,9 @@ Validator.prototype.bool = function bool(key, fallback) {
return value;
}
if (!this.loose)
throw new ValidationError(key, 'hash');
if (value === 'true' || value === '1')
return true;
@ -605,6 +697,9 @@ Validator.prototype.array = function array(key, fallback) {
return value;
}
if (!this.loose)
throw new ValidationError(key, 'hash');
const parts = value.trim().split(/\s*,\s*/);
const result = [];
@ -634,7 +729,7 @@ Validator.prototype.obj = function obj(key, fallback) {
if (value === null)
return fallback;
if (typeof value !== 'object')
if (typeof value !== 'object' || Array.isArray(value))
throw new ValidationError(key, 'object');
return value;
@ -662,6 +757,178 @@ Validator.prototype.func = function func(key, fallback) {
return value;
};
/*
* Constants
*/
const SENTINEL = new Validator(Object.create(null));
/**
* MultiValidator
* @alias module:utils.MultiValidator
* @constructor
* @extends Validator
* @param {Object[]} maps
* @param {Boolean} [loose=false]
*/
function MultiValidator(maps, loose) {
if (!(this instanceof MultiValidator))
return new MultiValidator(maps, loose);
this.maps = [];
this.init(maps, loose);
}
/**
* Initialize the validator.
* @private
* @param {Object[]} maps
* @param {Boolean} [loose=false]
*/
MultiValidator.prototype.init = function init(maps, loose) {
assert(Array.isArray(maps));
assert(maps.length > 0);
for (const map of maps) {
if (!(map instanceof Validator)) {
assert(map && typeof map === 'object');
this.maps.push(new Validator(map, loose));
continue;
}
this.maps.push(map);
}
};
/**
* Get a validator.
* @private
* @param {String} key
* @returns {Validator}
*/
MultiValidator.prototype.find = function find(key) {
for (const map of this.maps) {
if (map.has(key))
return map;
}
return SENTINEL;
};
MultiValidator.prototype.child = function child(key) {
return this.find(key).child(key);
};
MultiValidator.prototype.has = function has(key) {
return this.find(key).has(key);
};
MultiValidator.prototype.get = function get(key, fallback) {
return this.find(key).get(key, fallback);
};
MultiValidator.prototype.typeOf = function typeOf(key) {
return this.find(key).typeOf(key);
};
MultiValidator.prototype.str = function str(key, fallback) {
return this.find(key).str(key, fallback);
};
MultiValidator.prototype.int = function int(key, fallback) {
return this.find(key).int(key, fallback);
};
MultiValidator.prototype.uint = function uint(key, fallback) {
return this.find(key).uint(key, fallback);
};
MultiValidator.prototype.float = function float(key, fallback) {
return this.find(key).float(key, fallback);
};
MultiValidator.prototype.ufloat = function ufloat(key, fallback) {
return this.find(key).ufloat(key, fallback);
};
MultiValidator.prototype.fixed = function fixed(key, exp, fallback) {
return this.find(key).fixed(key, exp, fallback);
};
MultiValidator.prototype.ufixed = function ufixed(key, exp, fallback) {
return this.find(key).ufixed(key, exp, fallback);
};
MultiValidator.prototype.i8 = function i8(key, fallback) {
return this.find(key).i8(key, fallback);
};
MultiValidator.prototype.i16 = function i16(key, fallback) {
return this.find(key).i16(key, fallback);
};
MultiValidator.prototype.i32 = function i32(key, fallback) {
return this.find(key).i32(key, fallback);
};
MultiValidator.prototype.i64 = function i64(key, fallback) {
return this.find(key).i64(key, fallback);
};
MultiValidator.prototype.u8 = function u8(key, fallback) {
return this.find(key).u8(key, fallback);
};
MultiValidator.prototype.u16 = function u16(key, fallback) {
return this.find(key).u16(key, fallback);
};
MultiValidator.prototype.u32 = function u32(key, fallback) {
return this.find(key).u32(key, fallback);
};
MultiValidator.prototype.u64 = function u64(key, fallback) {
return this.find(key).u64(key, fallback);
};
MultiValidator.prototype.hash = function hash(key, fallback) {
return this.find(key).hash(key, fallback);
};
MultiValidator.prototype.uinthash = function uinthash(key, fallback) {
return this.find(key).uinthash(key, fallback);
};
MultiValidator.prototype.rhash = function rhash(key, fallback) {
return this.find(key).rhash(key, fallback);
};
MultiValidator.prototype.uintrhash = function uintrhash(key, fallback) {
return this.find(key).uintrhash(key, fallback);
};
MultiValidator.prototype.bool = function bool(key, fallback) {
return this.find(key).bool(key, fallback);
};
MultiValidator.prototype.buf = function buf(key, fallback, enc) {
return this.find(key).buf(key, fallback, enc);
};
MultiValidator.prototype.array = function array(key, fallback) {
return this.find(key).array(key, fallback);
};
MultiValidator.prototype.obj = function obj(key, fallback) {
return this.find(key).obj(key, fallback);
};
MultiValidator.prototype.func = function func(key, fallback) {
return this.find(key).func(key, fallback);
};
/*
* Helpers
*/

View File

@ -22,6 +22,9 @@ const Network = require('../protocol/network');
const Validator = require('../utils/validator');
const Address = require('../primitives/address');
const KeyRing = require('../primitives/keyring');
const Mnemonic = require('../hd/mnemonic');
const HDPrivateKey = require('../hd/private');
const HDPublicKey = require('../hd/public');
const common = require('./common');
/**
@ -109,7 +112,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
this.use(this.jsonRPC(this.rpc));
this.hook(async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
if (req.path.length === 0)
return;
@ -157,7 +160,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Rescan
this.post('/_admin/rescan', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const height = valid.u32('height');
res.send(200, { success: true });
@ -174,7 +177,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Backup WalletDB
this.post('/_admin/backup', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const path = valid.str('path');
enforce(path, 'Path is required.');
@ -201,31 +204,22 @@ HTTPServer.prototype.initRouter = function initRouter() {
res.send(200, req.wallet.master.toJSON(true));
});
// Create wallet (compat)
this.post('/', async (req, res) => {
const valid = req.valid();
const wallet = await this.wdb.create({
id: valid.str('id'),
type: valid.str('type'),
m: valid.u32('m'),
n: valid.u32('n'),
passphrase: valid.str('passphrase'),
master: valid.str('master'),
mnemonic: valid.str('mnemonic'),
witness: valid.bool('witness'),
accountKey: valid.str('accountKey'),
watchOnly: valid.bool('watchOnly')
});
const balance = await wallet.getBalance();
res.send(200, wallet.toJSON(false, balance));
});
// Create wallet
this.put('/:id', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
let master = valid.str('master');
let mnemonic = valid.str('mnemonic');
let accountKey = valid.str('accountKey');
if (master)
master = HDPrivateKey.fromBase58(master, this.network);
if (mnemonic)
mnemonic = Mnemonic.fromPhrase(mnemonic);
if (accountKey)
accountKey = HDPublicKey.fromBase58(accountKey, this.network);
const wallet = await this.wdb.create({
id: valid.str('id'),
@ -233,10 +227,10 @@ HTTPServer.prototype.initRouter = function initRouter() {
m: valid.u32('m'),
n: valid.u32('n'),
passphrase: valid.str('passphrase'),
master: valid.str('master'),
mnemonic: valid.str('mnemonic'),
master: master,
mnemonic: mnemonic,
witness: valid.bool('witness'),
accountKey: valid.str('accountKey'),
accountKey: accountKey,
watchOnly: valid.bool('watchOnly')
});
@ -253,7 +247,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Get account
this.get('/:id/account/:account', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const acct = valid.str('account');
const account = await req.wallet.getAccount(acct);
@ -267,33 +261,16 @@ HTTPServer.prototype.initRouter = function initRouter() {
res.send(200, account.toJSON(balance));
});
// Create account (compat)
this.post('/:id/account', async (req, res) => {
const valid = req.valid();
const passphrase = valid.str('passphrase');
const options = {
name: valid.str(['account', 'name']),
witness: valid.bool('witness'),
watchOnly: valid.bool('watchOnly'),
type: valid.str('type'),
m: valid.u32('m'),
n: valid.u32('n'),
accountKey: valid.str('accountKey'),
lookahead: valid.u32('lookahead')
};
const account = await req.wallet.createAccount(options, passphrase);
const balance = await req.wallet.getBalance(account.accountIndex);
res.send(200, account.toJSON(balance));
});
// Create account
this.put('/:id/account/:account', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const passphrase = valid.str('passphrase');
let accountKey = valid.get('accountKey');
if (accountKey)
accountKey = HDPublicKey.fromBase58(accountKey, this.network);
const options = {
name: valid.str('account'),
witness: valid.bool('witness'),
@ -301,7 +278,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
type: valid.str('type'),
m: valid.u32('m'),
n: valid.u32('n'),
accountKey: valid.str('accountKey'),
accountKey: accountKey,
lookahead: valid.u32('lookahead')
};
@ -313,7 +290,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Change passphrase
this.post('/:id/passphrase', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const passphrase = valid.str('passphrase');
const old = valid.str('old');
@ -326,7 +303,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Unlock wallet
this.post('/:id/unlock', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const passphrase = valid.str('passphrase');
const timeout = valid.u32('timeout');
@ -345,7 +322,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Import key
this.post('/:id/import', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const acct = valid.str('account');
const passphrase = valid.str('passphrase');
const pub = valid.buf('publicKey');
@ -353,7 +330,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
const b58 = valid.str('address');
if (pub) {
const key = KeyRing.fromPublic(pub, this.network);
const key = KeyRing.fromPublic(pub);
await req.wallet.importKey(acct, key);
res.send(200, { success: true });
return;
@ -378,7 +355,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Generate new token
this.post('/:id/retoken', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const passphrase = valid.str('passphrase');
const token = await req.wallet.retoken(passphrase);
@ -389,7 +366,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Send TX
this.post('/:id/send', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const passphrase = valid.str('passphrase');
const outputs = valid.array('outputs', []);
@ -406,17 +383,20 @@ HTTPServer.prototype.initRouter = function initRouter() {
};
for (const output of outputs) {
const valid = new Validator([output]);
const raw = valid.buf('script');
const valid = new Validator(output);
let script = null;
let addr = valid.str('address');
let script = valid.buf('script');
if (raw)
script = Script.fromRaw(raw);
if (addr)
addr = Address.fromString(addr, this.network);
if (script)
script = Script.fromRaw(script);
options.outputs.push({
address: addr,
script: script,
address: valid.str('address'),
value: valid.u64('value')
});
}
@ -430,7 +410,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Create TX
this.post('/:id/create', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const passphrase = valid.str('passphrase');
const outputs = valid.array('outputs', []);
@ -446,17 +426,20 @@ HTTPServer.prototype.initRouter = function initRouter() {
};
for (const output of outputs) {
const valid = new Validator([output]);
const raw = valid.buf('script');
const valid = new Validator(output);
let script = null;
let addr = valid.str('address');
let script = valid.buf('script');
if (raw)
script = Script.fromRaw(raw);
if (addr)
addr = Address.fromString(addr, this.network);
if (script)
script = Script.fromRaw(script);
options.outputs.push({
address: addr,
script: script,
address: valid.str('address'),
value: valid.u64('value')
});
}
@ -470,7 +453,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Sign TX
this.post('/:id/sign', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const passphrase = valid.str('passphrase');
const raw = valid.buf('tx');
@ -486,7 +469,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Zap Wallet TXs
this.post('/:id/zap', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const acct = valid.str('account');
const age = valid.u32('age');
@ -499,8 +482,8 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Abandon Wallet TX
this.del('/:id/tx/:hash', async (req, res) => {
const valid = req.valid();
const hash = valid.hash('hash');
const valid = Validator.fromRequest(req);
const hash = valid.rhash('hash');
enforce(hash, 'Hash is required.');
@ -517,7 +500,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Get Block Record
this.get('/:id/block/:height', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const height = valid.u32('height');
enforce(height != null, 'Height is required.');
@ -534,11 +517,13 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Add key
this.put('/:id/shared-key', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const acct = valid.str('account');
const key = valid.str('accountKey');
const b58 = valid.str('accountKey');
enforce(key, 'Key is required.');
enforce(b58, 'Key is required.');
const key = HDPublicKey.fromBase58(b58, this.network);
await req.wallet.addSharedKey(acct, key);
@ -547,11 +532,13 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Remove key
this.del('/:id/shared-key', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const acct = valid.str('account');
const key = valid.str('accountKey');
const b58 = valid.str('accountKey');
enforce(key, 'Key is required.');
enforce(b58, 'Key is required.');
const key = HDPublicKey.fromBase58(b58, this.network);
await req.wallet.removeSharedKey(acct, key);
@ -560,12 +547,13 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Get key by address
this.get('/:id/key/:address', async (req, res) => {
const valid = req.valid();
const address = valid.str('address');
const valid = Validator.fromRequest(req);
const b58 = valid.str('address');
enforce(address, 'Address is required.');
enforce(b58, 'Address is required.');
const key = await req.wallet.getKey(address);
const addr = Address.fromString(b58, this.network);
const key = await req.wallet.getKey(addr);
if (!key) {
res.send(404);
@ -577,13 +565,14 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Get private key
this.get('/:id/wif/:address', async (req, res) => {
const valid = req.valid();
const address = valid.str('address');
const valid = Validator.fromRequest(req);
const b58 = valid.str('address');
const passphrase = valid.str('passphrase');
enforce(address, 'Address is required.');
enforce(b58, 'Address is required.');
const key = await req.wallet.getPrivateKey(address, passphrase);
const addr = Address.fromString(b58, this.network);
const key = await req.wallet.getPrivateKey(addr, passphrase);
if (!key) {
res.send(404);
@ -595,34 +584,34 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Create address
this.post('/:id/address', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const acct = valid.str('account');
const address = await req.wallet.createReceive(acct);
const addr = await req.wallet.createReceive(acct);
res.send(200, address.toJSON(this.network));
res.send(200, addr.toJSON(this.network));
});
// Create change address
this.post('/:id/change', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const acct = valid.str('account');
const address = await req.wallet.createChange(acct);
const addr = await req.wallet.createChange(acct);
res.send(200, address.toJSON(this.network));
res.send(200, addr.toJSON(this.network));
});
// Create nested address
this.post('/:id/nested', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const acct = valid.str('account');
const address = await req.wallet.createNested(acct);
const addr = await req.wallet.createNested(acct);
res.send(200, address.toJSON(this.network));
res.send(200, addr.toJSON(this.network));
});
// Wallet Balance
this.get('/:id/balance', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const acct = valid.str('account');
const balance = await req.wallet.getBalance(acct);
@ -636,7 +625,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Wallet UTXOs
this.get('/:id/coin', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const acct = valid.str('account');
const coins = await req.wallet.getCoins(acct);
const result = [];
@ -662,8 +651,8 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Lock coin
this.put('/:id/locked/:hash/:index', async (req, res) => {
const valid = req.valid();
const hash = valid.hash('hash');
const valid = Validator.fromRequest(req);
const hash = valid.rhash('hash');
const index = valid.u32('index');
enforce(hash, 'Hash is required.');
@ -678,8 +667,8 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Unlock coin
this.del('/:id/locked/:hash/:index', async (req, res) => {
const valid = req.valid();
const hash = valid.hash('hash');
const valid = Validator.fromRequest(req);
const hash = valid.rhash('hash');
const index = valid.u32('index');
enforce(hash, 'Hash is required.');
@ -694,8 +683,8 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Wallet Coin
this.get('/:id/coin/:hash/:index', async (req, res) => {
const valid = req.valid();
const hash = valid.hash('hash');
const valid = Validator.fromRequest(req);
const hash = valid.rhash('hash');
const index = valid.u32('index');
enforce(hash, 'Hash is required.');
@ -713,7 +702,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Wallet TXs
this.get('/:id/tx/history', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const acct = valid.str('account');
const txs = await req.wallet.getHistory(acct);
@ -731,7 +720,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Wallet Pending TXs
this.get('/:id/tx/unconfirmed', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const acct = valid.str('account');
const txs = await req.wallet.getPending(acct);
@ -748,7 +737,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Wallet TXs within time range
this.get('/:id/tx/range', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const acct = valid.str('account');
const options = {
@ -770,7 +759,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Last Wallet TXs
this.get('/:id/tx/last', async (req, res) => {
const valid = req.valid();
const valid = Validator.fromRequest(req);
const acct = valid.str('account');
const limit = valid.u32('limit');
const txs = await req.wallet.getLast(acct, limit);
@ -785,8 +774,8 @@ HTTPServer.prototype.initRouter = function initRouter() {
// Wallet TX
this.get('/:id/tx/:hash', async (req, res) => {
const valid = req.valid();
const hash = valid.hash('hash');
const valid = Validator.fromRequest(req);
const hash = valid.rhash('hash');
enforce(hash, 'Hash is required.');
@ -869,7 +858,7 @@ HTTPServer.prototype.handleSocket = function handleSocket(socket) {
throw new Error('Already authed.');
if (!this.options.noAuth) {
const valid = new Validator([args]);
const valid = new Validator(args);
const key = valid.str(0, '');
if (key.length > 255)
@ -900,7 +889,7 @@ HTTPServer.prototype.handleSocket = function handleSocket(socket) {
HTTPServer.prototype.handleAuth = function handleAuth(socket) {
socket.hook('wallet join', async (args) => {
const valid = new Validator([args]);
const valid = new Validator(args);
const id = valid.str(0, '');
const token = valid.buf(1);
@ -934,7 +923,7 @@ HTTPServer.prototype.handleAuth = function handleAuth(socket) {
});
socket.hook('wallet leave', (args) => {
const valid = new Validator([args]);
const valid = new Validator(args);
const id = valid.str(0, '');
if (!id)

View File

@ -137,7 +137,7 @@ RPC.prototype.fundRawTransaction = async function fundRawTransaction(args, help)
}
const wallet = this.wallet;
const valid = new Validator([args]);
const valid = new Validator(args);
const data = valid.buf(0);
const options = valid.obj(1);
@ -155,7 +155,7 @@ RPC.prototype.fundRawTransaction = async function fundRawTransaction(args, help)
let change = null;
if (options) {
const valid = new Validator([options]);
const valid = new Validator(options);
rate = valid.ufixed('feeRate', 8);
change = valid.str('changeAddress');
@ -213,7 +213,7 @@ RPC.prototype.addWitnessAddress = async function addWitnessAddress(args, help) {
};
RPC.prototype.backupWallet = async function backupWallet(args, help) {
const valid = new Validator([args]);
const valid = new Validator(args);
const dest = valid.str(0);
if (help || args.length !== 1 || !dest)
@ -229,7 +229,7 @@ RPC.prototype.dumpPrivKey = async function dumpPrivKey(args, help) {
throw new RPCError(errs.MISC_ERROR, 'dumpprivkey "bitcoinaddress"');
const wallet = this.wallet;
const valid = new Validator([args]);
const valid = new Validator(args);
const addr = valid.str(0, '');
const hash = parseHash(addr, this.network);
@ -246,7 +246,7 @@ RPC.prototype.dumpWallet = async function dumpWallet(args, help) {
throw new RPCError(errs.MISC_ERROR, 'dumpwallet "filename"');
const wallet = this.wallet;
const valid = new Validator([args]);
const valid = new Validator(args);
const file = valid.str(0);
if (!file)
@ -304,7 +304,7 @@ RPC.prototype.encryptWallet = async function encryptWallet(args, help) {
if (!wallet.master.encrypted && (help || args.length !== 1))
throw new RPCError(errs.MISC_ERROR, 'encryptwallet "passphrase"');
const valid = new Validator([args]);
const valid = new Validator(args);
const passphrase = valid.str(0, '');
if (wallet.master.encrypted) {
@ -329,7 +329,7 @@ RPC.prototype.getAccountAddress = async function getAccountAddress(args, help) {
throw new RPCError(errs.MISC_ERROR, 'getaccountaddress "account"');
const wallet = this.wallet;
const valid = new Validator([args]);
const valid = new Validator(args);
let name = valid.str(0, '');
if (!name)
@ -348,7 +348,7 @@ RPC.prototype.getAccount = async function getAccount(args, help) {
throw new RPCError(errs.MISC_ERROR, 'getaccount "bitcoinaddress"');
const wallet = this.wallet;
const valid = new Validator([args]);
const valid = new Validator(args);
const addr = valid.str(0, '');
const hash = parseHash(addr, this.network);
@ -365,7 +365,7 @@ RPC.prototype.getAddressesByAccount = async function getAddressesByAccount(args,
throw new RPCError(errs.MISC_ERROR, 'getaddressesbyaccount "account"');
const wallet = this.wallet;
const valid = new Validator([args]);
const valid = new Validator(args);
let name = valid.str(0, '');
const addrs = [];
@ -389,7 +389,7 @@ RPC.prototype.getBalance = async function getBalance(args, help) {
}
const wallet = this.wallet;
const valid = new Validator([args]);
const valid = new Validator(args);
let name = valid.str(0);
const minconf = valid.u32(1, 1);
const watchOnly = valid.bool(2, false);
@ -419,7 +419,7 @@ RPC.prototype.getNewAddress = async function getNewAddress(args, help) {
throw new RPCError(errs.MISC_ERROR, 'getnewaddress ( "account" )');
const wallet = this.wallet;
const valid = new Validator([args]);
const valid = new Validator(args);
let name = valid.str(0);
if (name === '')
@ -447,7 +447,7 @@ RPC.prototype.getReceivedByAccount = async function getReceivedByAccount(args, h
}
const wallet = this.wallet;
const valid = new Validator([args]);
const valid = new Validator(args);
let name = valid.str(0);
const minconf = valid.u32(1, 0);
const height = this.wdb.state.height;
@ -492,7 +492,7 @@ RPC.prototype.getReceivedByAddress = async function getReceivedByAddress(args, h
}
const wallet = this.wallet;
const valid = new Validator([args]);
const valid = new Validator(args);
const addr = valid.str(0, '');
const minconf = valid.u32(1, 0);
const height = this.wdb.state.height;
@ -595,8 +595,8 @@ RPC.prototype.getTransaction = async function getTransaction(args, help) {
}
const wallet = this.wallet;
const valid = new Validator([args]);
const hash = valid.hash(0);
const valid = new Validator(args);
const hash = valid.rhash(0);
const watchOnly = valid.bool(1, false);
if (!hash)
@ -615,8 +615,8 @@ RPC.prototype.abandonTransaction = async function abandonTransaction(args, help)
throw new RPCError(errs.MISC_ERROR, 'abandontransaction "txid"');
const wallet = this.wallet;
const valid = new Validator([args]);
const hash = valid.hash(0);
const valid = new Validator(args);
const hash = valid.rhash(0);
if (!hash)
throw new RPCError(errs.TYPE_ERROR, 'Invalid parameter.');
@ -666,7 +666,7 @@ RPC.prototype.importPrivKey = async function importPrivKey(args, help) {
}
const wallet = this.wallet;
const valid = new Validator([args]);
const valid = new Validator(args);
const secret = valid.str(0);
const rescan = valid.bool(2, false);
@ -685,7 +685,7 @@ RPC.prototype.importWallet = async function importWallet(args, help) {
throw new RPCError(errs.MISC_ERROR, 'importwallet "filename" ( rescan )');
const wallet = this.wallet;
const valid = new Validator([args]);
const valid = new Validator(args);
const file = valid.str(0);
const rescan = valid.bool(1, false);
@ -731,7 +731,7 @@ RPC.prototype.importAddress = async function importAddress(args, help) {
}
const wallet = this.wallet;
const valid = new Validator([args]);
const valid = new Validator(args);
let addr = valid.str(0, '');
const rescan = valid.bool(2, false);
const p2sh = valid.bool(3, false);
@ -765,7 +765,7 @@ RPC.prototype.importPubkey = async function importPubkey(args, help) {
}
const wallet = this.wallet;
const valid = new Validator([args]);
const valid = new Validator(args);
const data = valid.buf(0);
const rescan = valid.bool(2, false);
@ -795,7 +795,7 @@ RPC.prototype.listAccounts = async function listAccounts(args, help) {
}
const wallet = this.wallet;
const valid = new Validator([args]);
const valid = new Validator(args);
const minconf = valid.u32(0, 0);
const watchOnly = valid.bool(1, false);
@ -848,7 +848,7 @@ RPC.prototype.listReceivedByAccount = async function listReceivedByAccount(args,
'listreceivedbyaccount ( minconf includeempty includeWatchonly )');
}
const valid = new Validator([args]);
const valid = new Validator(args);
const minconf = valid.u32(0, 0);
const includeEmpty = valid.bool(1, false);
const watchOnly = valid.bool(2, false);
@ -862,7 +862,7 @@ RPC.prototype.listReceivedByAddress = async function listReceivedByAddress(args,
'listreceivedbyaddress ( minconf includeempty includeWatchonly )');
}
const valid = new Validator([args]);
const valid = new Validator(args);
const minconf = valid.u32(0, 0);
const includeEmpty = valid.bool(1, false);
const watchOnly = valid.bool(2, false);
@ -955,8 +955,8 @@ RPC.prototype._listReceived = async function _listReceived(minconf, empty, watch
RPC.prototype.listSinceBlock = async function listSinceBlock(args, help) {
const wallet = this.wallet;
const chainHeight = this.wdb.state.height;
const valid = new Validator([args]);
const block = valid.hash(0);
const valid = new Validator(args);
const block = valid.rhash(0);
const minconf = valid.u32(1, 0);
const watchOnly = valid.bool(2, false);
@ -1084,7 +1084,7 @@ RPC.prototype.listTransactions = async function listTransactions(args, help) {
}
const wallet = this.wallet;
const valid = new Validator([args]);
const valid = new Validator(args);
let name = valid.str(0);
const count = valid.u32(1, 10);
const from = valid.u32(2, 0);
@ -1120,7 +1120,7 @@ RPC.prototype.listUnspent = async function listUnspent(args, help) {
}
const wallet = this.wallet;
const valid = new Validator([args]);
const valid = new Validator(args);
const minDepth = valid.u32(0, 1);
const maxDepth = valid.u32(1, 9999999);
const addrs = valid.array(2);
@ -1129,7 +1129,7 @@ RPC.prototype.listUnspent = async function listUnspent(args, help) {
const map = new Set();
if (addrs) {
const valid = new Validator([addrs]);
const valid = new Validator(addrs);
for (let i = 0; i < addrs.length; i++) {
const addr = valid.str(i, '');
const hash = parseHash(addr, this.network);
@ -1193,7 +1193,7 @@ RPC.prototype.lockUnspent = async function lockUnspent(args, help) {
}
const wallet = this.wallet;
const valid = new Validator([args]);
const valid = new Validator(args);
const unlock = valid.bool(0, false);
const outputs = valid.array(1);
@ -1207,8 +1207,8 @@ RPC.prototype.lockUnspent = async function lockUnspent(args, help) {
throw new RPCError(errs.TYPE_ERROR, 'Invalid parameter.');
for (const output of outputs) {
const valid = new Validator([output]);
const hash = valid.hash('txid');
const valid = new Validator(output);
const hash = valid.rhash('txid');
const index = valid.u32('vout');
if (hash == null || index == null)
@ -1240,7 +1240,7 @@ RPC.prototype.sendFrom = async function sendFrom(args, help) {
}
const wallet = this.wallet;
const valid = new Validator([args]);
const valid = new Validator(args);
let name = valid.str(0);
const str = valid.str(1);
const value = valid.ufixed(2, 8);
@ -1276,7 +1276,7 @@ RPC.prototype.sendMany = async function sendMany(args, help) {
}
const wallet = this.wallet;
const valid = new Validator([args]);
const valid = new Validator(args);
let name = valid.str(0);
const sendTo = valid.obj(1);
const minconf = valid.u32(2, 1);
@ -1288,7 +1288,7 @@ RPC.prototype.sendMany = async function sendMany(args, help) {
if (!sendTo)
throw new RPCError(errs.TYPE_ERROR, 'Invalid parameter.');
const to = new Validator([sendTo]);
const to = new Validator(sendTo);
const uniq = new Set();
const outputs = [];
@ -1331,7 +1331,7 @@ RPC.prototype.sendToAddress = async function sendToAddress(args, help) {
}
const wallet = this.wallet;
const valid = new Validator([args]);
const valid = new Validator(args);
const str = valid.str(0);
const value = valid.ufixed(1, 8);
const subtract = valid.bool(4, false);
@ -1365,7 +1365,7 @@ RPC.prototype.setAccount = async function setAccount(args, help) {
};
RPC.prototype.setTXFee = async function setTXFee(args, help) {
const valid = new Validator([args]);
const valid = new Validator(args);
const rate = valid.ufixed(0, 8);
if (help || args.length < 1 || args.length > 1)
@ -1386,7 +1386,7 @@ RPC.prototype.signMessage = async function signMessage(args, help) {
}
const wallet = this.wallet;
const valid = new Validator([args]);
const valid = new Validator(args);
const b58 = valid.str(0, '');
const str = valid.str(1, '');
@ -1430,7 +1430,7 @@ RPC.prototype.walletPassphraseChange = async function walletPassphraseChange(arg
+ ' "oldpassphrase" "newpassphrase"');
}
const valid = new Validator([args]);
const valid = new Validator(args);
const old = valid.str(0, '');
const passphrase = valid.str(1, '');
@ -1447,7 +1447,7 @@ RPC.prototype.walletPassphraseChange = async function walletPassphraseChange(arg
RPC.prototype.walletPassphrase = async function walletPassphrase(args, help) {
const wallet = this.wallet;
const valid = new Validator([args]);
const valid = new Validator(args);
const passphrase = valid.str(0, '');
const timeout = valid.u32(1);
@ -1476,7 +1476,7 @@ RPC.prototype.importPrunedFunds = async function importPrunedFunds(args, help) {
'importprunedfunds "rawtransaction" "txoutproof" ( "label" )');
}
const valid = new Validator([args]);
const valid = new Validator(args);
const txRaw = valid.buf(0);
const blockRaw = valid.buf(1);
@ -1515,8 +1515,8 @@ RPC.prototype.removePrunedFunds = async function removePrunedFunds(args, help) {
throw new RPCError(errs.MISC_ERROR, 'removeprunedfunds "txid"');
const wallet = this.wallet;
const valid = new Validator([args]);
const hash = valid.hash(0);
const valid = new Validator(args);
const hash = valid.rhash(0);
if (!hash)
throw new RPCError(errs.TYPE_ERROR, 'Invalid parameter.');
@ -1528,7 +1528,7 @@ RPC.prototype.removePrunedFunds = async function removePrunedFunds(args, help) {
};
RPC.prototype.selectWallet = async function selectWallet(args, help) {
const valid = new Validator([args]);
const valid = new Validator(args);
const id = valid.str(0);
if (help || args.length !== 1)
@ -1555,7 +1555,7 @@ RPC.prototype.setLogLevel = async function setLogLevel(args, help) {
if (help || args.length !== 1)
throw new RPCError(errs.MISC_ERROR, 'setloglevel "level"');
const valid = new Validator([args]);
const valid = new Validator(args);
const level = valid.str(0, '');
this.logger.setLevel(level);