Skip to content

Commit

Permalink
Relocate persistent data files into a user profile.
Browse files Browse the repository at this point in the history
These need to be moved out of the gateway tree for data persistence
when using Docker. This will also allow users to easily switch
profiles, if desired.
  • Loading branch information
Mike Stegeman committed Feb 14, 2018
1 parent e389b8b commit 88c58a3
Show file tree
Hide file tree
Showing 21 changed files with 248 additions and 105 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Expand Up @@ -5,9 +5,10 @@
.nyc_output/
/build
OZW_Log.txt
config/local.js
db.sqlite3
node_modules/
static/js/lib/stm_web.min.js
static/uploads/floorplan.svg
static/uploads
zwcfg_0x*.xml
zwscene.xml
12 changes: 7 additions & 5 deletions README.md
Expand Up @@ -118,13 +118,15 @@ $ yarn

Add SSL certificate:

If you don't plan on using Mozilla's provided tunneling service to set up a `*.mozilla-iot.org` domain, you can use your own SSL certificate. The HTTPS server looks for `privatekey.pem` and `certificate.pem`. You can use a real certificate or generate a self-signed one by following the steps below.
If you don't plan on using Mozilla's provided tunneling service to set up a `*.mozilla-iot.org` domain, you can use your own SSL certificate. The HTTPS server looks for `privatekey.pem` and `certificate.pem` in the `ssl` sub-directory of the `userProfile` directory specified in your config. You can use a real certificate or generate a self-signed one by following the steps below.

```
$ mkdir -p ssl
$ openssl genrsa -out ssl/privatekey.pem 2048
$ openssl req -new -sha256 -key ssl/privatekey.pem -out ssl/csr.pem
$ openssl x509 -req -in ssl/csr.pem -signkey ssl/privatekey.pem -out ssl/certificate.pem
$ MOZIOT_HOME="${MOZIOT_HOME:=${HOME}/.mozilla-iot}"
$ SSL_DIR="${MOZIOT_HOME}/ssl"
$ [ ! -d "${SSL_DIR}" ] && mkdir -p "${SSL_DIR}"
$ openssl genrsa -out "${SSL_DIR}/privatekey.pem" 2048
$ openssl req -new -sha256 -key "${SSL_DIR}/privatekey.pem" -out "${SSL_DIR}/csr.pem"
$ openssl x509 -req -in "${SSL_DIR}/csr.pem" -signkey "${SSL_DIR}/privatekey.pem" -out "${SSL_DIR}/certificate.pem"
```

Start the web server:
Expand Down
15 changes: 8 additions & 7 deletions config/default.js
Expand Up @@ -8,13 +8,18 @@

'use strict';

const os = require('os');
const home = os.homedir();

module.exports = {
// Expose CLI
cli: true,

profileDir: `${home}/.mozilla-iot`,

ports: {
https: 4443,
http: 8080
http: 8080,
},
// Whether the gateway is behind port forwarding and should use simplified
// port-free urls
Expand All @@ -25,7 +30,6 @@ module.exports = {
listUrl: 'https://raw.githubusercontent.com/mozilla-iot/addon-list/master/list.json',
},
database: {
filename: './db.sqlite3',
removeBeforeOpen: false,
},
ipc: {
Expand All @@ -43,9 +47,6 @@ module.exports = {
},
},
},
uploads: {
directory: '../static/uploads/' // Directory to store uploads in
},
authentication: {
defaultUser: null,
},
Expand All @@ -55,7 +56,7 @@ module.exports = {
domain: 'mozilla-iot.org',
pagekite_cmd: './pagekite.py',
port: 443,
certemail: 'certificate@mozilla-iot.org'
certemail: 'certificate@mozilla-iot.org',
},
bcryptRounds: 2
bcryptRounds: 2,
};
11 changes: 0 additions & 11 deletions config/test.js
Expand Up @@ -26,15 +26,4 @@ module.exports = {
ipc: {
protocol: 'inproc',
},
settings: {
defaults: {
},
},
uploads: {
directory: '../../static/uploads/' // Directory to store uploads in
},
authentication: {
defaultUser: null,
},
bcryptRounds: 2
};
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -38,6 +38,7 @@
"greenlock": "^2.1.15",
"jsonwebtoken": "^8.1.0",
"le-challenge-dns": "https://github.com/mozilla-iot/le-challenge-dns",
"mkdirp": "^0.5.1",
"mustache-express": "^1.2.5",
"nanomsg": "^3.3.0",
"nocache": "^2.0.0",
Expand Down
4 changes: 3 additions & 1 deletion run-app.sh
@@ -1,5 +1,7 @@
#!/bin/bash

MOZIOT_HOME="${MOZIOT_HOME:=${HOME}/.mozilla-iot}"

run_app() {
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
Expand All @@ -16,4 +18,4 @@ run_app() {
npm start
}

run_app > ${HOME}/mozilla-iot/gateway/run-app.log 2>&1
run_app > "${MOZIOT_HOME}/log/run-app.log" 2>&1
51 changes: 10 additions & 41 deletions src/app.js
Expand Up @@ -7,6 +7,12 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

// Set up the user profile.
const UserProfile = require('./user-profile');
UserProfile.init();
UserProfile.migrate();

// Dependencies
const https = require('https');
const http = require('http');
Expand All @@ -25,7 +31,6 @@ const Router = require('./router');
const TunnelService = require('./ssltunnel');
const JSONWebToken = require('./models/jsonwebtoken');
const Constants = require('./constants');
const Settings = require('./models/settings');

// Causes a timestamp to be prepended to console log lines.
require('./log-timestamps');
Expand All @@ -37,42 +42,6 @@ require('./app-instance');
// Open the database
db.open();

// Move the tunneltoken into the database
if (fs.existsSync('tunneltoken')) {
const token = JSON.parse(fs.readFileSync('tunneltoken'));
Settings.set('tunneltoken', token).then(function() {
fs.unlinkSync('tunneltoken');
}).catch(function(e) {
throw e;
});
}

// Move the notunnel setting into the database
if (fs.existsSync('notunnel')) {
Settings.set('notunnel', true).then(function() {
fs.unlinkSync('notunnel');
}).catch(function(e) {
throw e;
});
}

// Move certificates, if necessary. If this throws an error, let it bubble up.
if (!fs.existsSync('ssl')) {
fs.mkdirSync('ssl');
}

if (fs.existsSync('privatekey.pem')) {
fs.renameSync('privatekey.pem', path.join('ssl', 'privatekey.pem'));
}

if (fs.existsSync('certificate.pem')) {
fs.renameSync('certificate.pem', path.join('ssl', 'certificate.pem'));
}

if (fs.existsSync('chain.pem')) {
fs.renameSync('chain.pem', path.join('ssl', 'chain.pem'));
}

let httpServer = http.createServer();
let httpApp = createGatewayApp(httpServer);

Expand All @@ -86,11 +55,11 @@ function createHttpsServer() {

// HTTPS server configuration
const options = {
key: fs.readFileSync(path.join('ssl', 'privatekey.pem')),
cert: fs.readFileSync(path.join('ssl', 'certificate.pem'))
key: fs.readFileSync(path.join(UserProfile.sslDir, 'privatekey.pem')),
cert: fs.readFileSync(path.join(UserProfile.sslDir, 'certificate.pem'))
};
if (fs.existsSync(path.join('ssl', 'chain.pem'))) {
options.ca = fs.readFileSync(path.join('ssl', 'chain.pem'));
if (fs.existsSync(path.join(UserProfile.sslDir, 'chain.pem'))) {
options.ca = fs.readFileSync(path.join(UserProfile.sslDir, 'chain.pem'));
}
return https.createServer(options);
}
Expand Down
16 changes: 10 additions & 6 deletions src/controllers/settings_controller.js
Expand Up @@ -22,6 +22,7 @@ const path = require('path');
const TunnelService = require('../ssltunnel');
const Settings = require('../models/settings');
const Constants = require('../constants');
const UserProfile = require('../user-profile');

var SettingsController = PromiseRouter();

Expand Down Expand Up @@ -106,9 +107,9 @@ SettingsController.post('/subscribe', async (request, response) => {

let leStore = require('le-store-certbot').create({
webrootPath: Constants.STATIC_PATH,
configDir: '~/mozilla-iot/etc',
logsDir: '~/mozilla-iot/var/log',
workDir: '~/mozilla-iot/var/lib',
configDir: path.join(UserProfile.baseDir, 'etc'),
logsDir: path.join(UserProfile.baseDir, 'var', 'log'),
workDir: path.join(UserProfile.baseDir, 'var', 'lib'),
debug: true
});
let le = greenlock.create({
Expand Down Expand Up @@ -180,9 +181,12 @@ SettingsController.post('/subscribe', async (request, response) => {
console.log('success', results);

// ok. we got the certificates. let's save them
fs.writeFileSync(path.join('ssl', 'certificate.pem'), results.cert);
fs.writeFileSync(path.join('ssl', 'privatekey.pem'), results.privkey);
fs.writeFileSync(path.join('ssl', 'chain.pem'), results.chain);
fs.writeFileSync(
path.join(UserProfile.sslDir, 'certificate.pem'), results.cert);
fs.writeFileSync(
path.join(UserProfile.sslDir, 'privatekey.pem'), results.privkey);
fs.writeFileSync(
path.join(UserProfile.sslDir, 'chain.pem'), results.chain);

// now we associate user's emails with the subdomain, unless it was
// reclaimed.
Expand Down
4 changes: 2 additions & 2 deletions src/controllers/uploads_controller.js
Expand Up @@ -13,10 +13,10 @@
const express = require('express');
const fs = require('fs');
const path = require('path');
const config = require('config');
const Constants = require('../constants');
const UserProfile = require('../user-profile');

const UPLOADS_PATH = path.join(__dirname, config.get('uploads.directory'));
const UPLOADS_PATH = UserProfile.uploadDir;
const FLOORPLAN_PATH = path.join(UPLOADS_PATH, 'floorplan.svg');
const FALLBACK_FLOORPLAN_PATH = path.join(Constants.STATIC_PATH,
'images',
Expand Down
13 changes: 12 additions & 1 deletion src/db.js
Expand Up @@ -13,6 +13,7 @@
const config = require('config');
const sqlite3 = require('sqlite3').verbose();
const fs = require('fs');
const path = require('path');
const Passwords = require('./passwords');
const assert = require('assert');

Expand All @@ -38,8 +39,18 @@ var Database = {
* Open the database.
*/
open: function() {
var filename = config.get('database.filename');
// If the database is already open, just return.
if (this.db) {
return;
}

// Don't pull this from user-profile.js, because that would cause a
// circular dependency.
const filename =
path.join(config.get('profileDir'), 'config', 'db.sqlite3');

var removeBeforeOpen = config.get('database.removeBeforeOpen');

// Check if database already exists
var exists = fs.existsSync(filename);
if (exists && removeBeforeOpen) {
Expand Down
8 changes: 5 additions & 3 deletions src/ssltunnel.js
Expand Up @@ -11,9 +11,10 @@
const fs = require('fs');
const config = require('config');
const path = require('path');
const Settings = require('./models/settings');
const fetch = require('node-fetch');
const spawnSync = require('child_process').spawn;
const Settings = require('./models/settings');
const UserProfile = require('./user-profile');

const DEBUG = false || (process.env.NODE_ENV === 'test');

Expand Down Expand Up @@ -95,8 +96,9 @@ var TunnelService = {

// method to check if the box has certificates
hasCertificates: function() {
return fs.existsSync(path.join('ssl', 'certificate.pem')) &&
fs.existsSync(path.join('ssl', 'privatekey.pem'));
return fs.existsSync(path.join(UserProfile.sslDir,
'certificate.pem')) &&
fs.existsSync(path.join(UserProfile.sslDir, 'privatekey.pem'));
},

// method to check if the box has a registered tunnel
Expand Down
3 changes: 2 additions & 1 deletion src/test/run-tests.sh
Expand Up @@ -2,7 +2,8 @@

SCRIPTDIR="$(dirname ""$0"")"

if [ ! -f "ssl/certificate.pem" ]; then
MOZIOT_HOME="${MOZIOT_HOME:=${HOME}/.mozilla-iot}"
if [ ! -f "${MOZIOT_HOME}/ssl/certificate.pem" ]; then
${SCRIPTDIR}/../../tools/make-self-signed-cert.sh
fi

Expand Down
13 changes: 8 additions & 5 deletions src/tunnel_setup.js
Expand Up @@ -8,10 +8,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

var config = require('config');
var fs = require('fs');
var path = require('path');
const config = require('config');
const fs = require('fs');
const path = require('path');
const Settings = require('./models/settings');
const UserProfile = require('./user-profile');

var TunnelSetup = {

Expand All @@ -33,8 +34,10 @@ var TunnelSetup = {
}

// then we check if we have certificates installed
if ((fs.existsSync(path.join('ssl', 'certificate.pem'))
&& fs.existsSync(path.join('ssl', 'privatekey.pem')))
if ((fs.existsSync(path.join(UserProfile.sslDir,
'certificate.pem'))
&& fs.existsSync(path.join(UserProfile.sslDir,
'privatekey.pem')))
|| notunnel) {
// if certs are installed,
// then we don't need to do anything and return
Expand Down

0 comments on commit 88c58a3

Please sign in to comment.