http: better api key handling.
This commit is contained in:
parent
2b630ad99c
commit
30b7421ea7
@ -43,15 +43,6 @@ function HTTPClient(options) {
|
|||||||
this.auth = options.auth;
|
this.auth = options.auth;
|
||||||
this.rpc = new RPCClient(options);
|
this.rpc = new RPCClient(options);
|
||||||
|
|
||||||
if (this.apiKey) {
|
|
||||||
if (typeof this.apiKey === 'string') {
|
|
||||||
assert(utils.isHex(this.apiKey), 'API key must be a hex string.');
|
|
||||||
this.apiKey = new Buffer(this.apiKey, 'hex');
|
|
||||||
}
|
|
||||||
assert(Buffer.isBuffer(this.apiKey));
|
|
||||||
assert(this.apiKey.length === 32, 'API key must be 32 bytes.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open automatically.
|
// Open automatically.
|
||||||
this.open();
|
this.open();
|
||||||
}
|
}
|
||||||
@ -125,8 +116,7 @@ HTTPClient.prototype._open = function _open(callback) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.socket.on('connect', function() {
|
this.socket.on('connect', function() {
|
||||||
var apiKey = self.apiKey ? self.apiKey.toString('hex') : null;
|
self.socket.emit('auth', self.apiKey, function(err) {
|
||||||
self.socket.emit('auth', apiKey, function(err) {
|
|
||||||
if (err)
|
if (err)
|
||||||
return callback(new Error(err.error));
|
return callback(new Error(err.error));
|
||||||
callback();
|
callback();
|
||||||
@ -208,19 +198,15 @@ HTTPClient.prototype._request = function _request(method, endpoint, json, callba
|
|||||||
json = null;
|
json = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json && method === 'get') {
|
if (this.token) {
|
||||||
query = json;
|
if (!json)
|
||||||
json = true;
|
json = {};
|
||||||
|
json.token = this.token;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.apiKey) {
|
if (json && method === 'get') {
|
||||||
if (method === 'get') {
|
query = json;
|
||||||
query = query || {};
|
json = null;
|
||||||
query.apiKey = this.apiKey.toString('hex');
|
|
||||||
} else {
|
|
||||||
json = json || {};
|
|
||||||
json.apiKey = this.apiKey.toString('hex');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
request({
|
request({
|
||||||
@ -228,7 +214,10 @@ HTTPClient.prototype._request = function _request(method, endpoint, json, callba
|
|||||||
uri: this.uri + endpoint,
|
uri: this.uri + endpoint,
|
||||||
query: query,
|
query: query,
|
||||||
json: json,
|
json: json,
|
||||||
auth: this.auth,
|
auth: {
|
||||||
|
username: 'bitcoinrpc',
|
||||||
|
password: this.apiKey || ''
|
||||||
|
},
|
||||||
expect: 'json'
|
expect: 'json'
|
||||||
}, function(err, res, body) {
|
}, function(err, res, body) {
|
||||||
if (err)
|
if (err)
|
||||||
@ -572,9 +561,7 @@ HTTPClient.prototype.getBlock = function getBlock(hash, callback) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
HTTPClient.prototype.broadcast = function broadcast(tx, callback) {
|
HTTPClient.prototype.broadcast = function broadcast(tx, callback) {
|
||||||
var body = { tx: tx.toRaw().toString('hex') };
|
var body = { tx: toHex(tx) };
|
||||||
|
|
||||||
callback = utils.ensure(callback);
|
|
||||||
|
|
||||||
return this._post('/broadcast', body, callback);
|
return this._post('/broadcast', body, callback);
|
||||||
};
|
};
|
||||||
@ -598,15 +585,11 @@ HTTPClient.prototype.walletSend = function walletSend(id, options, callback) {
|
|||||||
options.outputs = options.outputs.map(function(output) {
|
options.outputs = options.outputs.map(function(output) {
|
||||||
return {
|
return {
|
||||||
value: utils.btc(output.value),
|
value: utils.btc(output.value),
|
||||||
address: output.address && output.address.toBase58
|
address: output.address,
|
||||||
? output.address.toBase58()
|
script: toHex(output.script)
|
||||||
: output.address,
|
|
||||||
script: output.script ? output.script.toRaw().toString('hex') : null
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
callback = utils.ensure(callback);
|
|
||||||
|
|
||||||
return this._post('/wallet/' + id + '/send', options, callback);
|
return this._post('/wallet/' + id + '/send', options, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -619,8 +602,6 @@ HTTPClient.prototype.walletSend = function walletSend(id, options, callback) {
|
|||||||
HTTPClient.prototype.walletRetoken = function walletRetoken(id, passphrase, callback) {
|
HTTPClient.prototype.walletRetoken = function walletRetoken(id, passphrase, callback) {
|
||||||
var options = { passphrase: passphrase };
|
var options = { passphrase: passphrase };
|
||||||
|
|
||||||
callback = utils.ensure(callback);
|
|
||||||
|
|
||||||
return this._post('/wallet/' + id + '/retoken', options, function(err, body) {
|
return this._post('/wallet/' + id + '/retoken', options, function(err, body) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
@ -639,8 +620,6 @@ HTTPClient.prototype.walletRetoken = function walletRetoken(id, passphrase, call
|
|||||||
HTTPClient.prototype.walletSetPassphrase = function walletSetPassphrase(id, old, new_, callback) {
|
HTTPClient.prototype.walletSetPassphrase = function walletSetPassphrase(id, old, new_, callback) {
|
||||||
var options = { old: old, passphrase: new_ };
|
var options = { old: old, passphrase: new_ };
|
||||||
|
|
||||||
callback = utils.ensure(callback);
|
|
||||||
|
|
||||||
return this._post('/wallet/' + id + '/passphrase', options, callback);
|
return this._post('/wallet/' + id + '/passphrase', options, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -653,7 +632,6 @@ HTTPClient.prototype.walletSetPassphrase = function walletSetPassphrase(id, old,
|
|||||||
|
|
||||||
HTTPClient.prototype.walletCreate = function walletCreate(id, options, callback) {
|
HTTPClient.prototype.walletCreate = function walletCreate(id, options, callback) {
|
||||||
options = utils.merge({}, options);
|
options = utils.merge({}, options);
|
||||||
options.outputs = options.outputs || [];
|
|
||||||
|
|
||||||
if (options.rate)
|
if (options.rate)
|
||||||
options.rate = utils.btc(options.rate);
|
options.rate = utils.btc(options.rate);
|
||||||
@ -661,15 +639,11 @@ HTTPClient.prototype.walletCreate = function walletCreate(id, options, callback)
|
|||||||
options.outputs = options.outputs.map(function(output) {
|
options.outputs = options.outputs.map(function(output) {
|
||||||
return {
|
return {
|
||||||
value: utils.btc(output.value),
|
value: utils.btc(output.value),
|
||||||
address: output.address && output.address.toBase58
|
address: output.address,
|
||||||
? output.address.toBase58()
|
script: toHex(output.script)
|
||||||
: output.address,
|
|
||||||
script: output.script ? output.script.toRaw().toString('hex') : null
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
callback = utils.ensure(callback);
|
|
||||||
|
|
||||||
return this._post('/wallet/' + id + '/create', options, callback);
|
return this._post('/wallet/' + id + '/create', options, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -686,14 +660,11 @@ HTTPClient.prototype.walletSign = function walletCreate(id, tx, options, callbac
|
|||||||
|
|
||||||
if (typeof options === 'function') {
|
if (typeof options === 'function') {
|
||||||
callback = options;
|
callback = options;
|
||||||
options = null;
|
options = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
body = utils.merge({}, options || {}, {
|
body = utils.merge({}, options);
|
||||||
tx: tx.toRaw().toString('hex')
|
body.tx = toHex(tx);
|
||||||
});
|
|
||||||
|
|
||||||
callback = utils.ensure(callback);
|
|
||||||
|
|
||||||
return this._post('/wallet/' + id + '/sign', body, callback);
|
return this._post('/wallet/' + id + '/sign', body, callback);
|
||||||
};
|
};
|
||||||
@ -705,10 +676,7 @@ HTTPClient.prototype.walletSign = function walletCreate(id, tx, options, callbac
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
HTTPClient.prototype.walletFill = function walletFill(tx, callback) {
|
HTTPClient.prototype.walletFill = function walletFill(tx, callback) {
|
||||||
var body = { tx: tx.toRaw().toString('hex') };
|
var body = { tx: toHex(tx) };
|
||||||
|
|
||||||
callback = utils.ensure(callback);
|
|
||||||
|
|
||||||
return this._post('/wallet/_/fill', body, callback);
|
return this._post('/wallet/_/fill', body, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -735,8 +703,6 @@ HTTPClient.prototype.walletZap = function walletZap(id, account, age, callback)
|
|||||||
|
|
||||||
assert(utils.isNumber(age));
|
assert(utils.isNumber(age));
|
||||||
|
|
||||||
callback = utils.ensure(callback);
|
|
||||||
|
|
||||||
return this._post('/wallet/' + id + '/zap', body, callback);
|
return this._post('/wallet/' + id + '/zap', body, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -761,8 +727,6 @@ HTTPClient.prototype.addKey = function addKey(id, account, key, callback) {
|
|||||||
key = key.xpubkey || key;
|
key = key.xpubkey || key;
|
||||||
options = { account: account, key: key };
|
options = { account: account, key: key };
|
||||||
|
|
||||||
callback = utils.ensure(callback);
|
|
||||||
|
|
||||||
return this._put('/wallet/' + id + '/key', options, callback);
|
return this._put('/wallet/' + id + '/key', options, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -787,8 +751,6 @@ HTTPClient.prototype.removeKey = function removeKey(id, account, key, callback)
|
|||||||
key = key.xpubkey || key;
|
key = key.xpubkey || key;
|
||||||
options = { account: account, key: key };
|
options = { account: account, key: key };
|
||||||
|
|
||||||
callback = utils.ensure(callback);
|
|
||||||
|
|
||||||
return this._del('/wallet/' + id + '/key', options, callback);
|
return this._del('/wallet/' + id + '/key', options, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -848,6 +810,23 @@ HTTPClient.prototype.getInfo = function getInfo(callback) {
|
|||||||
return this._get('/', callback);
|
return this._get('/', callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helpers
|
||||||
|
*/
|
||||||
|
|
||||||
|
function toHex(obj) {
|
||||||
|
if (!obj)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (obj.toRaw)
|
||||||
|
obj = obj.toRaw();
|
||||||
|
|
||||||
|
if (Buffer.isBuffer(obj))
|
||||||
|
obj = obj.toString('hex');
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expose
|
* Expose
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -35,23 +35,13 @@ function RPCClient(options) {
|
|||||||
this.uri = options.uri || 'http://localhost:' + this.network.rpcPort;
|
this.uri = options.uri || 'http://localhost:' + this.network.rpcPort;
|
||||||
this.apiKey = options.apiKey;
|
this.apiKey = options.apiKey;
|
||||||
this.id = 0;
|
this.id = 0;
|
||||||
|
|
||||||
if (this.apiKey) {
|
|
||||||
if (typeof this.apiKey === 'string') {
|
|
||||||
assert(utils.isHex(this.apiKey), 'API key must be a hex string.');
|
|
||||||
this.apiKey = new Buffer(this.apiKey, 'hex');
|
|
||||||
}
|
|
||||||
assert(Buffer.isBuffer(this.apiKey));
|
|
||||||
assert(this.apiKey.length === 32, 'API key must be 32 bytes.');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make an http request to endpoint.
|
* Make a json rpc request.
|
||||||
* @private
|
* @private
|
||||||
* @param {String} method
|
* @param {String} method - RPC method name.
|
||||||
* @param {String} endpoint - Path.
|
* @param {Array} params - RPC parameters.
|
||||||
* @param {Object} json - Body or query depending on method.
|
|
||||||
* @param {Function} callback - Returns [Error, Object?].
|
* @param {Function} callback - Returns [Error, Object?].
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -68,7 +58,7 @@ RPCClient.prototype.call = function call(method, params, callback) {
|
|||||||
},
|
},
|
||||||
auth: {
|
auth: {
|
||||||
username: 'bitcoinrpc',
|
username: 'bitcoinrpc',
|
||||||
password: this.apiKey ? this.apiKey.toString('hex') : ''
|
password: this.apiKey || ''
|
||||||
},
|
},
|
||||||
expect: 'json'
|
expect: 'json'
|
||||||
}, function(err, res, body) {
|
}, function(err, res, body) {
|
||||||
|
|||||||
@ -49,21 +49,21 @@ function HTTPServer(options) {
|
|||||||
this.logger = options.logger || this.node.logger;
|
this.logger = options.logger || this.node.logger;
|
||||||
this.loaded = false;
|
this.loaded = false;
|
||||||
this.apiKey = options.apiKey;
|
this.apiKey = options.apiKey;
|
||||||
|
this.apiHash = null;
|
||||||
this.rpc = null;
|
this.rpc = null;
|
||||||
|
|
||||||
if (this.apiKey) {
|
if (!this.apiKey)
|
||||||
if (typeof this.apiKey === 'string') {
|
this.apiKey = utils.toBase58(bcoin.ec.random(20));
|
||||||
assert(utils.isHex(this.apiKey), 'API key must be a hex string.');
|
|
||||||
this.apiKey = new Buffer(this.apiKey, 'hex');
|
|
||||||
}
|
|
||||||
assert(Buffer.isBuffer(this.apiKey));
|
|
||||||
assert(this.apiKey.length === 32, 'API key must be 32 bytes.');
|
|
||||||
} else {
|
|
||||||
this.apiKey = bcoin.ec.random(32);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.noAuth)
|
assert(typeof this.apiKey === 'string', 'API key must be a string.');
|
||||||
|
assert(this.apiKey.length <= 200, 'API key must be under 200 bytes.');
|
||||||
|
|
||||||
|
this.apiHash = hash256(this.apiKey);
|
||||||
|
|
||||||
|
if (options.noAuth) {
|
||||||
this.apiKey = null;
|
this.apiKey = null;
|
||||||
|
this.apiHash = null;
|
||||||
|
}
|
||||||
|
|
||||||
options.sockets = true;
|
options.sockets = true;
|
||||||
|
|
||||||
@ -124,7 +124,6 @@ HTTPServer.prototype._init = function _init() {
|
|||||||
|
|
||||||
auth = new Buffer(parts[1], 'base64').toString('utf8');
|
auth = new Buffer(parts[1], 'base64').toString('utf8');
|
||||||
parts = auth.split(':');
|
parts = auth.split(':');
|
||||||
assert(parts.length >= 2, 'Invalid auth token.');
|
|
||||||
|
|
||||||
req.username = parts.shift();
|
req.username = parts.shift();
|
||||||
req.password = parts.join(':');
|
req.password = parts.join(':');
|
||||||
@ -132,17 +131,37 @@ HTTPServer.prototype._init = function _init() {
|
|||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.use(function(req, res, next, send) {
|
||||||
|
if (!self.apiHash)
|
||||||
|
return next();
|
||||||
|
|
||||||
|
if (utils.ccmp(hash256(req.password), self.apiHash))
|
||||||
|
return next();
|
||||||
|
|
||||||
|
res.setHeader('WWW-Authenticate', 'Basic realm="node"');
|
||||||
|
|
||||||
|
if (req.method === 'POST'
|
||||||
|
&& req.pathname === '/') {
|
||||||
|
send(401, {
|
||||||
|
result: null,
|
||||||
|
error: {
|
||||||
|
message: 'Bad auth.',
|
||||||
|
code: 1
|
||||||
|
},
|
||||||
|
id: req.body.id
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
send(401, { error: 'Bad API key.' });
|
||||||
|
});
|
||||||
|
|
||||||
this.use(function(req, res, next, send) {
|
this.use(function(req, res, next, send) {
|
||||||
var params, options;
|
var params, options;
|
||||||
|
|
||||||
if (req.method === 'POST'
|
if (req.method === 'POST'
|
||||||
&& req.pathname === '/') {
|
&& req.pathname === '/') {
|
||||||
req.options = {};
|
req.options = {};
|
||||||
if (self.apiKey) {
|
|
||||||
assert(utils.isHex(req.password), 'API key must be a hex string.');
|
|
||||||
assert(req.password.length === 64, 'API key must be 32 bytes.');
|
|
||||||
req.password = new Buffer(req.password, 'hex');
|
|
||||||
}
|
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,19 +261,10 @@ HTTPServer.prototype._init = function _init() {
|
|||||||
if (params.passphrase)
|
if (params.passphrase)
|
||||||
options.passphrase = params.passphrase;
|
options.passphrase = params.passphrase;
|
||||||
|
|
||||||
if (req.password) {
|
if (params.token) {
|
||||||
assert(utils.isHex(req.password), 'API key must be a hex string.');
|
assert(utils.isHex(params.token), 'API key must be a hex string.');
|
||||||
assert(req.password.length === 64, 'API key must be 32 bytes.');
|
assert(params.token.length === 64, 'API key must be 32 bytes.');
|
||||||
options.token = new Buffer(req.password, 'hex');
|
options.token = new Buffer(params.token, 'hex');
|
||||||
}
|
|
||||||
|
|
||||||
if (req.headers['x-bcoin-api-key'])
|
|
||||||
params.apiKey = req.headers['x-bcoin-api-key'];
|
|
||||||
|
|
||||||
if (params.apiKey) {
|
|
||||||
assert(utils.isHex(params.apiKey), 'API key must be a hex string.');
|
|
||||||
assert(params.apiKey.length === 64, 'API key must be 32 bytes.');
|
|
||||||
options.apiKey = new Buffer(params.apiKey, 'hex');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
req.options = options;
|
req.options = options;
|
||||||
@ -263,18 +273,6 @@ HTTPServer.prototype._init = function _init() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.use(function(req, res, next, send) {
|
this.use(function(req, res, next, send) {
|
||||||
if (req.method === 'POST'
|
|
||||||
&& req.pathname === '/') {
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.apiKey) {
|
|
||||||
if (!utils.ccmp(req.options.apiKey, self.apiKey)) {
|
|
||||||
send(403, { error: 'Forbidden.' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req.path.length < 2 || req.path[0] !== 'wallet')
|
if (req.path.length < 2 || req.path[0] !== 'wallet')
|
||||||
return next();
|
return next();
|
||||||
|
|
||||||
@ -296,8 +294,7 @@ HTTPServer.prototype._init = function _init() {
|
|||||||
if (err) {
|
if (err) {
|
||||||
self.logger.info('Auth failure for %s: %s.',
|
self.logger.info('Auth failure for %s: %s.',
|
||||||
req.options.id, err.message);
|
req.options.id, err.message);
|
||||||
res.setHeader('WWW-Authenticate', 'Basic realm="wallet"');
|
send(403, { error: err.message });
|
||||||
send(401, { error: err.message });
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,21 +320,6 @@ HTTPServer.prototype._init = function _init() {
|
|||||||
if (!(req.body.method && req.body.params))
|
if (!(req.body.method && req.body.params))
|
||||||
return next(new Error('Method not found.'));
|
return next(new Error('Method not found.'));
|
||||||
|
|
||||||
if (self.apiKey) {
|
|
||||||
if (!utils.ccmp(req.password, self.apiKey)) {
|
|
||||||
res.setHeader('WWW-Authenticate', 'Basic realm="rpc"');
|
|
||||||
send(401, {
|
|
||||||
result: null,
|
|
||||||
error: {
|
|
||||||
message: 'Bad auth.',
|
|
||||||
code: 1
|
|
||||||
},
|
|
||||||
id: req.body.id
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!self.rpc) {
|
if (!self.rpc) {
|
||||||
RPC = require('./rpc');
|
RPC = require('./rpc');
|
||||||
self.rpc = new RPC(self.node);
|
self.rpc = new RPC(self.node);
|
||||||
@ -548,10 +530,7 @@ HTTPServer.prototype._init = function _init() {
|
|||||||
if (err)
|
if (err)
|
||||||
return next(err);
|
return next(err);
|
||||||
|
|
||||||
json = wallet.toJSON();
|
send(200, wallet.toJSON());
|
||||||
wallet.destroy();
|
|
||||||
|
|
||||||
send(200, json);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -561,9 +540,6 @@ HTTPServer.prototype._init = function _init() {
|
|||||||
if (err)
|
if (err)
|
||||||
return next(err);
|
return next(err);
|
||||||
|
|
||||||
if (accounts.length === 0)
|
|
||||||
return send(404);
|
|
||||||
|
|
||||||
send(200, accounts);
|
send(200, accounts);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -759,9 +735,6 @@ HTTPServer.prototype._init = function _init() {
|
|||||||
if (err)
|
if (err)
|
||||||
return next(err);
|
return next(err);
|
||||||
|
|
||||||
if (!txs.length)
|
|
||||||
return send(404);
|
|
||||||
|
|
||||||
req.wallet.toDetails(txs, function(err, txs) {
|
req.wallet.toDetails(txs, function(err, txs) {
|
||||||
if (err)
|
if (err)
|
||||||
return next(err);
|
return next(err);
|
||||||
@ -780,9 +753,6 @@ HTTPServer.prototype._init = function _init() {
|
|||||||
if (err)
|
if (err)
|
||||||
return next(err);
|
return next(err);
|
||||||
|
|
||||||
if (!txs.length)
|
|
||||||
return send(404);
|
|
||||||
|
|
||||||
req.wallet.toDetails(txs, function(err, txs) {
|
req.wallet.toDetails(txs, function(err, txs) {
|
||||||
if (err)
|
if (err)
|
||||||
return next(err);
|
return next(err);
|
||||||
@ -802,9 +772,6 @@ HTTPServer.prototype._init = function _init() {
|
|||||||
if (err)
|
if (err)
|
||||||
return next(err);
|
return next(err);
|
||||||
|
|
||||||
if (!txs.length)
|
|
||||||
return send(404);
|
|
||||||
|
|
||||||
req.wallet.toDetails(txs, function(err, txs) {
|
req.wallet.toDetails(txs, function(err, txs) {
|
||||||
if (err)
|
if (err)
|
||||||
return next(err);
|
return next(err);
|
||||||
@ -816,17 +783,14 @@ HTTPServer.prototype._init = function _init() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Wallet TXs within time range
|
// Last Wallet TXs
|
||||||
this.get('/wallet/:id/tx/last', function(req, res, next, send) {
|
this.get('/wallet/:id/tx/last', function(req, res, next, send) {
|
||||||
var account = req.options.account;
|
var account = req.options.account;
|
||||||
var limit = req.options.limit;
|
var limit = req.options.limit;
|
||||||
req.wallet.getRange(account, limit, function(err, txs) {
|
req.wallet.getLast(account, limit, function(err, txs) {
|
||||||
if (err)
|
if (err)
|
||||||
return next(err);
|
return next(err);
|
||||||
|
|
||||||
if (!txs.length)
|
|
||||||
return send(404);
|
|
||||||
|
|
||||||
req.wallet.toDetails(txs, function(err, txs) {
|
req.wallet.toDetails(txs, function(err, txs) {
|
||||||
if (err)
|
if (err)
|
||||||
return next(err);
|
return next(err);
|
||||||
@ -885,19 +849,14 @@ HTTPServer.prototype._initIO = function _initIO() {
|
|||||||
socket.on('auth', function(apiKey, callback) {
|
socket.on('auth', function(apiKey, callback) {
|
||||||
callback = utils.ensure(callback);
|
callback = utils.ensure(callback);
|
||||||
|
|
||||||
if (!self.apiKey) {
|
if (!self.apiHash) {
|
||||||
self.logger.info('Successful auth.');
|
self.logger.info('Successful auth.');
|
||||||
socket.bcoin.stopTimeout();
|
socket.bcoin.stopTimeout();
|
||||||
self.emit('websocket', socket);
|
self.emit('websocket', socket);
|
||||||
return callback();
|
return callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!utils.isHex(apiKey))
|
if (!utils.ccmp(hash256(apiKey), self.apiHash))
|
||||||
return callback({ error: 'Bad key.' });
|
|
||||||
|
|
||||||
apiKey = new Buffer(apiKey, 'hex');
|
|
||||||
|
|
||||||
if (!utils.ccmp(apiKey, self.apiKey))
|
|
||||||
return callback({ error: 'Bad key.' });
|
return callback({ error: 'Bad key.' });
|
||||||
|
|
||||||
self.logger.info('Successful auth.');
|
self.logger.info('Successful auth.');
|
||||||
@ -990,10 +949,12 @@ HTTPServer.prototype._initIO = function _initIO() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
HTTPServer.prototype.open = function open(callback) {
|
HTTPServer.prototype.open = function open(callback) {
|
||||||
if (this.apiKey)
|
if (this.apiKey) {
|
||||||
this.logger.info('API key: %s', this.apiKey.toString('hex'));
|
this.logger.info('API key: %s', this.apiKey);
|
||||||
else
|
this.apiKey = null;
|
||||||
|
} else if (!this.apiHash) {
|
||||||
this.logger.warning('WARNING: Your http server is open to the world.');
|
this.logger.warning('WARNING: Your http server is open to the world.');
|
||||||
|
}
|
||||||
|
|
||||||
this.server.open(callback);
|
this.server.open(callback);
|
||||||
};
|
};
|
||||||
@ -1103,6 +1064,18 @@ ClientSocket.prototype.destroy = function() {
|
|||||||
this.socket.disconnect();
|
this.socket.disconnect();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helpers
|
||||||
|
*/
|
||||||
|
|
||||||
|
function hash256(data) {
|
||||||
|
if (typeof data !== 'string')
|
||||||
|
return new Buffer(0);
|
||||||
|
if (data.length > 200)
|
||||||
|
return new Buffer(0);
|
||||||
|
return utils.hash256(new Buffer(data, 'utf8'));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expose
|
* Expose
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -91,14 +91,13 @@ HTTPWallet.prototype._init = function _init() {
|
|||||||
HTTPWallet.prototype.open = function open(options, callback) {
|
HTTPWallet.prototype.open = function open(options, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
if (Buffer.isBuffer(options.token))
|
|
||||||
options.token = options.token.toString('hex');
|
|
||||||
|
|
||||||
this.id = options.id;
|
this.id = options.id;
|
||||||
|
|
||||||
if (options.token) {
|
if (options.token) {
|
||||||
this.client.auth = { username: 'x', password: options.token };
|
this.token = options.token;
|
||||||
this.token = new Buffer(options.token, 'hex');
|
if (Buffer.isBuffer(this.token))
|
||||||
|
this.token = this.token.toString('hex');
|
||||||
|
this.client.token = this.token;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.client.open(function(err) {
|
this.client.open(function(err) {
|
||||||
@ -272,6 +271,14 @@ HTTPWallet.prototype.getAccounts = function getAccounts(callback) {
|
|||||||
return this.client.getWalletAccounts(this.id, callback);
|
return this.client.getWalletAccounts(this.id, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Wallet#getAccount
|
||||||
|
*/
|
||||||
|
|
||||||
|
HTTPWallet.prototype.getAccount = function getAccount(options, callback) {
|
||||||
|
return this.client.getWalletAccount(this.id, options, callback);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Wallet#createAccount
|
* @see Wallet#createAccount
|
||||||
*/
|
*/
|
||||||
@ -298,8 +305,8 @@ HTTPWallet.prototype.retoken = function retoken(passphrase, callback) {
|
|||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
self.client.auth = { username: 'x', password: token };
|
self.token = token;
|
||||||
self.token = new Buffer(token, 'hex');
|
self.client.token = token;
|
||||||
|
|
||||||
return callback(null, token);
|
return callback(null, token);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -29,20 +29,19 @@ var dummyInput = {
|
|||||||
|
|
||||||
describe('HTTP', function() {
|
describe('HTTP', function() {
|
||||||
var request = bcoin.http.request;
|
var request = bcoin.http.request;
|
||||||
var apiKey = utils.hash256(new Buffer([]));
|
|
||||||
var w, addr, hash;
|
var w, addr, hash;
|
||||||
|
|
||||||
this.timeout(15000);
|
this.timeout(15000);
|
||||||
|
|
||||||
var node = new bcoin.fullnode({
|
var node = new bcoin.fullnode({
|
||||||
network: 'regtest',
|
network: 'regtest',
|
||||||
apiKey: apiKey,
|
apiKey: 'foo',
|
||||||
walletAuth: true
|
walletAuth: true
|
||||||
});
|
});
|
||||||
|
|
||||||
var wallet = new bcoin.http.wallet({
|
var wallet = new bcoin.http.wallet({
|
||||||
network: 'regtest',
|
network: 'regtest',
|
||||||
apiKey: apiKey
|
apiKey: 'foo'
|
||||||
});
|
});
|
||||||
|
|
||||||
node.on('error', function() {});
|
node.on('error', function() {});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user