Merge pull request #213 from pnagurny/feature/https

Add https to web service
This commit is contained in:
Braydon Fuller 2015-09-10 11:16:07 -04:00
commit c5dfc26b28
7 changed files with 141 additions and 33 deletions

View File

@ -32,6 +32,8 @@ function Node(config) {
$.checkState(config.datadir, 'Node config expects "datadir"');
this.datadir = config.datadir;
this.port = config.port;
this.https = config.https;
this.httpsOptions = config.httpsOptions;
this._setNetwork(config);

View File

@ -25,8 +25,6 @@ var BASE_PACKAGE = {
}
};
var BASE_BITCOIN_CONFIG = 'whitelist=127.0.0.1\n' + 'txindex=1\n';
/**
* Will create a directory and bitcoin.conf file for Bitcoin.
* @param {String} dataDir - The absolute path
@ -38,12 +36,9 @@ function createBitcoinDirectory(datadir, done) {
throw err;
}
try {
fs.writeFileSync(datadir + '/bitcoin.conf', BASE_BITCOIN_CONFIG);
} catch(e) {
done(e);
}
done();
// Don't create the configuration yet
});
}

View File

@ -46,7 +46,13 @@ Bitcoin.prototype._loadConfiguration = function() {
}
if (!fs.existsSync(configPath)) {
fs.writeFileSync(configPath, Bitcoin.DEFAULT_CONFIG);
var defaultConfig = Bitcoin.DEFAULT_CONFIG;
if(this.node.https && this.node.httpsOptions) {
defaultConfig += 'rpcssl=1\n';
defaultConfig += 'rpcsslprivatekeyfile=' + this.node.httpsOptions.key + '\n';
defaultConfig += 'rpcsslcertificatechainfile=' + this.node.httpsOptions.cert + '\n';
}
fs.writeFileSync(configPath, defaultConfig);
}
var file = fs.readFileSync(configPath);

View File

@ -1,6 +1,7 @@
'use strict';
var http = require('http');
var https = require('https');
var express = require('express');
var bodyParser = require('body-parser');
var socketio = require('socket.io');
@ -8,10 +9,13 @@ var BaseService = require('../service');
var inherits = require('util').inherits;
var index = require('../');
var log = index.log;
var fs = require('fs');
var WebService = function(options) {
var self = this;
this.node = options.node;
this.https = options.https || this.node.https;
this.httpsOptions = options.httpsOptions || this.node.httpsOptions;
this.port = options.port || this.node.port || 3456;
this.node.on('ready', function() {
@ -31,7 +35,12 @@ WebService.prototype.start = function(callback) {
this.app = express();
this.app.use(bodyParser.json());
this.server = http.createServer(this.app);
if(this.https) {
this.transformHttpsOptions();
this.server = https.createServer(this.httpsOptions, this.app);
} else {
this.server = http.createServer(this.app);
}
this.io = socketio.listen(this.server);
this.io.on('connection', this.socketHandler.bind(this));
@ -186,4 +195,15 @@ WebService.prototype.socketMessageHandler = function(message, socketCallback) {
}
};
WebService.prototype.transformHttpsOptions = function() {
if(!this.httpsOptions || !this.httpsOptions.key || !this.httpsOptions.cert) {
throw new Error('Missing https options');
}
this.httpsOptions = {
key: fs.readFileSync(this.httpsOptions.key),
cert: fs.readFileSync(this.httpsOptions.cert)
};
};
module.exports = WebService;

View File

@ -70,11 +70,9 @@ describe('#create', function() {
var configPath = testDir + '/mynode/bitcore-node.json';
var packagePath = testDir + '/mynode/package.json';
var bitcoinConfig = testDir + '/mynode/data/bitcoin.conf';
should.equal(fs.existsSync(configPath), true);
should.equal(fs.existsSync(packagePath), true);
should.equal(fs.existsSync(bitcoinConfig), true);
var config = JSON.parse(fs.readFileSync(configPath));
config.services.should.deep.equal(['bitcoind', 'db', 'address', 'web']);
@ -103,26 +101,6 @@ describe('#create', function() {
});
it('will not create bitcoin.conf if it already exists', function() {
create({
cwd: testDir,
dirname: 'mynode2',
name: 'My Node 2',
isGlobal: false,
datadir: '../.bitcoin'
}, function(err) {
if (err) {
throw err;
}
var bitcoinConfig = testDir + '/.bitcoin/bitcoin.conf';
should.equal(fs.existsSync(bitcoinConfig), false);
});
});
it('will not create a package.json if globally installed', function() {
create({

View File

@ -75,6 +75,36 @@ describe('Bitcoin Service', function() {
bitcoind._loadConfiguration({datadir: './test'});
}).should.throw('Txindex option');
});
it('should set https options if node https options are set', function() {
var writeFileSync = function(path, config) {
config.should.equal('whitelist=127.0.0.1\ntxindex=1\nrpcssl=1\nrpcsslprivatekeyfile=key.pem\nrpcsslcertificatechainfile=cert.pem\n');
};
var TestBitcoin = proxyquire('../../lib/services/bitcoind', {
fs: {
writeFileSync: writeFileSync,
readFileSync: readFileSync,
existsSync: sinon.stub().returns(false)
},
mkdirp: {
sync: sinon.stub()
}
});
var config = {
node: {
datadir: 'testdir',
network: {
name: 'regtest'
},
https: true,
httpsOptions: {
key: 'key.pem',
cert: 'cert.pem'
}
}
};
var bitcoind = new TestBitcoin(config);
bitcoind._loadConfiguration({datadir: process.env.HOME + '/.bitcoin'});
});
describe('reindex', function() {
var log = require('../../lib/').log;
var stub;

View File

@ -2,17 +2,64 @@
var should = require('chai').should();
var sinon = require('sinon');
var WebService = require('../../lib/services/web');
var EventEmitter = require('events').EventEmitter;
var proxyquire = require('proxyquire');
var httpStub = {
createServer: sinon.spy()
};
var httpsStub = {
createServer: sinon.spy()
};
var fsStub = {
readFileSync: function(arg1) {
return arg1 + '-buffer';
}
};
var fakeSocketListener = new EventEmitter();
var fakeSocket = new EventEmitter();
fakeSocket.on('test/event1', function(data) {
data.should.equal('testdata');
done();
});
fakeSocketListener.emit('connection', fakeSocket);
fakeSocket.emit('subscribe', 'test/event1');
var WebService = proxyquire('../../lib/services/web', {http: httpStub, https: httpsStub, fs: fsStub});
describe('WebService', function() {
var defaultNode = new EventEmitter();
describe('#start', function() {
it('should call the callback with no error', function(done) {
beforeEach(function() {
httpStub.createServer.reset();
httpsStub.createServer.reset();
});
it('should create an http server if no options are specified and node is not configured for https', function(done) {
var web = new WebService({node: defaultNode});
web.deriveHttpsOptions = sinon.spy();
web.start(function(err) {
should.not.exist(err);
httpStub.createServer.called.should.equal(true);
done();
});
});
it('should create an https server if no options are specified and node is configured for https', function(done) {
var node = new EventEmitter();
node.https = true;
var web = new WebService({node: node});
web.transformHttpsOptions = sinon.spy();
web.start(function(err) {
should.not.exist(err);
httpsStub.createServer.called.should.equal(true);
done();
});
});
@ -291,4 +338,34 @@ describe('WebService', function() {
});
});
describe('#deriveHttpsOptions', function() {
it('should read key and cert from files specified', function() {
var web = new WebService({
node: defaultNode,
https: true,
httpsOptions: {
key: 'key',
cert: 'cert'
}
});
web.transformHttpsOptions();
web.httpsOptions.key.should.equal('key-buffer');
web.httpsOptions.cert.should.equal('cert-buffer');
});
it('should throw an error if https is specified but key or cert is not specified', function() {
var web = new WebService({
node: defaultNode,
https: true,
httpsOptions: {
key: 'key'
}
});
(function() {
web.transformHttpsOptions();
}).should.throw('Missing https options');
});
});
});