http: more methods and better validation.
This commit is contained in:
parent
6f18d890f1
commit
80aa8f8c4c
79
bin/cli
79
bin/cli
@ -7,7 +7,6 @@ var utils = require('../lib/utils/utils');
|
||||
var co = require('../lib/utils/co');
|
||||
var Client = require('../lib/http/client');
|
||||
var Wallet = require('../lib/http/wallet');
|
||||
var assert = require('assert');
|
||||
var main;
|
||||
|
||||
function CLI() {
|
||||
@ -38,8 +37,8 @@ CLI.prototype.createWallet = co(function* createWallet() {
|
||||
if (this.config.master)
|
||||
options.master = this.config.master;
|
||||
|
||||
if (this.config.key)
|
||||
options.key = this.config.key;
|
||||
if (this.config.mnemonic)
|
||||
options.master = this.config.mnemonic;
|
||||
|
||||
if (this.config.m)
|
||||
options.m = this.config.m >>> 0;
|
||||
@ -65,13 +64,13 @@ CLI.prototype.createWallet = co(function* createWallet() {
|
||||
CLI.prototype.addKey = co(function* addKey() {
|
||||
var key = this.argv[0];
|
||||
yield this.wallet.addKey(this.config.account, key);
|
||||
this.log('added');
|
||||
this.log('Added key.');
|
||||
});
|
||||
|
||||
CLI.prototype.removeKey = co(function* removeKey() {
|
||||
var key = this.argv[0];
|
||||
yield this.wallet.removeKey(this.config.account, key);
|
||||
this.log('removed');
|
||||
this.log('Removed key.');
|
||||
});
|
||||
|
||||
CLI.prototype.getAccount = co(function* getAccount() {
|
||||
@ -130,6 +129,8 @@ CLI.prototype.getTX = co(function* getTX() {
|
||||
|
||||
CLI.prototype.getBlock = co(function* getBlock() {
|
||||
var hash = this.argv[0];
|
||||
var block;
|
||||
|
||||
if (hash.length !== 64)
|
||||
hash = +hash;
|
||||
|
||||
@ -137,7 +138,7 @@ CLI.prototype.getBlock = co(function* getBlock() {
|
||||
|
||||
if (!block) {
|
||||
this.log('Block not found.');
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
this.log(block);
|
||||
@ -268,7 +269,6 @@ CLI.prototype.zap = co(function* zap() {
|
||||
});
|
||||
|
||||
CLI.prototype.broadcast = co(function* broadcast() {
|
||||
var self = this;
|
||||
var raw = this.argv[0] || this.config.tx;
|
||||
var tx = yield this.client.broadcast(raw);
|
||||
this.log('Broadcasted:');
|
||||
@ -292,6 +292,56 @@ CLI.prototype.retoken = co(function* retoken() {
|
||||
this.log(result);
|
||||
});
|
||||
|
||||
CLI.prototype.rescan = co(function* rescan() {
|
||||
var hash = this.argv[0];
|
||||
|
||||
if (hash.length !== 64)
|
||||
hash = +hash;
|
||||
|
||||
yield this.client.rescan(hash);
|
||||
|
||||
this.log('Rescanning...');
|
||||
});
|
||||
|
||||
CLI.prototype.importKey = co(function* importKey() {
|
||||
var key = this.argv[0];
|
||||
|
||||
if (!key)
|
||||
throw new Error('No key for import.');
|
||||
|
||||
if (utils.isBase58(key)) {
|
||||
yield this.wallet.importPrivate(key);
|
||||
this.log('Imported private key.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (utils.isHex(key)) {
|
||||
yield this.wallet.importPublic(key);
|
||||
this.log('Imported public key.');
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error('Bad key for import.');
|
||||
});
|
||||
|
||||
CLI.prototype.importAddress = co(function* importKey() {
|
||||
var address = this.argv[0];
|
||||
yield this.wallet.importAddress(address);
|
||||
this.log('Imported address.');
|
||||
});
|
||||
|
||||
CLI.prototype.lock = co(function* lock() {
|
||||
yield this.wallet.lock();
|
||||
this.log('Locked.');
|
||||
});
|
||||
|
||||
CLI.prototype.unlock = co(function* unlock() {
|
||||
var passphrase = this.argv[0];
|
||||
var timeout = +this.argv[1] || null;
|
||||
yield this.wallet.unlock(passphrase, timeout);
|
||||
this.log('Unlocked.');
|
||||
});
|
||||
|
||||
CLI.prototype.rpc = co(function* rpc() {
|
||||
var method = this.argv.shift();
|
||||
var params = [];
|
||||
@ -369,6 +419,14 @@ CLI.prototype.handleWallet = co(function* handleWallet() {
|
||||
return yield this.getDetails();
|
||||
case 'view':
|
||||
return yield this.viewTX();
|
||||
case 'import':
|
||||
return yield this.importKey();
|
||||
case 'watch':
|
||||
return yield this.importAddress();
|
||||
case 'lock':
|
||||
return yield this.lock();
|
||||
case 'unlock':
|
||||
return yield this.unlock();
|
||||
default:
|
||||
this.log('Unrecognized command.');
|
||||
this.log('Commands:');
|
||||
@ -390,6 +448,10 @@ CLI.prototype.handleWallet = co(function* handleWallet() {
|
||||
this.log(' $ zap --age [age]: Zap pending wallet TXs.');
|
||||
this.log(' $ tx [hash]: View transaction details.');
|
||||
this.log(' $ view [tx-hex]: Parse and view transaction.');
|
||||
this.log(' $ import [wif|hex]: Import private or public key.');
|
||||
this.log(' $ watch [address]: Import an address.');
|
||||
this.log(' $ lock: Lock wallet.');
|
||||
this.log(' $ unlock [passphrase] [timeout]: Unlock wallet.');
|
||||
this.log('Other Options:');
|
||||
this.log(' --passphrase [passphrase]: For signing and account creation.');
|
||||
this.log(' --account [account-name]: Account name.');
|
||||
@ -421,6 +483,8 @@ CLI.prototype.handleNode = co(function* handleNode() {
|
||||
return yield this.getCoin();
|
||||
case 'block':
|
||||
return yield this.getBlock();
|
||||
case 'rescan':
|
||||
return yield this.rescan();
|
||||
case 'rpc':
|
||||
return yield this.rpc();
|
||||
default:
|
||||
@ -432,6 +496,7 @@ CLI.prototype.handleNode = co(function* handleNode() {
|
||||
this.log(' $ tx [hash/address]: View transactions.');
|
||||
this.log(' $ coin [hash+index/address]: View coins.');
|
||||
this.log(' $ block [hash/height]: View block.');
|
||||
this.log(' $ rescan [height/hash]: Rescan for transactions.');
|
||||
this.log(' $ rpc [command] [args]: Execute RPC command.');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -12,7 +12,6 @@ var AsyncObject = require('../utils/async');
|
||||
var RPCClient = require('./rpcclient');
|
||||
var utils = require('../utils/utils');
|
||||
var co = require('../utils/co');
|
||||
var assert = require('assert');
|
||||
var request = require('./request').promise;
|
||||
|
||||
/**
|
||||
@ -348,6 +347,17 @@ HTTPClient.prototype.broadcast = function broadcast(tx) {
|
||||
return this._post('/broadcast', body);
|
||||
};
|
||||
|
||||
/**
|
||||
* Rescan the chain.
|
||||
* @param {Hash|Number} hash
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
HTTPClient.prototype.rescan = function rescan(hash) {
|
||||
var options = { hash: hash };
|
||||
return this._post('/rescan', options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Listen for events on wallet id.
|
||||
* @param {WalletID} id
|
||||
@ -650,7 +660,6 @@ HTTPClient.prototype.zap = function zap(id, account, age) {
|
||||
account: account,
|
||||
age: age
|
||||
};
|
||||
assert(utils.isNumber(age));
|
||||
return this._post('/wallet/' + id + '/zap', body);
|
||||
};
|
||||
|
||||
@ -664,11 +673,7 @@ HTTPClient.prototype.zap = function zap(id, account, age) {
|
||||
*/
|
||||
|
||||
HTTPClient.prototype.addKey = function addKey(id, account, key) {
|
||||
var options;
|
||||
|
||||
key = key.xpubkey || key;
|
||||
options = { account: account, key: key };
|
||||
|
||||
var options = { account: account, accountKey: key };
|
||||
return this._put('/wallet/' + id + '/key', options);
|
||||
};
|
||||
|
||||
@ -682,14 +687,108 @@ HTTPClient.prototype.addKey = function addKey(id, account, key) {
|
||||
*/
|
||||
|
||||
HTTPClient.prototype.removeKey = function removeKey(id, account, key) {
|
||||
var options;
|
||||
|
||||
key = key.xpubkey || key;
|
||||
options = { account: account, key: key };
|
||||
|
||||
var options = { account: account, accountKey: key };
|
||||
return this._del('/wallet/' + id + '/key', options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Import private key.
|
||||
* @param {String} id
|
||||
* @param {Number|String} account
|
||||
* @param {String} key
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
HTTPClient.prototype.importPrivate = function importPrivate(id, account, key) {
|
||||
var options = { privateKey: key };
|
||||
return this._post('/wallet/' + id + '/import', options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Import public key.
|
||||
* @param {String} id
|
||||
* @param {Number|String} account
|
||||
* @param {String} key
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
HTTPClient.prototype.importPublic = function importPublic(id, account, key) {
|
||||
var options = { publicKey: key };
|
||||
return this._post('/wallet/' + id + '/import', options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Import address.
|
||||
* @param {String} id
|
||||
* @param {Number|String} account
|
||||
* @param {String} address
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
HTTPClient.prototype.importAddress = function importAddress(id, account, address) {
|
||||
var options = { address: address };
|
||||
return this._post('/wallet/' + id + '/import', options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Lock a coin.
|
||||
* @param {String} id
|
||||
* @param {String} hash
|
||||
* @param {Number} index
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
HTTPClient.prototype.lockCoin = function lockCoin(id, hash, index) {
|
||||
var options = { hash: hash, index: index };
|
||||
return this._put('/wallet/' + id + '/coin/locked', options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Unlock a coin.
|
||||
* @param {String} id
|
||||
* @param {String} hash
|
||||
* @param {Number} index
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
HTTPClient.prototype.unlockCoin = function unlockCoin(id, hash, index) {
|
||||
var options = { hash: hash, index: index };
|
||||
return this._del('/wallet/' + id + '/coin/locked', options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get locked coins.
|
||||
* @param {String} id
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
HTTPClient.prototype.getLocked = function getLocked(id) {
|
||||
return this._get('/wallet/' + id + '/coin/locked');
|
||||
};
|
||||
|
||||
/**
|
||||
* Lock wallet.
|
||||
* @param {String} id
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
HTTPClient.prototype.lock = function lock(id) {
|
||||
return this._post('/wallet/' + id + '/lock', {});
|
||||
};
|
||||
|
||||
/**
|
||||
* Unlock wallet.
|
||||
* @param {String} id
|
||||
* @param {String} passphrase
|
||||
* @param {Number} timeout
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
HTTPClient.prototype.unlock = function unlock(id, passphrase, timeout) {
|
||||
var options = { passphrase: passphrase, timeout: timeout };
|
||||
return this._post('/wallet/' + id + '/unlock', options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get wallet accounts.
|
||||
* @param {WalletID} id
|
||||
|
||||
@ -8,17 +8,21 @@
|
||||
'use strict';
|
||||
|
||||
/* jshint -W069 */
|
||||
/* jshint noyield: true */
|
||||
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var assert = require('assert');
|
||||
var constants = require('../protocol/constants');
|
||||
var HTTPBase = require('./base');
|
||||
var utils = require('../utils/utils');
|
||||
var co = require('../utils/co');
|
||||
var Address = require('../primitives/address');
|
||||
var TX = require('../primitives/tx');
|
||||
var KeyRing = require('../primitives/keyring');
|
||||
var Outpoint = require('../primitives/outpoint');
|
||||
var HD = require('../hd/hd');
|
||||
var Script = require('../script/script');
|
||||
var crypto = require('../crypto/crypto');
|
||||
var assert = require('assert');
|
||||
var con = co.con;
|
||||
var RPC;
|
||||
|
||||
@ -176,8 +180,8 @@ HTTPServer.prototype._init = function _init() {
|
||||
var i, params, options, output, address;
|
||||
|
||||
if (req.method === 'POST' && req.pathname === '/') {
|
||||
assert(typeof req.body.method === 'string', 'Method must be a string.');
|
||||
assert(Array.isArray(req.body.params), 'Params must be an array.');
|
||||
enforce(typeof req.body.method === 'string', 'Method must be a string.');
|
||||
enforce(Array.isArray(req.body.params), 'Params must be an array.');
|
||||
req.options = {};
|
||||
return next();
|
||||
}
|
||||
@ -193,15 +197,15 @@ HTTPServer.prototype._init = function _init() {
|
||||
this.logger.debug(params);
|
||||
|
||||
if (params.id) {
|
||||
assert(typeof params.id === 'string', 'ID must be a string.');
|
||||
enforce(typeof params.id === 'string', 'ID must be a string.');
|
||||
options.id = params.id;
|
||||
}
|
||||
|
||||
if (params.hash) {
|
||||
assert(typeof params.hash === 'string', 'Hash must be a string.');
|
||||
enforce(typeof params.hash === 'string', 'Hash must be a string.');
|
||||
if (params.hash.length !== 64) {
|
||||
options.height = Number(params.hash);
|
||||
assert(utils.isUInt32(options.height), 'Height must be a number.');
|
||||
enforce(utils.isUInt32(options.height), 'Height must be a number.');
|
||||
} else {
|
||||
options.hash = utils.revHex(params.hash);
|
||||
}
|
||||
@ -209,37 +213,37 @@ HTTPServer.prototype._init = function _init() {
|
||||
|
||||
if (params.index != null) {
|
||||
options.index = Number(params.index);
|
||||
assert(utils.isUInt32(options.index), 'Index must be a number.');
|
||||
enforce(utils.isUInt32(options.index), 'Index must be a number.');
|
||||
}
|
||||
|
||||
if (params.height != null) {
|
||||
options.height = Number(params.height);
|
||||
assert(utils.isUInt32(options.height), 'Height must be a number.');
|
||||
enforce(utils.isUInt32(options.height), 'Height must be a number.');
|
||||
}
|
||||
|
||||
if (params.start != null) {
|
||||
options.start = Number(params.start);
|
||||
assert(utils.isUInt32(options.start), 'Start must be a number.');
|
||||
enforce(utils.isUInt32(options.start), 'Start must be a number.');
|
||||
}
|
||||
|
||||
if (params.end != null) {
|
||||
options.end = Number(params.end);
|
||||
assert(utils.isUInt32(options.end), 'End must be a number.');
|
||||
enforce(utils.isUInt32(options.end), 'End must be a number.');
|
||||
}
|
||||
|
||||
if (params.limit != null) {
|
||||
options.limit = Number(params.limit);
|
||||
assert(utils.isUInt32(options.limit), 'Limit must be a number.');
|
||||
enforce(utils.isUInt32(options.limit), 'Limit must be a number.');
|
||||
}
|
||||
|
||||
if (params.age != null) {
|
||||
options.age = Number(params.age);
|
||||
assert(utils.isUInt32(options.age), 'Age must be a number.');
|
||||
enforce(utils.isUInt32(options.age), 'Age must be a number.');
|
||||
}
|
||||
|
||||
if (params.confirmations != null) {
|
||||
options.confirmations = Number(params.confirmations);
|
||||
assert(utils.isNumber(options.confirmations),
|
||||
enforce(utils.isNumber(options.confirmations),
|
||||
'Confirmations must be a number.');
|
||||
}
|
||||
|
||||
@ -257,53 +261,63 @@ HTTPServer.prototype._init = function _init() {
|
||||
|
||||
if (params.m != null) {
|
||||
options.m = Number(params.m);
|
||||
assert(utils.isUInt32(options.m), 'm must be a number.');
|
||||
enforce(utils.isUInt32(options.m), 'm must be a number.');
|
||||
}
|
||||
|
||||
if (params.n != null) {
|
||||
options.n = Number(params.n);
|
||||
assert(utils.isUInt32(options.n), 'n must be a number.');
|
||||
enforce(utils.isUInt32(options.n), 'n must be a number.');
|
||||
}
|
||||
|
||||
if (params.blocks != null) {
|
||||
options.blocks = Number(params.blocks);
|
||||
assert(utils.isUInt32(options.blocks), 'Blocks must be a number.');
|
||||
enforce(utils.isUInt32(options.blocks), 'Blocks must be a number.');
|
||||
}
|
||||
|
||||
if (params.subtractFee != null) {
|
||||
if (typeof params.subtractFee === 'number') {
|
||||
options.subtractFee = params.subtractFee;
|
||||
assert(utils.isUInt32(options.subtractFee), 'subtractFee must be a number.');
|
||||
enforce(utils.isUInt32(options.subtractFee), 'subtractFee must be a number.');
|
||||
} else {
|
||||
options.subtractFee = params.subtractFee;
|
||||
assert(typeof options.subtractFee === 'boolean', 'subtractFee must be a boolean.');
|
||||
enforce(typeof options.subtractFee === 'boolean', 'subtractFee must be a boolean.');
|
||||
}
|
||||
}
|
||||
|
||||
if (params.watchOnly != null) {
|
||||
assert(typeof params.watchOnly === 'boolean', 'watchOnly must be a boolean.');
|
||||
enforce(typeof params.watchOnly === 'boolean', 'watchOnly must be a boolean.');
|
||||
options.watchOnly = params.watchOnly;
|
||||
}
|
||||
|
||||
if (params.accountKey) {
|
||||
assert(typeof params.accountKey === 'string', 'accountKey must be a string.');
|
||||
options.accountKey = params.accountKey;
|
||||
enforce(typeof params.accountKey === 'string', 'accountKey must be a string.');
|
||||
options.accountKey = HD.fromExtended(params.accountKey);
|
||||
}
|
||||
|
||||
if (params.timeout != null) {
|
||||
options.timeout = Number(params.timeout);
|
||||
enforce(utils.isNumber(options.timeout), 'Timeout must be a number.');
|
||||
}
|
||||
|
||||
if (params.witness != null) {
|
||||
enforce(typeof params.witness === 'boolean', 'witness must be a boolean.');
|
||||
options.witness = params.witness;
|
||||
}
|
||||
|
||||
if (params.outputs) {
|
||||
assert(Array.isArray(params.outputs), 'Outputs must be an array.');
|
||||
enforce(Array.isArray(params.outputs), 'Outputs must be an array.');
|
||||
options.outputs = [];
|
||||
for (i = 0; i < params.outputs.length; i++) {
|
||||
output = params.outputs[i];
|
||||
|
||||
assert(output && typeof output === 'object', 'Output must be an object.');
|
||||
enforce(output && typeof output === 'object', 'Output must be an object.');
|
||||
|
||||
if (output.address)
|
||||
assert(typeof output.address === 'string', 'Address must be a string.');
|
||||
enforce(typeof output.address === 'string', 'Address must be a string.');
|
||||
else if (output.script)
|
||||
assert(typeof output.script === 'string', 'Script must be a string.');
|
||||
enforce(typeof output.script === 'string', 'Script must be a string.');
|
||||
else
|
||||
assert(false, 'No address or script present.');
|
||||
enforce(false, 'No address or script present.');
|
||||
|
||||
options.outputs.push({
|
||||
address: output.address
|
||||
@ -322,11 +336,11 @@ HTTPServer.prototype._init = function _init() {
|
||||
options.address = [];
|
||||
for (i = 0; i < params.address.length; i++) {
|
||||
address = params.address[i];
|
||||
assert(typeof address === 'string', 'Address must be a string.');
|
||||
enforce(typeof address === 'string', 'Address must be a string.');
|
||||
address = Address.fromBase58(address);
|
||||
}
|
||||
} else {
|
||||
assert(typeof params.address === 'string', 'Address must be a string.');
|
||||
enforce(typeof params.address === 'string', 'Address must be a string.');
|
||||
options.address = Address.fromBase58(params.address);
|
||||
}
|
||||
}
|
||||
@ -335,7 +349,7 @@ HTTPServer.prototype._init = function _init() {
|
||||
if (typeof params.tx === 'object') {
|
||||
options.tx = TX.fromJSON(params.tx);
|
||||
} else {
|
||||
assert(typeof params.tx === 'string', 'TX must be a hex string.');
|
||||
enforce(typeof params.tx === 'string', 'TX must be a hex string.');
|
||||
options.tx = TX.fromRaw(params.tx, 'hex');
|
||||
}
|
||||
}
|
||||
@ -343,43 +357,59 @@ HTTPServer.prototype._init = function _init() {
|
||||
if (params.account != null) {
|
||||
if (typeof params.account === 'number') {
|
||||
options.account = params.account;
|
||||
assert(utils.isUInt32(options.account), 'Account must be a number.');
|
||||
enforce(utils.isUInt32(options.account), 'Account must be a number.');
|
||||
} else {
|
||||
assert(typeof params.account === 'string', 'Account must be a string.');
|
||||
enforce(typeof params.account === 'string', 'Account must be a string.');
|
||||
options.account = params.account;
|
||||
}
|
||||
}
|
||||
|
||||
if (params.type) {
|
||||
assert(typeof params.type === 'string', 'Type must be a string.');
|
||||
enforce(typeof params.type === 'string', 'Type must be a string.');
|
||||
options.type = params.type;
|
||||
}
|
||||
|
||||
if (params.name) {
|
||||
assert(typeof params.name === 'string', 'Name must be a string.');
|
||||
enforce(typeof params.name === 'string', 'Name must be a string.');
|
||||
options.name = params.name;
|
||||
}
|
||||
|
||||
if (params.key) {
|
||||
assert(typeof params.key === 'string', 'Key must be a string.');
|
||||
options.key = params.key;
|
||||
if (params.privateKey) {
|
||||
enforce(typeof params.privateKey === 'string', 'Key must be a string.');
|
||||
options.privateKey = KeyRing.fromSecret(params.privateKey);
|
||||
}
|
||||
|
||||
if (params.publicKey) {
|
||||
enforce(typeof params.publicKey === 'string', 'Key must be a string.');
|
||||
options.publicKey = new Buffer(params.publicKey, 'hex');
|
||||
options.publicKey = KeyRing.fromKey(options.publicKey, this.network);
|
||||
}
|
||||
|
||||
if (params.master) {
|
||||
enforce(typeof params.key === 'string', 'Key must be a string.');
|
||||
options.master = HD.fromExtended(params.master);
|
||||
}
|
||||
|
||||
if (params.mnemonic) {
|
||||
enforce(typeof params.mnemonic === 'string', 'Key must be a string.');
|
||||
options.master = HD.fromMnemonic(params.mnemonic, this.network);
|
||||
}
|
||||
|
||||
if (params.old) {
|
||||
assert(typeof params.old === 'string', 'Passphrase must be a string.');
|
||||
assert(params.old.length > 0, 'Passphrase must be a string.');
|
||||
enforce(typeof params.old === 'string', 'Passphrase must be a string.');
|
||||
enforce(params.old.length > 0, 'Passphrase must be a string.');
|
||||
options.old = params.old;
|
||||
}
|
||||
|
||||
if (params.passphrase) {
|
||||
assert(typeof params.passphrase === 'string', 'Passphrase must be a string.');
|
||||
assert(params.passphrase.length > 0, 'Passphrase must be a string.');
|
||||
enforce(typeof params.passphrase === 'string', 'Passphrase must be a string.');
|
||||
enforce(params.passphrase.length > 0, 'Passphrase must be a string.');
|
||||
options.passphrase = params.passphrase;
|
||||
}
|
||||
|
||||
if (params.token) {
|
||||
assert(utils.isHex(params.token), 'Wallet token must be a hex string.');
|
||||
assert(params.token.length === 64, 'Wallet token must be 32 bytes.');
|
||||
enforce(utils.isHex(params.token), 'Wallet token must be a hex string.');
|
||||
enforce(params.token.length === 64, 'Wallet token must be 32 bytes.');
|
||||
options.token = new Buffer(params.token, 'hex');
|
||||
}
|
||||
|
||||
@ -425,7 +455,9 @@ HTTPServer.prototype._init = function _init() {
|
||||
}
|
||||
|
||||
req.wallet = wallet;
|
||||
|
||||
this.logger.info('Successful auth for %s.', req.options.id);
|
||||
|
||||
next();
|
||||
}));
|
||||
|
||||
@ -489,7 +521,12 @@ HTTPServer.prototype._init = function _init() {
|
||||
|
||||
// UTXO by address
|
||||
this.get('/coin/address/:address', con(function* (req, res, send, next) {
|
||||
var coins = yield this.node.getCoinsByAddress(req.options.address);
|
||||
var coins;
|
||||
|
||||
enforce(req.options.address, 'Address is required.');
|
||||
|
||||
coins = yield this.node.getCoinsByAddress(req.options.address);
|
||||
|
||||
send(200, coins.map(function(coin) {
|
||||
return coin.toJSON();
|
||||
}));
|
||||
@ -497,7 +534,12 @@ HTTPServer.prototype._init = function _init() {
|
||||
|
||||
// UTXO by id
|
||||
this.get('/coin/:hash/:index', con(function* (req, res, send, next) {
|
||||
var coin = yield this.node.getCoin(req.options.hash, req.options.index);
|
||||
var coin;
|
||||
|
||||
enforce(req.options.hash, 'Hash is required.');
|
||||
enforce(req.options.index != null, 'Index is required.');
|
||||
|
||||
coin = yield this.node.getCoin(req.options.hash, req.options.index);
|
||||
|
||||
if (!coin)
|
||||
return send(404);
|
||||
@ -507,7 +549,12 @@ HTTPServer.prototype._init = function _init() {
|
||||
|
||||
// Bulk read UTXOs
|
||||
this.post('/coin/address', con(function* (req, res, send, next) {
|
||||
var coins = yield this.node.getCoinsByAddress(req.options.address);
|
||||
var coins;
|
||||
|
||||
enforce(req.options.address, 'Address is required.');
|
||||
|
||||
coins = yield this.node.getCoinsByAddress(req.options.address);
|
||||
|
||||
send(200, coins.map(function(coin) {
|
||||
return coin.toJSON();
|
||||
}));
|
||||
@ -515,7 +562,11 @@ HTTPServer.prototype._init = function _init() {
|
||||
|
||||
// TX by hash
|
||||
this.get('/tx/:hash', con(function* (req, res, send, next) {
|
||||
var tx = yield this.node.getTX(req.options.hash);
|
||||
var tx;
|
||||
|
||||
enforce(req.options.hash, 'Hash is required.');
|
||||
|
||||
tx = yield this.node.getTX(req.options.hash);
|
||||
|
||||
if (!tx)
|
||||
return send(404);
|
||||
@ -527,8 +578,11 @@ HTTPServer.prototype._init = function _init() {
|
||||
|
||||
// TX by address
|
||||
this.get('/tx/address/:address', con(function* (req, res, send, next) {
|
||||
var txs = yield this.node.getTXByAddress(req.options.address);
|
||||
var i, tx;
|
||||
var i, txs, tx;
|
||||
|
||||
enforce(req.options.address, 'Address is required.');
|
||||
|
||||
txs = yield this.node.getTXByAddress(req.options.address);
|
||||
|
||||
for (i = 0; i < txs.length; i++) {
|
||||
tx = txs[i];
|
||||
@ -542,8 +596,11 @@ HTTPServer.prototype._init = function _init() {
|
||||
|
||||
// Bulk read TXs
|
||||
this.post('/tx/address', con(function* (req, res, send, next) {
|
||||
var txs = yield this.node.getTXByAddress(req.options.address);
|
||||
var i, tx;
|
||||
var i, txs, tx;
|
||||
|
||||
enforce(req.options.address, 'Address is required.');
|
||||
|
||||
txs = yield this.node.getTXByAddress(req.options.address);
|
||||
|
||||
for (i = 0; i < txs.length; i++) {
|
||||
tx = txs[i];
|
||||
@ -558,7 +615,11 @@ HTTPServer.prototype._init = function _init() {
|
||||
// Block by hash/height
|
||||
this.get('/block/:hash', con(function* (req, res, send, next) {
|
||||
var hash = req.options.hash || req.options.height;
|
||||
var block = yield this.node.getFullBlock(hash);
|
||||
var block;
|
||||
|
||||
enforce(hash != null, 'Hash or height required.');
|
||||
|
||||
block = yield this.node.getFullBlock(hash);
|
||||
|
||||
if (!block)
|
||||
return send(404);
|
||||
@ -587,6 +648,7 @@ HTTPServer.prototype._init = function _init() {
|
||||
|
||||
// Broadcast TX
|
||||
this.post('/broadcast', con(function* (req, res, send, next) {
|
||||
enforce(req.options.tx, 'TX is required.');
|
||||
yield this.node.sendTX(req.options.tx);
|
||||
send(200, { success: true });
|
||||
}));
|
||||
@ -603,6 +665,15 @@ HTTPServer.prototype._init = function _init() {
|
||||
send(200, { rate: utils.btc(fee) });
|
||||
});
|
||||
|
||||
// Rescan
|
||||
this.post('/rescan', con(function* (req, res, send, next) {
|
||||
var options = req.options;
|
||||
var height = options.hash || options.height;
|
||||
enforce(height != null, 'Hash or height is required.');
|
||||
send(200, { success: true });
|
||||
yield this.node.scan(height);
|
||||
}));
|
||||
|
||||
// Get wallet
|
||||
this.get('/wallet/:id', function(req, res, send, next) {
|
||||
send(200, req.wallet.toJSON());
|
||||
@ -622,7 +693,13 @@ HTTPServer.prototype._init = function _init() {
|
||||
|
||||
// Get account
|
||||
this.get('/wallet/:id/account/:account', con(function* (req, res, send, next) {
|
||||
var account = yield req.wallet.getAccount(req.options.account);
|
||||
var options = req.options;
|
||||
var acct = options.name || options.account;
|
||||
var account;
|
||||
|
||||
enforce(acct != null, 'Account is required.');
|
||||
|
||||
account = yield req.wallet.getAccount(acct);
|
||||
|
||||
if (!account)
|
||||
return send(404);
|
||||
@ -630,9 +707,17 @@ HTTPServer.prototype._init = function _init() {
|
||||
send(200, account.toJSON());
|
||||
}));
|
||||
|
||||
// Create/get account
|
||||
// Create account
|
||||
this.post('/wallet/:id/account/:account?', con(function* (req, res, send, next) {
|
||||
var account = yield req.wallet.createAccount(req.options);
|
||||
var options = req.options;
|
||||
var account;
|
||||
|
||||
if (typeof options.account === 'string') {
|
||||
options.name = options.account;
|
||||
options.account = null;
|
||||
}
|
||||
|
||||
account = yield req.wallet.createAccount(req.options);
|
||||
|
||||
if (!account)
|
||||
return send(404);
|
||||
@ -645,10 +730,49 @@ HTTPServer.prototype._init = function _init() {
|
||||
var options = req.options;
|
||||
var old = options.old;
|
||||
var new_ = options.passphrase;
|
||||
enforce(old || new_, 'Passphrase is required.');
|
||||
yield req.wallet.setPassphrase(old, new_);
|
||||
send(200, { success: true });
|
||||
}));
|
||||
|
||||
// Unlock wallet
|
||||
this.post('/wallet/:id/unlock', con(function* (req, res, send, next) {
|
||||
var options = req.options;
|
||||
var passphrase = options.passphrase;
|
||||
var timeout = options.timeout;
|
||||
enforce(passphrase, 'Passphrase is required.');
|
||||
yield req.wallet.unlock(passphrase, timeout);
|
||||
send(200, { success: true });
|
||||
}));
|
||||
|
||||
// Lock wallet
|
||||
this.post('/wallet/:id/lock', con(function* (req, res, send, next) {
|
||||
yield req.wallet.lock();
|
||||
send(200, { success: true });
|
||||
}));
|
||||
|
||||
// Import key
|
||||
this.post('/wallet/:id/import', con(function* (req, res, send, next) {
|
||||
var options = req.options;
|
||||
var acct = req.options.name || req.options.account;
|
||||
var key = options.privateKey || options.publicKey;
|
||||
|
||||
if (key) {
|
||||
yield req.wallet.importKey(acct, key);
|
||||
send(200, { success: true });
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.address) {
|
||||
enforce(options.address instanceof Address, 'Address is required.');
|
||||
yield req.wallet.importAddress(acct, options.address);
|
||||
send(200, { success: true });
|
||||
return;
|
||||
}
|
||||
|
||||
enforce(false, 'Key or address is required.');
|
||||
}));
|
||||
|
||||
// Generate new token
|
||||
this.post('/wallet/:id/retoken', con(function* (req, res, send, next) {
|
||||
var options = req.options;
|
||||
@ -675,6 +799,7 @@ HTTPServer.prototype._init = function _init() {
|
||||
this.post('/wallet/:id/sign', con(function* (req, res, send, next) {
|
||||
var options = req.options;
|
||||
var tx = req.options.tx;
|
||||
enforce(tx, 'TX is required.');
|
||||
yield req.wallet.sign(tx, options);
|
||||
send(200, tx.toJSON());
|
||||
}));
|
||||
@ -682,59 +807,70 @@ HTTPServer.prototype._init = function _init() {
|
||||
// Fill TX
|
||||
this.post('/wallet/:id/fill', con(function* (req, res, send, next) {
|
||||
var tx = req.options.tx;
|
||||
enforce(tx, 'TX is required.');
|
||||
yield req.wallet.fillHistory(tx);
|
||||
send(200, tx.toJSON());
|
||||
}));
|
||||
|
||||
// Zap Wallet TXs
|
||||
this.post('/wallet/:id/zap', con(function* (req, res, send, next) {
|
||||
var account = req.options.account;
|
||||
var age = req.options.age;
|
||||
yield req.wallet.zap(account, age);
|
||||
var options = req.options;
|
||||
var acct = options.name || options.account;
|
||||
var age = options.age;
|
||||
enforce(age, 'Age is required.');
|
||||
yield req.wallet.zap(acct, age);
|
||||
send(200, { success: true });
|
||||
}));
|
||||
|
||||
// Abandon Wallet TX
|
||||
this.del('/wallet/:id/tx/:hash', con(function* (req, res, send, next) {
|
||||
var hash = req.options.hash;
|
||||
enforce(hash, 'Hash is required.');
|
||||
yield req.wallet.abandon(hash);
|
||||
send(200, { success: true });
|
||||
}));
|
||||
|
||||
// Add key
|
||||
this.put('/wallet/:id/key', con(function* (req, res, send, next) {
|
||||
var account = req.options.account;
|
||||
var key = req.options.key;
|
||||
yield req.wallet.addKey(account, key);
|
||||
var options = req.options;
|
||||
var acct = options.name || options.account;
|
||||
var key = options.accountKey;
|
||||
enforce(key, 'Key is required.');
|
||||
yield req.wallet.addKey(acct, key);
|
||||
send(200, { success: true });
|
||||
}));
|
||||
|
||||
// Remove key
|
||||
this.del('/wallet/:id/key', con(function* (req, res, send, next) {
|
||||
var account = req.options.account;
|
||||
var key = req.options.key;
|
||||
yield req.wallet.removeKey(account, key);
|
||||
var options = req.options;
|
||||
var acct = options.name || options.account;
|
||||
var key = options.accountKey;
|
||||
enforce(key, 'Key is required.');
|
||||
yield req.wallet.removeKey(acct, key);
|
||||
send(200, { success: true });
|
||||
}));
|
||||
|
||||
// Create address
|
||||
this.post('/wallet/:id/address', con(function* (req, res, send, next) {
|
||||
var account = req.options.account;
|
||||
var address = yield req.wallet.createReceive(account);
|
||||
var options = req.options;
|
||||
var acct = options.name || options.account;
|
||||
var address = yield req.wallet.createReceive(acct);
|
||||
send(200, address.toJSON());
|
||||
}));
|
||||
|
||||
// Create nested address
|
||||
this.post('/wallet/:id/nested', con(function* (req, res, send, next) {
|
||||
var account = req.options.account;
|
||||
var address = yield req.wallet.createNested(account);
|
||||
var options = req.options;
|
||||
var acct = options.name || options.account;
|
||||
var address = yield req.wallet.createNested(acct);
|
||||
send(200, address.toJSON());
|
||||
}));
|
||||
|
||||
// Wallet Balance
|
||||
this.get('/wallet/:id/balance', con(function* (req, res, send, next) {
|
||||
var account = req.options.account;
|
||||
var balance = yield req.wallet.getBalance(account);
|
||||
var options = req.options;
|
||||
var acct = options.name || options.account;
|
||||
var balance = yield req.wallet.getBalance(acct);
|
||||
|
||||
if (!balance)
|
||||
return send(404);
|
||||
@ -744,18 +880,61 @@ HTTPServer.prototype._init = function _init() {
|
||||
|
||||
// Wallet UTXOs
|
||||
this.get('/wallet/:id/coin', con(function* (req, res, send, next) {
|
||||
var account = req.options.account;
|
||||
var coins = yield req.wallet.getCoins(account);
|
||||
var options = req.options;
|
||||
var acct = options.name || options.account;
|
||||
var coins = yield req.wallet.getCoins(acct);
|
||||
|
||||
sortCoins(coins);
|
||||
|
||||
send(200, coins.map(function(coin) {
|
||||
return coin.toJSON();
|
||||
}));
|
||||
}));
|
||||
|
||||
// Locked coins
|
||||
this.get('/wallet/:id/coin/locked', con(function* (req, res, send, next) {
|
||||
var locked = this.wallet.getLocked();
|
||||
send(200, locked.map(function(outpoint) {
|
||||
return outpoint.toJSON();
|
||||
}));
|
||||
}));
|
||||
|
||||
// Lock coin
|
||||
this.put('/wallet/:id/coin/locked', con(function* (req, res, send, next) {
|
||||
var options = req.options.hash;
|
||||
var outpoint;
|
||||
|
||||
enforce(options.hash, 'Hash is required.');
|
||||
enforce(options.index != null, 'Index is required.');
|
||||
|
||||
outpoint = new Outpoint(options.hash, options.index);
|
||||
|
||||
this.wallet.lockCoin(outpoint);
|
||||
}));
|
||||
|
||||
// Unlock coin
|
||||
this.del('/wallet/:id/coin/locked', con(function* (req, res, send, next) {
|
||||
var options = req.options.hash;
|
||||
var outpoint;
|
||||
|
||||
enforce(options.hash, 'Hash is required.');
|
||||
enforce(options.index != null, 'Index is required.');
|
||||
|
||||
outpoint = new Outpoint(options.hash, options.index);
|
||||
|
||||
this.wallet.unlockCoin(outpoint);
|
||||
}));
|
||||
|
||||
// Wallet Coin
|
||||
this.get('/wallet/:id/coin/:hash/:index', con(function* (req, res, send, next) {
|
||||
var hash = req.options.hash;
|
||||
var index = req.options.index;
|
||||
var coin = yield req.wallet.getCoin(hash, index);
|
||||
var coin;
|
||||
|
||||
enforce(hash, 'Hash is required.');
|
||||
enforce(index != null, 'Index is required.');
|
||||
|
||||
coin = yield req.wallet.getCoin(hash, index);
|
||||
|
||||
if (!coin)
|
||||
return send(404);
|
||||
@ -765,9 +944,15 @@ HTTPServer.prototype._init = function _init() {
|
||||
|
||||
// Wallet TXs
|
||||
this.get('/wallet/:id/tx/history', con(function* (req, res, send, next) {
|
||||
var account = req.options.account;
|
||||
var txs = yield req.wallet.getHistory(account);
|
||||
var details = yield req.wallet.toDetails(txs);
|
||||
var options = req.options;
|
||||
var acct = options.name || options.account;
|
||||
var txs = yield req.wallet.getHistory(acct);
|
||||
var details;
|
||||
|
||||
sortTX(txs);
|
||||
|
||||
details = yield req.wallet.toDetails(txs);
|
||||
|
||||
send(200, details.map(function(tx) {
|
||||
return tx.toJSON();
|
||||
}));
|
||||
@ -775,9 +960,15 @@ HTTPServer.prototype._init = function _init() {
|
||||
|
||||
// Wallet Pending TXs
|
||||
this.get('/wallet/:id/tx/unconfirmed', con(function* (req, res, send, next) {
|
||||
var account = req.options.account;
|
||||
var txs = yield req.wallet.getUnconfirmed(account);
|
||||
var details = yield req.wallet.toDetails(txs);
|
||||
var options = req.options;
|
||||
var acct = options.name || options.account;
|
||||
var txs = yield req.wallet.getUnconfirmed(acct);
|
||||
var details;
|
||||
|
||||
sortTX(txs);
|
||||
|
||||
details = yield req.wallet.toDetails(txs);
|
||||
|
||||
send(200, details.map(function(tx) {
|
||||
return tx.toJSON();
|
||||
}));
|
||||
@ -785,9 +976,9 @@ HTTPServer.prototype._init = function _init() {
|
||||
|
||||
// Wallet TXs within time range
|
||||
this.get('/wallet/:id/tx/range', con(function* (req, res, send, next) {
|
||||
var account = req.options.account;
|
||||
var options = req.options;
|
||||
var txs = yield req.wallet.getRange(account, options);
|
||||
var acct = options.name || options.account;
|
||||
var txs = yield req.wallet.getRange(acct, options);
|
||||
var details = yield req.wallet.toDetails(txs);
|
||||
send(200, details.map(function(tx) {
|
||||
return tx.toJSON();
|
||||
@ -796,9 +987,10 @@ HTTPServer.prototype._init = function _init() {
|
||||
|
||||
// Last Wallet TXs
|
||||
this.get('/wallet/:id/tx/last', con(function* (req, res, send, next) {
|
||||
var account = req.options.account;
|
||||
var limit = req.options.limit;
|
||||
var txs = yield req.wallet.getLast(account, limit);
|
||||
var options = req.options;
|
||||
var acct = options.name || options.account;
|
||||
var limit = options.limit;
|
||||
var txs = yield req.wallet.getLast(acct, limit);
|
||||
var details = yield req.wallet.toDetails(txs);
|
||||
send(200, details.map(function(tx) {
|
||||
return tx.toJSON();
|
||||
@ -808,13 +1000,17 @@ HTTPServer.prototype._init = function _init() {
|
||||
// Wallet TX
|
||||
this.get('/wallet/:id/tx/:hash', con(function* (req, res, send, next) {
|
||||
var hash = req.options.hash;
|
||||
var tx = yield req.wallet.getTX(hash);
|
||||
var details;
|
||||
var tx, details;
|
||||
|
||||
enforce(hash, 'Hash is required.');
|
||||
|
||||
tx = yield req.wallet.getTX(hash);
|
||||
|
||||
if (!tx)
|
||||
return send(404);
|
||||
|
||||
details = yield req.wallet.toDetails(tx);
|
||||
|
||||
send(200, details.toJSON());
|
||||
}));
|
||||
|
||||
@ -1373,6 +1569,30 @@ function softMerge(a, b, soft) {
|
||||
}
|
||||
}
|
||||
|
||||
function enforce(value, msg) {
|
||||
var err;
|
||||
|
||||
if (!value) {
|
||||
err = new Error(msg);
|
||||
err.statusCode = 400;
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
function sortTX(txs) {
|
||||
return txs.sort(function(a, b) {
|
||||
return a.ps - b.ps;
|
||||
});
|
||||
}
|
||||
|
||||
function sortCoins(coins) {
|
||||
return coins.sort(function(a, b) {
|
||||
a = a.height === -1 ? 0x7fffffff : a.height;
|
||||
b = b.height === -1 ? 0x7fffffff : b.height;
|
||||
return a - b;
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose
|
||||
*/
|
||||
|
||||
@ -309,6 +309,90 @@ HTTPWallet.prototype.retoken = co(function* retoken(passphrase) {
|
||||
return token;
|
||||
});
|
||||
|
||||
/**
|
||||
* Import private key.
|
||||
* @param {Number|String} account
|
||||
* @param {String} key
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
HTTPWallet.prototype.importPrivate = function importPrivate(id, account, key) {
|
||||
return this.client.importPrivate(this.id, account, key);
|
||||
};
|
||||
|
||||
/**
|
||||
* Import public key.
|
||||
* @param {Number|String} account
|
||||
* @param {String} key
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
HTTPWallet.prototype.importPublic = function importPublic(id, account, key) {
|
||||
return this.client.importPublic(this.id, account, key);
|
||||
};
|
||||
|
||||
/**
|
||||
* Import address.
|
||||
* @param {Number|String} account
|
||||
* @param {String} address
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
HTTPWallet.prototype.importAddress = function importAddress(id, account, address) {
|
||||
return this.client.importAddress(this.id, account, address);
|
||||
};
|
||||
|
||||
/**
|
||||
* Lock a coin.
|
||||
* @param {String} hash
|
||||
* @param {Number} index
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
HTTPWallet.prototype.lockCoin = function lockCoin(id, hash, index) {
|
||||
return this.client.lockCoin(this.id, hash, index);
|
||||
};
|
||||
|
||||
/**
|
||||
* Unlock a coin.
|
||||
* @param {String} hash
|
||||
* @param {Number} index
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
HTTPWallet.prototype.unlockCoin = function unlockCoin(id, hash, index) {
|
||||
return this.client.unlockCoin(this.id, hash, index);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get locked coins.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
HTTPWallet.prototype.getLocked = function getLocked(id) {
|
||||
return this.client.getLocked(this.id);
|
||||
};
|
||||
|
||||
/**
|
||||
* Lock wallet.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
HTTPWallet.prototype.lock = function lock(id) {
|
||||
return this.client.lock(this.id);
|
||||
};
|
||||
|
||||
/**
|
||||
* Unlock wallet.
|
||||
* @param {String} passphrase
|
||||
* @param {Number} timeout
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
HTTPWallet.prototype.unlock = function unlock(id, passphrase, timeout) {
|
||||
return this.client.unlock(this.id, passphrase, timeout);
|
||||
};
|
||||
|
||||
/*
|
||||
* Expose
|
||||
*/
|
||||
|
||||
Loading…
Reference in New Issue
Block a user