diff --git a/.eslintrc.js b/.eslintrc.js index 69cb41cb491..0b13cab2a5c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,26 +1,35 @@ module.exports = { - "plugins": [ - "security" + 'plugins': [ + 'security' ], - "extends": [ - "eslint:recommended", - "plugin:security/recommended" + 'extends': [ + 'eslint:recommended', + 'plugin:security/recommended' ], - "parser": "babel-eslint", - "env": { - "browser": true, - "commonjs": true, - "es6": true, - "node": true, - "mocha": true, - "jquery": true + 'parser': 'babel-eslint', + 'env': { + 'browser': true, + 'commonjs': true, + 'es6': true, + 'node': true, + 'mocha': true, + 'jquery': true }, - "rules": { - "no-unused-vars": [ - "error", + 'rules': { + 'security/detect-object-injection' : 0, + 'no-unused-vars': [ + 'error', { - "varsIgnorePattern": "should|expect" + 'varsIgnorePattern': 'should|expect' } ] - } + }, + 'overrides': [ + { + 'files': ['lib/client/*.js'], + 'rules': { + 'security/detect-object-injection': 1 + } + } + ], }; \ No newline at end of file diff --git a/.gitignore b/.gitignore index 834d6f3e5a7..925a4f2feaa 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ bundle/bundle.out.js *.iml my.env my.*.env +*.pem static/bower_components/ .*.sw? diff --git a/bin/generateRandomString.js b/bin/generateRandomString.js new file mode 100644 index 00000000000..deb307ab26d --- /dev/null +++ b/bin/generateRandomString.js @@ -0,0 +1,5 @@ + +require('crypto').randomBytes(1024, function(err, buffer) { + var token = buffer.toString('hex'); + console.log(token); +}); diff --git a/bundle/bundle.source.js b/bundle/bundle.source.js index c0286e800ff..85d68097387 100644 --- a/bundle/bundle.source.js +++ b/bundle/bundle.source.js @@ -28,6 +28,12 @@ window.Nightscout = { admin_plugins: require('../lib/admin_plugins/')() }; +window.Nightscout.report_plugins_preinit = require('../lib/report_plugins/'); +window.Nightscout.predictions = require('../lib/report/predictions'); +window.Nightscout.reportclient = require('../lib/report/reportclient'); +window.Nightscout.profileclient = require('../lib/profile/profileeditor'); +window.Nightscout.foodclient = require('../lib/food/food'); + console.info('Nightscout bundle ready'); // Needed for Hot Module Replacement diff --git a/lib/api/index.js b/lib/api/index.js index ad1ef6c1da9..3eb16ac826a 100644 --- a/lib/api/index.js +++ b/lib/api/index.js @@ -13,13 +13,13 @@ function create (env, ctx) { app.set('version', env.version); app.set('units', env.DISPLAY_UNITS); - // Only allow access to the API if API_SECRET is set on the server. + // Only allow access to the API if API KEY is set on the server. app.disable('api'); - if (env.api_secret) { - console.log('API_SECRET present, enabling API'); + if (env.enclave.isApiKeySet()) { + console.log('API KEY present, enabling API'); app.enable('api'); } else { - console.log('API_SECRET not found, API disabled'); + console.log('API KEY has not been set, API disabled'); } if (env.settings.enable) { diff --git a/lib/authorization/index.js b/lib/authorization/index.js index b63038c0533..410536dd19c 100644 --- a/lib/authorization/index.js +++ b/lib/authorization/index.js @@ -96,7 +96,7 @@ function init (env, ctx) { } function authorizeAdminSecret (secret) { - return (env.api_secret && env.api_secret.length > 12) ? (secret === env.api_secret) : false; + return env.enclave.isApiKey(secret); } authorization.seenPermissions = []; @@ -185,7 +185,7 @@ function init (env, ctx) { // Tokens have to be well formed JWTs try { - const verified = await jwt.verify(data.token, env.api_secret); + const verified = env.enclave.verifyJWT(data.token); token = verified.accessToken; } catch (err) {} @@ -237,7 +237,7 @@ function init (env, ctx) { /** * Check if the client has a permission execute an action, - * based on an API_SECRET or JWT in the request. + * based on an API KEY or JWT in the request. * * Used to authorize API calls * @@ -281,8 +281,9 @@ function init (env, ctx) { */ authorization.authorize = function authorize (accessToken) { - let userToken = accessToken - const decodedToken = jwt.decode(accessToken); + + let userToken = accessToken; + const decodedToken = env.enclave.verifyJWT(accessToken); if (decodedToken && decodedToken.accessToken) { userToken = decodedToken.accessToken; @@ -292,18 +293,14 @@ function init (env, ctx) { var authorized = null; if (subject) { - var token = jwt.sign({ accessToken: subject.accessToken }, env.api_secret, { expiresIn: '8h' }); - - //decode so we can tell the client the issued and expired times - var decoded = jwt.decode(token); + const token = env.enclave.signJWT({ accessToken: subject.accessToken }); + const decoded = env.enclave.verifyJWT(token); var roles = _.uniq(subject.roles.concat(defaultRoles)); authorized = { token , sub: subject.name - // not sending roles to client to prevent us from treating them as magic - // instead group permissions by role so the we can create correct shiros on the client , permissionGroups: _.map(roles, storage.roleToPermissions) , iat: decoded.iat , exp: decoded.exp diff --git a/lib/authorization/storage.js b/lib/authorization/storage.js index c867f0ee572..054f9a07b0d 100644 --- a/lib/authorization/storage.js +++ b/lib/authorization/storage.js @@ -151,12 +151,9 @@ function init (env, ctx) { } storage.subjects = _.map(results, function eachSubject (subject) { - if (env.api_secret) { - var shasum = crypto.createHash('sha1'); - shasum.update(env.api_secret); - shasum.update(subject._id.toString()); + if (env.enclave.isApiKeySet()) { + subject.digest = env.enclave.getSubjectHash(subject._id.toString()); var abbrev = subject.name.toLowerCase().replace(/[\W]/g, '').substring(0, 10); - subject.digest = shasum.digest('hex'); subject.accessToken = abbrev + '-' + subject.digest.substring(0, 16); subject.accessTokenDigest = storage.getSHA1(subject.accessToken); } diff --git a/lib/client/boluscalc.js b/lib/client/boluscalc.js index ae019ebdfef..5f5e19dbb76 100644 --- a/lib/client/boluscalc.js +++ b/lib/client/boluscalc.js @@ -593,14 +593,16 @@ function init (client, $) { if (qp.hideafteruse) { qp.hidden = true; - var apisecrethash = localStorage.getItem('apisecrethash'); - var dataJson = JSON.stringify(qp, null, ' '); - - var xhr = new XMLHttpRequest(); - xhr.open('PUT', '/api/v1/food/', true); - xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8'); - xhr.setRequestHeader('api-secret', apisecrethash); - xhr.send(dataJson); + $.ajax({ + method: 'PUT' + , url: '/api/v1/food/' + , headers: client.headers() + , data: qp + }).done(function treatmentSaved (response) { + console.info('quick pick saved', response); + }).fail(function treatmentSaveFail (response) { + console.info('quick pick failed to save', response); + }); } } diff --git a/lib/food/food.js b/lib/food/food.js index d5b32b84b36..299418d5b1a 100644 --- a/lib/food/food.js +++ b/lib/food/food.js @@ -146,7 +146,7 @@ client.init(function loaded () { $('#fe_filter_subcategory').empty().append(new Option(translate('(none)'),'')); if (filter.category !== '') { for (s in categories[filter.category]) { - if (categories[filter.category].hasOwnProperty(s)) { + if (Object.prototype.hasOwnProperty.call(categories[filter.category],s)) { $('#fe_filter_subcategory').append(new Option(s,s)); } } @@ -162,7 +162,7 @@ client.init(function loaded () { $('#fe_subcategory_list').empty().append(new Option(translate('(none)'),'')); if (foodrec.category !== '') { for (s in categories[foodrec.category]) { - if (categories[foodrec.category].hasOwnProperty(s)) { + if (Object.prototype.hasOwnProperty.call(categories[foodrec.category],s)) { $('#fe_subcategory_list').append(new Option(s,s)); } } @@ -198,7 +198,7 @@ client.init(function loaded () { $('#fe_filter_category').empty().append(new Option(translate('(none)'),'')); $('#fe_category_list').empty().append(new Option(translate('(none)'),'')); for (var s in categories) { - if (categories.hasOwnProperty(s)) { + if (Object.prototype.hasOwnProperty.call(categories,s)) { $('#fe_filter_category').append(new Option(s,s)); $('#fe_category_list').append(new Option(s,s)); } @@ -398,7 +398,7 @@ client.init(function loaded () { function savePortions(event) { var index = $(this).attr('index'); var findex = $(this).attr('findex'); - var val = parseFloat($(this).val().replace(/\,/g,'.')); + var val = parseFloat($(this).val().replace(/,/g,'.')); foodquickpick[index].foods[findex].portions=val; calculateCarbs(index); drawQuickpick(); diff --git a/lib/language.js b/lib/language.js index ea3f7e71143..3035286514e 100644 --- a/lib/language.js +++ b/lib/language.js @@ -78,28 +78,32 @@ function init (fs) { translated = language.translateCS(text); } - let keys = null; + var hasCI = false; + var hasParams = false; - if (options && options.params) { - keys = options.params; + if (options) { + hasCI = Object.prototype.hasOwnProperty.call(options,'ci'); + hasParams = Object.prototype.hasOwnProperty.call(options,'params'); } - if (options && !options.hasOwnProperty('ci') && !options.hasOwnProperty('params')) { + var keys = hasParams ? options.params : null; + + if (options && !hasCI && !hasParams) { keys = []; for (var i = 1; i < arguments.length; i++) { keys.push(arguments[i]); } } - if (options && (options.hasOwnProperty('ci') || options.hasOwnProperty('params')) && arguments.length > 2) { + if (options && (hasCI || hasParams) && arguments.length > 2) { if (!keys) keys = []; - for (var i = 2; i < arguments.length; i++) { + for (i = 2; i < arguments.length; i++) { keys.push(arguments[i]); } } if (keys) { - for (var i = 0; i < keys.length; i++) { + for (i = 0; i < keys.length; i++) { // eslint-disable-next-line no-useless-escape var r = new RegExp('\%' + (i + 1), 'g'); translated = translated.replace(r, keys[i]); diff --git a/lib/profile/profileeditor.js b/lib/profile/profileeditor.js index a8fecce1a25..d05d4ba1161 100644 --- a/lib/profile/profileeditor.js +++ b/lib/profile/profileeditor.js @@ -100,12 +100,12 @@ var init = function init () { _.each(mongoprofile.store, function eachStoredProfile (p) { // allign with default profile for (var key in defaultprofile) { - if (defaultprofile.hasOwnProperty(key) && !p.hasOwnProperty(key)) { + if (Object.prototype.hasOwnProperty.call(defaultprofile,key) && !Object.prototype.hasOwnProperty.call(p,key)) { p[key] = defaultprofile[key]; } } for (key in p) { - if (p.hasOwnProperty(key) && !defaultprofile.hasOwnProperty(key)) { + if (Object.prototype.hasOwnProperty.call(p,key) && !Object.prototype.hasOwnProperty.call(defaultprofile,key)) { delete p[key]; } } @@ -232,7 +232,7 @@ var init = function init () { $('#pe_profiles').empty(); for (var key in record.store) { - if (record.store.hasOwnProperty(key)) { + if (Object.prototype.hasOwnProperty.call(record.store,key)) { $('#pe_profiles').append(''); } } @@ -656,7 +656,7 @@ var init = function init () { var adjustedRecord = _.cloneDeep(record); for (var key in adjustedRecord.store) { - if (adjustedRecord.store.hasOwnProperty(key)) { + if (Object.prototype.hasOwnProperty.call(adjustedRecord.store,key)) { var profile = adjustedRecord.store[key]; if (!profile.perGIvalues) { delete profile.perGIvalues; @@ -707,7 +707,7 @@ var init = function init () { function getFirstAvailableProfile(record) { var availableProfiles = []; for (var key in record.store) { - if (record.store.hasOwnProperty(key)) { + if (Object.prototype.hasOwnProperty.call(record.store,key)) { if (key !== currentprofile) { availableProfiles.push(key); } diff --git a/app.js b/lib/server/app.js similarity index 86% rename from app.js rename to lib/server/app.js index 5a298f8ad43..b62a143b287 100644 --- a/app.js +++ b/lib/server/app.js @@ -4,11 +4,23 @@ const _get = require('lodash/get'); const express = require('express'); const compression = require('compression'); const bodyParser = require('body-parser'); +const randomToken = require('random-token'); const path = require('path'); const fs = require('fs'); const ejs = require('ejs'); +function resolvePath(filePath) { + + if (fs.existsSync(filePath)) return filePath; + let p = path.join(__dirname, filePath); + if (fs.existsSync(p)) return p; + p = path.join(process.cwd(), filePath); + if (fs.existsSync(p)) return p; + + return require.resolve(filePath); +} + function create (env, ctx) { var app = express(); var appInfo = env.name + ' ' + env.version; @@ -101,27 +113,14 @@ function create (env, ctx) { } app.set('view engine', 'ejs'); - // this allows you to render .html files as templates in addition to .ejs app.engine('html', require('ejs').renderFile); - app.set("views", path.join(__dirname, "views/")); - - let cacheBuster = 'developmentMode'; - let lastModified = new Date(); - let busterPath = '/tmp/cacheBusterToken'; - - if (process.env.NODE_ENV !== 'development') { - busterPath = process.cwd() + busterPath; - } else { - busterPath = __dirname + busterPath; - } + app.set("views", resolvePath('/views')); - if (fs.existsSync(busterPath)) { - cacheBuster = fs.readFileSync(busterPath).toString().trim(); - var stats = fs.statSync(busterPath); - lastModified = stats.mtime; - } + let cacheBuster = process.env.NODE_ENV == 'development' ? 'developmentMode': randomToken(16); app.locals.cachebuster = cacheBuster; + let lastModified = new Date(); + app.get("/robots.txt", (req, res) => { res.setHeader('Content-Type', 'text/plain'); res.send(['User-agent: *','Disallow: /'].join('\n')); @@ -133,7 +132,7 @@ function create (env, ctx) { res.setHeader('Last-Modified', lastModified.toUTCString()); } res.send(ejs.render(fs.readFileSync( - require.resolve(`${__dirname}/views/service-worker.js`), + resolvePath('/views/service-worker.js'), { encoding: 'utf-8' }), { locals: app.locals} )); @@ -147,19 +146,19 @@ function create (env, ctx) { console.log('Development environment detected, setting static file cache age to 1 second'); } - var staticFiles = express.static(env.static_files, { + var staticFiles = express.static(resolvePath(env.static_files), { maxAge }); // serve the static content app.use(staticFiles); - app.use('/translations', express.static('translations', { + app.use('/translations', express.static(resolvePath('/translations'), { maxAge })); if (ctx.bootErrors && ctx.bootErrors.length > 0) { - const bootErrorView = require('./lib/server/booterror')(env, ctx); + const bootErrorView = require('./booterror')(env, ctx); bootErrorView.setLocals(app.locals); app.get('*', bootErrorView); return app; @@ -185,11 +184,11 @@ function create (env, ctx) { /////////////////////////////////////////////////// // api and json object variables /////////////////////////////////////////////////// - const apiRoot = require('./lib/api/root')(env, ctx); - var api = require('./lib/api/')(env, ctx); - var api3 = require('./lib/api3/')(env, ctx); - var ddata = require('./lib/data/endpoints')(env, ctx); - var notificationsV2 = require('./lib/api/notifications-v2')(app, ctx); + const apiRoot = require('../api/root')(env, ctx); + var api = require('../api/')(env, ctx); + var api3 = require('../api3/')(env, ctx); + var ddata = require('../data/endpoints')(env, ctx); + var notificationsV2 = require('../api/notifications-v2')(app, ctx); app.use(compression({ filter: function shouldCompress (req, res) { @@ -242,7 +241,7 @@ function create (env, ctx) { }); }); - const clockviews = require('./lib/server/clocks.js')(env, ctx); + const clockviews = require('./clocks.js')(env, ctx); clockviews.setLocals(app.locals); app.use("/clock", clockviews); @@ -278,7 +277,7 @@ function create (env, ctx) { const swaggerUi = require('swagger-ui-express'); const swaggerUseSchema = schema => (...args) => swaggerUi.setup(schema)(...args); const swaggerDocument = require('./swagger.json'); - const swaggerDocumentApiV3 = require('./lib/api3/swagger.json'); + const swaggerDocumentApiV3 = require('../api3/swagger.json'); app.use('/api-docs', swaggerUi.serve, swaggerUseSchema(swaggerDocument)); app.use('/api3-docs', swaggerUi.serve, swaggerUseSchema(swaggerDocumentApiV3)); @@ -291,7 +290,6 @@ function create (env, ctx) { // if production, rely on postinstall script to run packaging for us app.locals.bundle = '/bundle'; - app.locals.mode = 'production'; if (process.env.NODE_ENV === 'development') { @@ -302,7 +300,7 @@ function create (env, ctx) { app.locals.bundle = '/devbundle'; const webpack = require('webpack'); - var webpack_conf = require('./webpack.config'); + var webpack_conf = require('../../webpack.config'); const middleware = require('webpack-dev-middleware'); const compiler = webpack(webpack_conf); @@ -320,16 +318,9 @@ function create (env, ctx) { } // Production bundling - var tmpFiles; - if (fs.existsSync(process.cwd() + '/tmp/cacheBusterToken')) { - tmpFiles = express.static('tmp', { - maxAge: maxAge - }); - } else { - tmpFiles = express.static(__dirname + '/tmp', { - maxAge: maxAge - }); - } + const tmpFiles = express.static(resolvePath('/tmp/public'), { + maxAge: maxAge + }); // serve the static content app.use('/bundle', tmpFiles); @@ -350,7 +341,7 @@ function create (env, ctx) { , coffee_match: /coffeescript/ , json_match: /json/ , cssmin: myCssmin - , cache: __dirname + '/tmp' + , cache: resolvePath('/tmp/public') , onerror: undefined , })); diff --git a/lib/server/bootevent.js b/lib/server/bootevent.js index 5be45189759..47e7ba300f0 100644 --- a/lib/server/bootevent.js +++ b/lib/server/bootevent.js @@ -111,7 +111,7 @@ function boot (env, language) { err: 'MONGODB_URI setting is missing, cannot connect to database'}); } - if (!env.api_secret) { + if (!env.enclave.isApiKeySet()) { ctx.bootErrors.push({'desc': 'Mandatory setting missing', err: 'API_SECRET setting is missing, cannot enable REST API'}); } diff --git a/lib/server/enclave.js b/lib/server/enclave.js new file mode 100644 index 00000000000..1c80122dc92 --- /dev/null +++ b/lib/server/enclave.js @@ -0,0 +1,81 @@ +'use strict;' + +const path = require('path'); +const crypto = require('crypto'); +const jwt = require('jsonwebtoken'); +const fs = require('fs'); + +// this is a class for holding potentially sensitive data in the app +// the class also implement functions to use the data, so the data is not shared outside the class + +const init = function init () { + + const enclave = {}; + const secrets = {}; + const apiKey = Symbol('api-secret'); + const apiKeySHA1 = Symbol('api-secretSHA1'); + const apiKeySHA512 = Symbol('api-secretSHA512'); + const jwtKey = Symbol('jwtkey'); + let apiKeySet = false; + + function readKey (filename) { + let filePath = path.resolve(__dirname + '/../../tmp/' + filename); + if (fs.existsSync(filePath)) { + return fs.readFileSync(filePath).toString().trim(); + } + console.error('Key file ', filePath, 'not found'); + return null; + } + + secrets[jwtKey] = readKey('randomString'); + + function genHash(data, algorihtm) { + const hash = crypto.createHash(algorihtm); + data = hash.update(data, 'utf-8'); + return data.digest('hex'); + } + + enclave.setApiKey = function setApiKey (keyValue) { + if (keyValue.length < 12) return; + apiKeySet = true; + secrets[apiKey] = keyValue; + secrets[apiKeySHA1] = genHash(keyValue,'sha1'); + secrets[apiKeySHA512] = genHash(keyValue,'sha512'); + } + + enclave.isApiKeySet = function isApiKeySet () { + return isApiKeySet; + } + + enclave.isApiKey = function isApiKey (keyValue) { + return keyValue == secrets[apiKeySHA1] || keyValue == secrets[apiKeySHA512]; + } + + enclave.setJWTKey = function setJWTKey (keyValue) { + secrets[jwtKey] = keyValue; + } + + enclave.signJWT = function signJWT(token, lifetime) { + const lt = lifetime ? lifetime : '8h'; + return jwt.sign(token, secrets[jwtKey], { expiresIn: lt }); + } + + enclave.verifyJWT = function verifyJWT(tokenString) { + try { + return jwt.verify(tokenString, secrets[jwtKey]); + } catch(err) { + return null; + } + } + + enclave.getSubjectHash = function getSubjectHash(id) { + var shasum = crypto.createHash('sha1'); + shasum.update(secrets[apiKey]); + shasum.update(id); + return shasum.digest('hex'); + } + + return enclave; +} + +module.exports = init; diff --git a/env.js b/lib/server/env.js similarity index 93% rename from env.js rename to lib/server/env.js index ccd9ebb48e4..ea2e154f027 100644 --- a/env.js +++ b/lib/server/env.js @@ -5,16 +5,16 @@ const _trim = require('lodash/trim'); const _forIn = require('lodash/forIn'); const _startsWith = require('lodash/startsWith'); const _camelCase = require('lodash/camelCase'); +const enclave = require('./enclave'); const owasp = require('owasp-password-strength-test'); - const fs = require('fs'); const crypto = require('crypto'); -const consts = require('./lib/constants'); +const consts = require('../constants'); const env = { - settings: require('./lib/settings')() + settings: require('../settings')() }; var shadowEnv; @@ -34,13 +34,14 @@ function config ( ) { env.PORT = readENV('PORT', 1337); env.HOSTNAME = readENV('HOSTNAME', null); env.IMPORT_CONFIG = readENV('IMPORT_CONFIG', null); - env.static_files = readENV('NIGHTSCOUT_STATIC_FILES', __dirname + '/static/'); + env.static_files = readENV('NIGHTSCOUT_STATIC_FILES', '/static'); env.debug = { minify: readENVTruthy('DEBUG_MINIFY', true) }; env.err = []; env.notifies = []; + env.enclave = enclave(); setSSL(); setAPISecret(); @@ -85,10 +86,12 @@ function setAPISecret() { console.error(msg); env.err.push({ desc: msg }); } else { - var shasum = crypto.createHash('sha1'); - shasum.update(readENV('API_SECRET')); - var testresult = owasp.test(readENV('API_SECRET')); + const apiSecret = readENV('API_SECRET'); + delete process.env.API_SECRET; + + env.enclave.setApiKey(apiSecret); + var testresult = owasp.test(apiSecret); const messages = testresult.errors; if (messages) { @@ -98,13 +101,12 @@ function setAPISecret() { env.notifies.push({persistent: true, title: 'Security issue', message: m + ' Please change your API_SECRET to reduce risk of unauthorized access.'}); }); } - env.api_secret = shasum.digest('hex'); } } } function setVersion() { - var software = require('./package.json'); + var software = require('../../package.json'); env.version = software.version; env.name = software.name; } @@ -123,7 +125,7 @@ function setStorage() { // TODO: clean up a bit // Some people prefer to use a json configuration file instead. // This allows a provided json config to override environment variables - var DB = require('./database_configuration.json'), + var DB = require('../../database_configuration.json'), DB_URL = DB.url ? DB.url : env.storageURI, DB_COLLECTION = DB.collection ? DB.collection : env.entries_collection; env.storageURI = DB_URL; diff --git a/server.js b/lib/server/server.js similarity index 93% rename from server.js rename to lib/server/server.js index 56ce2b2d894..ea75d5ac636 100644 --- a/server.js +++ b/lib/server/server.js @@ -28,7 +28,7 @@ const fs = require('fs'); const env = require('./env')( ); -const language = require('./lib/language')(); +const language = require('../language')(); const translate = language.set(env.settings.language).translate; language.loadLocalization(fs); @@ -47,7 +47,7 @@ function create (app) { return transport.createServer(app); } -require('./lib/server/bootevent')(env, language).boot(function booted (ctx) { +require('./bootevent')(env, language).boot(function booted (ctx) { console.log('Boot event processing completed'); @@ -68,7 +68,7 @@ require('./lib/server/bootevent')(env, language).boot(function booted (ctx) { /////////////////////////////////////////////////// // setup socket io for data and message transmission /////////////////////////////////////////////////// - var websocket = require('./lib/server/websocket')(env, ctx, server); + var websocket = require('./websocket')(env, ctx, server); ctx.bus.on('data-processed', function() { websocket.update(); diff --git a/swagger.json b/lib/server/swagger.json similarity index 100% rename from swagger.json rename to lib/server/swagger.json diff --git a/swagger.yaml b/lib/server/swagger.yaml similarity index 100% rename from swagger.yaml rename to lib/server/swagger.yaml diff --git a/lib/server/websocket.js b/lib/server/websocket.js index 18081181f56..26da4394a2f 100644 --- a/lib/server/websocket.js +++ b/lib/server/websocket.js @@ -41,7 +41,7 @@ function init (env, ctx, server) { if (verParse) { versionNum = 10000 * parseInt(verParse[1]) + 100 * parseInt(verParse[2]) + 1 * parseInt(verParse[3]); } - var apiEnabled = env.api_secret ? true : false; + var apiEnabled = env.enclave.isApiKeySet(); var activeProfile = ctx.ddata.lastProfileFromSwitch; diff --git a/package.json b/package.json index 5f51c399a21..4f1906f08d0 100644 --- a/package.json +++ b/package.json @@ -26,23 +26,23 @@ "url": "https://github.com/nightscout/cgm-remote-monitor/issues" }, "scripts": { - "start": "node server.js", + "start": "node lib/server/server.js", "test": "env-cmd -f ./my.test.env mocha --require ./tests/hooks.js -exit ./tests/*.test.js", "test-single": "env-cmd -f ./my.test.env mocha --require ./tests/hooks.js --exit ./tests/$TEST.test.js", "test-ci": "env-cmd -f ./ci.test.env nyc --reporter=lcov --reporter=text-summary mocha --require ./tests/hooks.js --exit ./tests/*.test.js", "env": "env", - "postinstall": "webpack --mode production --config webpack.config.js && npm run-script update-buster", - "bundle": "webpack --mode production --config webpack.config.js && npm run-script update-buster", - "bundle-dev": "webpack --mode development --config webpack.config.js && npm run-script update-buster", + "postinstall": "webpack --mode production --config webpack.config.js && npm run-script generate-keys", + "bundle": "webpack --mode production --config webpack.config.js && npm run-script generate-keys", + "bundle-dev": "webpack --mode development --config webpack.config.js && npm run-script generate-keys", "bundle-analyzer": "webpack --mode development --config webpack.config.js --profile --json > stats.json && webpack-bundle-analyzer stats.json", - "update-buster": "node bin/generateCacheBuster.js >tmp/cacheBusterToken", + "generate-keys": "node bin/generateRandomString.js >tmp/randomString", "coverage": "cat ./coverage/lcov.info | env-cmd -f ./ci.test.env codacy-coverage", - "dev": "env-cmd -f ./my.env nodemon --inspect server.js 0.0.0.0", - "dev-test": "env-cmd -f ./my.devtest.env nodemon --inspect server.js 0.0.0.0", - "prod": "env-cmd -f ./my.prod.env node server.js 0.0.0.0", + "dev": "env-cmd -f ./my.env nodemon --inspect lib/server/server.js 0.0.0.0", + "dev-test": "env-cmd -f ./my.devtest.env nodemon --inspect lib/server/server.js 0.0.0.0", + "prod": "env-cmd -f ./my.prod.env node lib/server/server.js 0.0.0.0", "lint": "eslint lib" }, - "main": "server.js", + "main": "lib/server/server.js", "nodemonConfig": { "ignore": [ "tests/*", diff --git a/tests/XX_clean.test.js b/tests/XX_clean.test.js index 0698c14f82a..9b921a01721 100644 --- a/tests/XX_clean.test.js +++ b/tests/XX_clean.test.js @@ -10,7 +10,7 @@ describe('Clean MONGO after tests', function ( ) { var api = require('../lib/api/'); beforeEach(function (done) { process.env.API_SECRET = 'this is my long pass phrase'; - self.env = require('../env')(); + self.env = require('../lib/server/env')(); self.env.settings.authDefaultRoles = 'readable'; self.env.settings.enable = ['careportal', 'api']; this.wares = require('../lib/middleware/')(self.env); diff --git a/tests/admintools.test.js b/tests/admintools.test.js index b8ed0e102ce..59f10c720a7 100644 --- a/tests/admintools.test.js +++ b/tests/admintools.test.js @@ -70,7 +70,7 @@ describe('admintools', function ( ) { before(function (done) { benv.setup(function() { - benv.require(__dirname + '/../tmp/js/bundle.app.js'); + benv.require(__dirname + '/../tmp/public/js/bundle.app.js'); self.$ = $; diff --git a/tests/api.alexa.test.js b/tests/api.alexa.test.js index 6fa5c12044a..7075b8e6d5b 100644 --- a/tests/api.alexa.test.js +++ b/tests/api.alexa.test.js @@ -13,7 +13,9 @@ describe('Alexa REST api', function ( ) { const apiRoot = require('../lib/api/root'); const api = require('../lib/api/'); before(function (done) { - var env = require('../env')( ); + delete process.env.API_SECRET; + process.env.API_SECRET = 'this is my long pass phrase'; + var env = require('../lib/server/env')( ); env.settings.enable = ['alexa']; env.settings.authDefaultRoles = 'readable'; env.api_secret = 'this is my long pass phrase'; diff --git a/tests/api.devicestatus.test.js b/tests/api.devicestatus.test.js index 0dd460b6ecd..50b6c202d08 100644 --- a/tests/api.devicestatus.test.js +++ b/tests/api.devicestatus.test.js @@ -8,11 +8,12 @@ var language = require('../lib/language')(); describe('Devicestatus API', function ( ) { this.timeout(10000); var self = this; + var known = 'b723e97aa97846eb92d5264f084b2823f57c4aa1'; var api = require('../lib/api/'); beforeEach(function (done) { process.env.API_SECRET = 'this is my long pass phrase'; - self.env = require('../env')(); + self.env = require('../lib/server/env')(); self.env.settings.authDefaultRoles = 'readable'; self.env.settings.enable = ['careportal', 'api']; this.wares = require('../lib/middleware/')(self.env); @@ -31,7 +32,7 @@ describe('Devicestatus API', function ( ) { console.log('Inserting devicestatus entry'); request(self.app) .post('/api/devicestatus/') - .set('api-secret', self.env.api_secret || '') + .set('api-secret', known || '') .send({ device: 'xdripjs://rigName' , xdripjs: { @@ -53,7 +54,7 @@ describe('Devicestatus API', function ( ) { .get('/api/devicestatus/') .query('find[created_at][$gte]=2018-12-16') .query('find[created_at][$lte]=2018-12-17') - .set('api-secret', self.env.api_secret || '') + .set('api-secret', known || '') .expect(200) .expect(function (response) { console.log(JSON.stringify(response.body[0])); @@ -69,7 +70,7 @@ describe('Devicestatus API', function ( ) { request(self.app) .delete('/api/devicestatus/') .query('find[created_at][$gte]=2018-12-16') - .set('api-secret', self.env.api_secret || '') + .set('api-secret', known || '') .expect(200) .end(function (err) { if (err) { @@ -80,7 +81,7 @@ describe('Devicestatus API', function ( ) { request(self.app) .get('/api/devicestatus/') .query('find[created_at][$lte]=2018-12-16') - .set('api-secret', self.env.api_secret || '') + .set('api-secret', known || '') .expect(200) .expect(function (response) { response.body.length.should.equal(0); diff --git a/tests/api.entries.test.js b/tests/api.entries.test.js index 6c0c3f14e45..cbb1c885631 100644 --- a/tests/api.entries.test.js +++ b/tests/api.entries.test.js @@ -9,10 +9,13 @@ require('should'); describe('Entries REST api', function ( ) { var entries = require('../lib/api/entries/'); var self = this; + var known = 'b723e97aa97846eb92d5264f084b2823f57c4aa1'; this.timeout(10000); before(function (done) { - self.env = require('../env')( ); + delete process.env.API_SECRET; + process.env.API_SECRET = 'this is my long pass phrase'; + self.env = require('../lib/server/env')( ); self.env.settings.authDefaultRoles = 'readable'; self.wares = require('../lib/middleware/')(self.env); self.archive = null; @@ -254,7 +257,7 @@ describe('Entries REST api', function ( ) { console.log('Inserting glucose entry') request(self.app) .post('/entries/') - .set('api-secret', self.env.api_secret || '') + .set('api-secret', known || '') .send({ "type": "sgv", "sgv": "199", "dateString": "2014-07-20T00:44:15.000-07:00" , "date": 1405791855000, "device": "dexcom", "direction": "NOT COMPUTABLE" @@ -268,7 +271,7 @@ describe('Entries REST api', function ( ) { console.log('Ensuring glucose entry was inserted successfully'); request(self.app) .get('/entries.json?find[dateString][$gte]=2014-07-20&count=100') - .set('api-secret', self.env.api_secret || '') + .set('api-secret', known || '') .expect(200) .expect(function (response) { var entry = response.body[0]; @@ -283,7 +286,7 @@ describe('Entries REST api', function ( ) { console.log('Deleting test glucose entry'); request(self.app) .delete('/entries.json?find[dateString][$gte]=2014-07-20&count=100') - .set('api-secret', self.env.api_secret || '') + .set('api-secret', known || '') .expect(200) .end(function (err) { if (err) { @@ -293,7 +296,7 @@ describe('Entries REST api', function ( ) { console.log('Testing if glucose entry was deleted'); request(self.app) .get('/entries.json?find[dateString][$gte]=2014-07-20&count=100') - .set('api-secret', self.env.api_secret || '') + .set('api-secret', known || '') .expect(200) .expect(function (response) { response.body.length.should.equal(0); @@ -307,12 +310,12 @@ describe('Entries REST api', function ( ) { }); }); - it('post multipole entries, query, delete, verify gone', function (done) { + it('post multiple entries, query, delete, verify gone', function (done) { // insert a glucose entry - needs to be unique from example data console.log('Inserting glucose entry') request(self.app) .post('/entries/') - .set('api-secret', self.env.api_secret || '') + .set('api-secret', known || '') .send([{ "type": "sgv", "sgv": "199", "dateString": "2014-07-20T00:44:15.000-07:00" , "date": 1405791855000, "device": "dexcom", "direction": "NOT COMPUTABLE" @@ -329,7 +332,7 @@ describe('Entries REST api', function ( ) { console.log('Ensuring glucose entry was inserted successfully'); request(self.app) .get('/entries.json?find[dateString][$gte]=2014-07-20&count=100') - .set('api-secret', self.env.api_secret || '') + .set('api-secret', known || '') .expect(200) .expect(function (response) { var entry = response.body[0]; @@ -345,7 +348,7 @@ describe('Entries REST api', function ( ) { console.log('Deleting test glucose entry'); request(self.app) .delete('/entries.json?find[dateString][$gte]=2014-07-20&count=100') - .set('api-secret', self.env.api_secret || '') + .set('api-secret', known || '') .expect(200) .end(function (err) { if (err) { @@ -355,7 +358,7 @@ describe('Entries REST api', function ( ) { console.log('Testing if glucose entries were deleted'); request(self.app) .get('/entries.json?find[dateString][$gte]=2014-07-20&count=100') - .set('api-secret', self.env.api_secret || '') + .set('api-secret', known || '') .expect(200) .expect(function (response) { response.body.length.should.equal(0); diff --git a/tests/api.security.test.js b/tests/api.security.test.js index 87d51246c03..0955594b47d 100644 --- a/tests/api.security.test.js +++ b/tests/api.security.test.js @@ -13,10 +13,13 @@ describe('Security of REST API V1', function() { this.timeout(30000); + var known = 'b723e97aa97846eb92d5264f084b2823f57c4aa1'; + before(function(done) { var api = require('../lib/api/'); - self.env = require('../env')(); - self.env.api_secret = 'this is my long pass phrase'; + delete process.env.API_SECRET; + process.env.API_SECRET = 'this is my long pass phrase'; + self.env = require('../lib/server/env')(); self.env.settings.authDefaultRoles = 'denied'; this.wares = require('../lib/middleware/')(self.env); self.app = require('express')(); @@ -71,7 +74,7 @@ describe('Security of REST API V1', function() { it('Data load should succeed with API SECRET', function(done) { request(self.app) .get('/api/v1/entries.json') - .set('api-secret', self.env.api_secret) + .set('api-secret', known) .expect(200) .end(function(err, res) { done(); diff --git a/tests/api.status.test.js b/tests/api.status.test.js index 51730a6f078..5426689aceb 100644 --- a/tests/api.status.test.js +++ b/tests/api.status.test.js @@ -8,7 +8,9 @@ require('should'); describe('Status REST api', function ( ) { var api = require('../lib/api/'); before(function (done) { - var env = require('../env')( ); + delete process.env.API_SECRET; + process.env.API_SECRET = 'this is my long pass phrase'; + var env = require('../lib/server/env')( ); env.settings.enable = ['careportal', 'rawbg']; env.settings.authDefaultRoles = 'readable'; env.api_secret = 'this is my long pass phrase'; diff --git a/tests/api.treatments.test.js b/tests/api.treatments.test.js index 567ea1da278..40e2d052de7 100644 --- a/tests/api.treatments.test.js +++ b/tests/api.treatments.test.js @@ -10,10 +10,12 @@ describe('Treatment API', function ( ) { this.timeout(10000); var self = this; + var api_secret_hash = 'b723e97aa97846eb92d5264f084b2823f57c4aa1'; + var api = require('../lib/api/'); beforeEach(function (done) { process.env.API_SECRET = 'this is my long pass phrase'; - self.env = require('../env')(); + self.env = require('../lib/server/env')(); self.env.settings.authDefaultRoles = 'readable'; self.env.settings.enable = ['careportal', 'api']; this.wares = require('../lib/middleware/')(self.env); @@ -37,7 +39,7 @@ describe('Treatment API', function ( ) { var now = (new Date()).toISOString(); request(self.app) .post('/api/treatments/') - .set('api-secret', self.env.api_secret || '') + .set('api-secret', api_secret_hash || '') .send({eventType: 'Meal Bolus', created_at: now, carbs: '30', insulin: '2.00', preBolus: '15', glucose: 100, glucoseType: 'Finger', units: 'mg/dl', notes: ''}) .expect(200) .end(function (err) { @@ -90,7 +92,7 @@ describe('Treatment API', function ( ) { self.ctx.treatments().remove({ }, function ( ) { request(self.app) .post('/api/treatments/') - .set('api-secret', self.env.api_secret || '') + .set('api-secret', api_secret_hash || '') .send({eventType: 'Meal Bolus', created_at: _moment(current_time).format("YYYY-MM-DDTHH:mm:ss.SSSZZ"), carbs: '30', insulin: '2.00', glucose: 100, glucoseType: 'Finger', units: 'mg/dl'}) .expect(200) .end(function (err) { @@ -124,7 +126,7 @@ describe('Treatment API', function ( ) { var now = (new Date()).toISOString(); request(self.app) .post('/api/treatments/') - .set('api-secret', self.env.api_secret || '') + .set('api-secret', api_secret_hash || '') .send([ {eventType: 'BG Check', created_at: now, glucose: 100, preBolus: '0', glucoseType: 'Finger', units: 'mg/dl', notes: ''} , {eventType: 'Meal Bolus', created_at: now, carbs: '30', insulin: '2.00', preBolus: '15', glucose: 100, glucoseType: 'Finger', units: 'mg/dl'} @@ -151,7 +153,7 @@ describe('Treatment API', function ( ) { var now = (new Date()).toISOString(); request(self.app) .post('/api/treatments/') - .set('api-secret', self.env.api_secret || '') + .set('api-secret', api_secret_hash || '') .send([ {eventType: 'BG Check', glucose: 100, units: 'mg/dl', created_at: now} , {eventType: 'BG Check', glucose: 100, units: 'mg/dl', created_at: now} @@ -192,7 +194,7 @@ describe('Treatment API', function ( ) { var now = (new Date()).toISOString(); request(self.app) .post('/api/treatments/') - .set('api-secret', self.env.api_secret || '') + .set('api-secret', api_secret_hash || '') .send({eventType: 'Meal Bolus', created_at: now, carbs: '99', insulin: '2.00', preBolus: '15', glucose: 100, glucoseType: 'Finger', units: 'mg/dl'}) .expect(200) .end(function (err) { @@ -204,7 +206,7 @@ describe('Treatment API', function ( ) { request(self.app) .get('/api/treatments/') .query('find[carbs]=99') - .set('api-secret', self.env.api_secret || '') + .set('api-secret', api_secret_hash || '') .expect(200) .expect(function (response) { response.body[0].carbs.should.equal(99); @@ -218,7 +220,7 @@ describe('Treatment API', function ( ) { request(self.app) .delete('/api/treatments/') .query('find[carbs]=99') - .set('api-secret', self.env.api_secret || '') + .set('api-secret', api_secret_hash || '') .expect(200) .end(function (err) { if (err) { @@ -229,7 +231,7 @@ describe('Treatment API', function ( ) { request(self.app) .get('/api/treatments/') .query('find[carbs]=99') - .set('api-secret', self.env.api_secret || '') + .set('api-secret', api_secret_hash || '') .expect(200) .expect(function (response) { response.body.length.should.equal(0); diff --git a/tests/api.unauthorized.test.js b/tests/api.unauthorized.test.js index f3603ebb8b4..e1cfae62ac8 100644 --- a/tests/api.unauthorized.test.js +++ b/tests/api.unauthorized.test.js @@ -14,7 +14,7 @@ describe('authed REST api', function ( ) { var known = 'b723e97aa97846eb92d5264f084b2823f57c4aa1'; delete process.env.API_SECRET; process.env.API_SECRET = 'this is my long pass phrase'; - var env = require('../env')( ); + var env = require('../lib/server/env')( ); env.settings.authDefaultRoles = 'readable'; this.wares = require('../lib/middleware/')(env); this.archive = null; diff --git a/tests/api.verifyauth.test.js b/tests/api.verifyauth.test.js index 318ba610a29..fe4f22a7d78 100644 --- a/tests/api.verifyauth.test.js +++ b/tests/api.verifyauth.test.js @@ -9,11 +9,13 @@ describe('Verifyauth REST api', function ( ) { var self = this; this.timeout(10000); - + var known = 'b723e97aa97846eb92d5264f084b2823f57c4aa1'; + var api = require('../lib/api/'); before(function (done) { - self.env = require('../env')( ); - self.env.api_secret = 'this is my long pass phrase'; + delete process.env.API_SECRET; + process.env.API_SECRET = 'this is my long pass phrase'; + self.env = require('../lib/server/env')( ); self.env.settings.authDefaultRoles = 'denied'; this.wares = require('../lib/middleware/')(self.env); self.app = require('express')( ); @@ -37,7 +39,7 @@ describe('Verifyauth REST api', function ( ) { it('/verifyauth should return OK', function (done) { request(self.app) .get('/api/verifyauth') - .set('api-secret', self.env.api_secret || '') + .set('api-secret', known || '') .expect(200) .end(function(err, res) { res.body.message.message.should.equal('OK'); diff --git a/tests/ar2.test.js b/tests/ar2.test.js index 601c94831ef..91ae4353841 100644 --- a/tests/ar2.test.js +++ b/tests/ar2.test.js @@ -20,7 +20,7 @@ describe('ar2', function ( ) { var ar2 = require('../lib/plugins/ar2')(ctx); var bgnow = require('../lib/plugins/bgnow')(ctx); - var env = require('../env')(); + var env = require('../lib/server/env')(); var now = Date.now(); var before = now - FIVE_MINS; @@ -42,7 +42,7 @@ describe('ar2', function ( ) { it('should plot a line if coneFactor is 0', function () { ctx.ddata.sgvs = [{mgdl: 100, mills: before}, {mgdl: 105, mills: now}]; - var env0 = require('../env')(); + var env0 = require('../lib/server/env')(); env0.extendedSettings = { ar2: { coneFactor: 0 } }; var sbx = require('../lib/sandbox')().serverInit(env0, ctx).withExtendedSettings(ar2); bgnow.setProperties(sbx); diff --git a/tests/basalprofileplugin.test.js b/tests/basalprofileplugin.test.js index d809a735000..59b14463e04 100644 --- a/tests/basalprofileplugin.test.js +++ b/tests/basalprofileplugin.test.js @@ -5,7 +5,7 @@ const language = require('../lib/language')(fs); describe('basalprofile', function ( ) { var sandbox = require('../lib/sandbox')(); - var env = require('../env')(); + var env = require('../lib/server/env')(); var ctx = { settings: {} , language: language diff --git a/tests/boluswizardpreview.test.js b/tests/boluswizardpreview.test.js index c5e6533bad2..6cc4127e19b 100644 --- a/tests/boluswizardpreview.test.js +++ b/tests/boluswizardpreview.test.js @@ -3,7 +3,7 @@ var Stream = require('stream'); var levels = require('../lib/levels'); describe('boluswizardpreview', function ( ) { - var env = require('../env')(); + var env = require('../lib/server/env')(); env.testMode = true; var ctx = { diff --git a/tests/cannulaage.test.js b/tests/cannulaage.test.js index 0668de060b0..b9108b044c7 100644 --- a/tests/cannulaage.test.js +++ b/tests/cannulaage.test.js @@ -4,7 +4,7 @@ require('should'); var levels = require('../lib/levels'); describe('cage', function ( ) { - var env = require('../env')(); + var env = require('../lib/server/env')(); var ctx = {}; ctx.ddata = require('../lib/data/ddata')(); ctx.notifications = require('../lib/notifications')(env, ctx); diff --git a/tests/careportal.test.js b/tests/careportal.test.js index b7cc668ef49..1da34673535 100644 --- a/tests/careportal.test.js +++ b/tests/careportal.test.js @@ -10,6 +10,10 @@ var nowData = { , treatments: [] }; +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + describe('careportal', function ( ) { this.timeout(60000); // TODO: see why this test takes longer on Travis to complete @@ -34,7 +38,7 @@ describe('careportal', function ( ) { done( ); }); - it ('open careportal, and enter a treatment', function (done) { + it ('open careportal, and enter a treatment', async () =>{ console.log('Careportal test client start'); @@ -49,8 +53,11 @@ describe('careportal', function ( ) { console.log('Careportal test client init'); client.init(); + sleep(50); + console.log('Careportal test client data update'); client.dataUpdate(nowData, true); + sleep(50); client.careportal.prepareEvents(); @@ -89,7 +96,6 @@ describe('careportal', function ( ) { client.careportal.save(); - done(); }); }); diff --git a/tests/dbsize.test.js b/tests/dbsize.test.js index af0572fd5fe..ce3f373c2c7 100644 --- a/tests/dbsize.test.js +++ b/tests/dbsize.test.js @@ -15,7 +15,7 @@ describe('Database Size', function() { var dataWarn = { dbstats: { dataSize: 1024 * 1024 * 250, indexSize: 1024 * 1024 * 100, fileSize: 1024 * 1024 * 360 } }; var dataUrgent = { dbstats: { dataSize: 1024 * 1024 * 300, indexSize: 1024 * 1024 * 150, fileSize: 1024 * 1024 * 496 } }; - var env = require('../env')(); + var env = require('../lib/server/env')(); it('display database size in range', function(done) { var sandbox = require('../lib/sandbox')(); diff --git a/tests/ddata.test.js b/tests/ddata.test.js index ceb163b7c4f..034847b89a9 100644 --- a/tests/ddata.test.js +++ b/tests/ddata.test.js @@ -6,7 +6,7 @@ var should = require('should'); describe('ddata', function ( ) { // var sandbox = require('../lib/sandbox')(); - // var env = require('../env')(); + // var env = require('../lib/server/env')(); var ctx = {}; ctx.ddata = require('../lib/data/ddata')(); diff --git a/tests/env.test.js b/tests/env.test.js index 7990b470692..0de2a686054 100644 --- a/tests/env.test.js +++ b/tests/env.test.js @@ -7,7 +7,7 @@ describe('env', function () { process.env.SHOW_PLUGINS = 'iob'; process.env.ENABLE = 'iob cob'; - var env = require( '../env' )(); + var env = require( '../lib/server/env' )(); var showPlugins = env.settings.showPlugins; showPlugins.should.containEql( 'iob' ); showPlugins.should.containEql( 'delta' ); @@ -22,7 +22,7 @@ describe('env', function () { process.env.ENABLE = 'scaryplugin'; process.env.SCARYPLUGIN_DO_THING = 'yes'; - var env = require( '../env' )(); + var env = require( '../lib/server/env' )(); env.settings.isEnabled( 'scaryplugin' ).should.equal( true ); //Note the camelCase @@ -35,7 +35,7 @@ describe('env', function () { it( 'add pushover to enable if one of the env vars is set', function () { process.env.PUSHOVER_API_TOKEN = 'abc12345'; - var env = require( '../env' )(); + var env = require( '../lib/server/env' )(); env.settings.enable.should.containEql( 'pushover' ); env.extendedSettings.pushover.apiToken.should.equal( 'abc12345' ); @@ -45,7 +45,7 @@ describe('env', function () { it( 'add pushover to enable if one of the weird azure env vars is set', function () { process.env.CUSTOMCONNSTR_PUSHOVER_API_TOKEN = 'abc12345'; - var env = require( '../env' )(); + var env = require( '../lib/server/env' )(); env.settings.enable.should.containEql( 'pushover' ); env.extendedSettings.pushover.apiToken.should.equal( 'abc12345' ); @@ -54,17 +54,17 @@ describe('env', function () { it( 'readENVTruthy ', function () { process.env.INSECURE_USE_HTTP = 'true'; - var env = require( '../env' )(); + var env = require( '../lib/server/env' )(); env.insecureUseHttp.should.be.true(); process.env.INSECURE_USE_HTTP = 'false'; - env = require( '../env' )(); + env = require( '../lib/server/env' )(); env.insecureUseHttp.should.be.false(); process.env.INSECURE_USE_HTTP = 'not set ok, so use default value false'; - env = require( '../env' )(); + env = require( '../lib/server/env' )(); env.insecureUseHttp.should.be.false(); delete process.env.INSECURE_USE_HTTP; // unset INSECURE_USE_HTTP process.env.SECURE_HSTS_HEADER = 'true'; - env = require( '../env' )(); + env = require( '../lib/server/env' )(); env.insecureUseHttp.should.be.false(); // not defined should be false env.secureHstsHeader.should.be.true(); }); @@ -75,28 +75,28 @@ describe('env', function () { describe ( 'mmol', function () { it( 'mmol => mmol', function () { process.env.DISPLAY_UNITS = MMOL; - var env = require( '../env' )(); + var env = require( '../lib/server/env' )(); env.settings.units.should.equal( MMOL ); delete process.env.DISPLAY_UNITS; } ); it( 'mmol/l => mmol', function () { process.env.DISPLAY_UNITS = 'mmol/l'; - var env = require( '../env' )(); + var env = require( '../lib/server/env' )(); env.settings.units.should.equal( MMOL ); delete process.env.DISPLAY_UNITS; } ); it( 'mmol/L => mmol', function () { process.env.DISPLAY_UNITS = 'mmol/L'; - var env = require( '../env' )(); + var env = require( '../lib/server/env' )(); env.settings.units.should.equal( MMOL ); delete process.env.DISPLAY_UNITS; } ); it( 'MMOL => mmol', function () { process.env.DISPLAY_UNITS = 'MMOL'; - var env = require( '../env' )(); + var env = require( '../lib/server/env' )(); env.settings.units.should.equal( MMOL ); delete process.env.DISPLAY_UNITS; } ); @@ -105,28 +105,28 @@ describe('env', function () { describe ( 'mg/dl', function () { it( 'mg/dl => mg/dl', function () { process.env.DISPLAY_UNITS = MGDL; - var env = require( '../env' )(); + var env = require( '../lib/server/env' )(); env.settings.units.should.equal( MGDL ); delete process.env.DISPLAY_UNITS; } ); it( 'mg/dL => mg/dl', function () { process.env.DISPLAY_UNITS = 'mg/dL'; - var env = require( '../env' )(); + var env = require( '../lib/server/env' )(); env.settings.units.should.equal( MGDL ); delete process.env.DISPLAY_UNITS; } ); it( 'MG/DL => mg/dl', function () { process.env.DISPLAY_UNITS = 'MG/DL'; - var env = require( '../env' )(); + var env = require( '../lib/server/env' )(); env.settings.units.should.equal( MGDL ); delete process.env.DISPLAY_UNITS; } ); it( 'mgdl => mg/dl', function () { process.env.DISPLAY_UNITS = 'mgdl'; - var env = require( '../env' )(); + var env = require( '../lib/server/env' )(); env.settings.units.should.equal( MGDL ); delete process.env.DISPLAY_UNITS; } ); @@ -139,14 +139,14 @@ describe('env', function () { random = [...Array(~~(Math.random()*20)+1)].map(i=>(~~(Math.random()*36)).toString(36)).join(''); process.env.DISPLAY_UNITS = random; - var env = require( '../env' )(); + var env = require( '../lib/server/env' )(); env.settings.units.should.equal( MGDL ); delete process.env.DISPLAY_UNITS; } ); it( ' => mg/dl', function () { delete process.env.DISPLAY_UNITS; - var env = require( '../env' )(); + var env = require( '../lib/server/env' )(); env.settings.units.should.equal( MGDL ); delete process.env.DISPLAY_UNITS; } ); diff --git a/tests/errorcodes.test.js b/tests/errorcodes.test.js index b7c885a39f5..b8d3617710f 100644 --- a/tests/errorcodes.test.js +++ b/tests/errorcodes.test.js @@ -5,7 +5,7 @@ var levels = require('../lib/levels'); describe('errorcodes', function ( ) { var now = Date.now(); - var env = require('../env')(); + var env = require('../lib/server/env')(); var ctx = {}; ctx.ddata = require('../lib/data/ddata')(); ctx.notifications = require('../lib/notifications')(env, ctx); diff --git a/tests/fixtures/api/instance.js b/tests/fixtures/api/instance.js index ed5b28474c9..45f49185cdf 100644 --- a/tests/fixtures/api/instance.js +++ b/tests/fixtures/api/instance.js @@ -22,7 +22,7 @@ function configure () { process.env.API_SECRET = apiSecret; process.env.HOSTNAME = 'localhost'; - const env = require('../../../env')(); + const env = require('../../../lib/server/env')(); if (useHttps) { env.ssl = { diff --git a/tests/fixtures/api3/instance.js b/tests/fixtures/api3/instance.js index beaa03da18d..2b19aad6145 100644 --- a/tests/fixtures/api3/instance.js +++ b/tests/fixtures/api3/instance.js @@ -25,7 +25,7 @@ function configure () { process.env.API_SECRET = apiSecret; process.env.HOSTNAME = 'localhost'; - const env = require('../../../env')(); + const env = require('../../../lib/server/env')(); if (useHttps) { env.ssl = { diff --git a/tests/fixtures/headless.js b/tests/fixtures/headless.js index b5857da40ea..a3ad66b2424 100644 --- a/tests/fixtures/headless.js +++ b/tests/fixtures/headless.js @@ -10,6 +10,7 @@ function headless (benv, binding) { function init (opts, callback) { + var localStorage = opts.localStorage || './localstorage'; const t = Date.now(); console.log('Headless init'); @@ -23,14 +24,14 @@ function headless (benv, binding) { benv.setup(function() { console.log('Setting up benv', Date.now() - t); - - benv.require(__dirname + '/../../tmp/js/bundle.report.js'); - console.log('Bundle loaded', Date.now() - t); + benv.require(__dirname + '/../../tmp/public/js/bundle.app.js'); + console.log('Bundle loaded', Date.now() - t); + self.$ = $; - self.localCookieStorage = self.localStorage = self.$.localStorage = require('./localstorage'); + self.localCookieStorage = self.localStorage = self.$.localStorage = require(localStorage); self.$.fn.tooltip = function mockTooltip ( ) { }; diff --git a/tests/insulinage.test.js b/tests/insulinage.test.js index a2e060ff584..b21b54c011d 100644 --- a/tests/insulinage.test.js +++ b/tests/insulinage.test.js @@ -4,7 +4,7 @@ require('should'); var levels = require('../lib/levels'); describe('insulinage', function ( ) { - var env = require('../env')(); + var env = require('../lib/server/env')(); var ctx = {}; ctx.levels = levels; ctx.ddata = require('../lib/data/ddata')(); diff --git a/tests/loop.test.js b/tests/loop.test.js index 46617683a1e..64f5bc81148 100644 --- a/tests/loop.test.js +++ b/tests/loop.test.js @@ -13,7 +13,7 @@ var ctx_top = { , levels: levels }; ctx_top.language.set('en'); -var env = require('../env')(); +var env = require('../lib/server/env')(); var loop = require('../lib/plugins/loop')(ctx_top); var sandbox = require('../lib/sandbox')(ctx_top); diff --git a/tests/mongo-storage.test.js b/tests/mongo-storage.test.js index ee706906ff8..506e54e5441 100644 --- a/tests/mongo-storage.test.js +++ b/tests/mongo-storage.test.js @@ -4,7 +4,7 @@ var should = require('should'); var assert = require('assert'); describe('mongo storage', function () { - var env = require('../env')(); + var env = require('../lib/server/env')(); before(function (done) { delete env.api_secret; diff --git a/tests/notifications-api.test.js b/tests/notifications-api.test.js index 19d33e8311d..a534f1271fa 100644 --- a/tests/notifications-api.test.js +++ b/tests/notifications-api.test.js @@ -16,8 +16,8 @@ describe('Notifications API', function ( ) { var known = 'b723e97aa97846eb92d5264f084b2823f57c4aa1'; delete process.env.API_SECRET; process.env.API_SECRET = 'this is my long pass phrase'; - var env = require('../env')( ); - env.api_secret.should.equal(known); + var env = require('../lib/server/env')( ); + env.enclave.isApiKey(known).should.equal(true); env.testMode = true; var ctx = { @@ -68,7 +68,7 @@ describe('Notifications API', function ( ) { function makeRequest () { request(app) .get('/notifications/ack?level=1') - .set('api-secret', env.api_secret || '') + .set('api-secret', known || '') .expect(200) .end(function (err) { should.not.exist(err); diff --git a/tests/openaps-storage.test.js b/tests/openaps-storage.test.js index 48c2eb7764d..36714181a40 100644 --- a/tests/openaps-storage.test.js +++ b/tests/openaps-storage.test.js @@ -4,7 +4,7 @@ var should = require('should'); describe('openaps storage', function () { - var env = require('../env')(); + var env = require('../lib/server/env')(); before(function (done) { diff --git a/tests/openaps.test.js b/tests/openaps.test.js index dda62a7b090..1e31e934016 100644 --- a/tests/openaps.test.js +++ b/tests/openaps.test.js @@ -14,7 +14,7 @@ var top_ctx = { top_ctx.language.set('en'); var levels = require('../lib/levels'); top_ctx.levels = levels; -var env = require('../env')(); +var env = require('../lib/server/env')(); var openaps = require('../lib/plugins/openaps')(top_ctx); var sandbox = require('../lib/sandbox')(top_ctx); diff --git a/tests/pebble.test.js b/tests/pebble.test.js index 4b4a5c5a744..be6e09e9030 100644 --- a/tests/pebble.test.js +++ b/tests/pebble.test.js @@ -91,7 +91,9 @@ describe('Pebble Endpoint', function ( ) { var pebble = require('../lib/server/pebble'); before(function (done) { - var env = require('../env')( ); + delete process.env.API_SECRET; + process.env.API_SECRET = 'this is my long pass phrase'; + var env = require('../lib/server/env')( ); env.settings.authDefaultRoles = 'readable'; this.app = require('express')( ); this.app.enable('api'); @@ -226,7 +228,9 @@ describe('Pebble Endpoint', function ( ) { describe('Pebble Endpoint with Raw and IOB and COB', function ( ) { var pebbleRaw = require('../lib/server/pebble'); before(function (done) { - var env = require('../env')( ); + delete process.env.API_SECRET; + process.env.API_SECRET = 'this is my long pass phrase'; + var env = require('../lib/server/env')( ); env.settings.enable = ['rawbg', 'iob', 'cob']; env.settings.authDefaultRoles = 'readable'; this.appRaw = require('express')( ); diff --git a/tests/pump.test.js b/tests/pump.test.js index 6b38f814183..c2289fddd17 100644 --- a/tests/pump.test.js +++ b/tests/pump.test.js @@ -11,7 +11,7 @@ var top_ctx = { , settings: require('../lib/settings')() }; top_ctx.language.set('en'); -var env = require('../env')(); +var env = require('../lib/server/env')(); var levels = require('../lib/levels'); var profile = require('../lib/profilefunctions')(); top_ctx.levels = levels; diff --git a/tests/pushnotify.test.js b/tests/pushnotify.test.js index 28a222f8852..bc7a95720e1 100644 --- a/tests/pushnotify.test.js +++ b/tests/pushnotify.test.js @@ -6,7 +6,7 @@ var levels = require('../lib/levels'); describe('pushnotify', function ( ) { it('send a pushover alarm, but only 1 time', function (done) { - var env = require('../env')(); + var env = require('../lib/server/env')(); var ctx = {}; ctx.levels = levels; @@ -40,7 +40,7 @@ describe('pushnotify', function ( ) { }); it('send a pushover notification, but only 1 time', function (done) { - var env = require('../env')(); + var env = require('../lib/server/env')(); var ctx = {}; ctx.levels = levels; ctx.notifications = require('../lib/notifications')(env, ctx); @@ -72,7 +72,7 @@ describe('pushnotify', function ( ) { }); it('send a pushover alarm, and then cancel', function (done) { - var env = require('../env')(); + var env = require('../lib/server/env')(); var ctx = {}; ctx.levels = levels; diff --git a/tests/sandbox.test.js b/tests/sandbox.test.js index 966589a3129..e6422843c02 100644 --- a/tests/sandbox.test.js +++ b/tests/sandbox.test.js @@ -33,7 +33,7 @@ describe('sandbox', function ( ) { }); function createServerSandbox() { - var env = require('../env')(); + var env = require('../lib/server/env')(); var ctx = {}; ctx.ddata = require('../lib/data/ddata')(); ctx.notifications = require('../lib/notifications')(env, ctx); diff --git a/tests/security.test.js b/tests/security.test.js index ebc2e3e7278..c0b8821248b 100644 --- a/tests/security.test.js +++ b/tests/security.test.js @@ -21,15 +21,15 @@ describe('API_SECRET', function ( ) { it('should fail when unauthorized', function (done) { var known = 'b723e97aa97846eb92d5264f084b2823f57c4aa1'; + delete process.env.API_SECRET; process.env.API_SECRET = 'this is my long pass phrase'; - var env = require('../env')( ); - env.api_secret.should.equal(known); + var env = require('../lib/server/env')( ); + + env.enclave.isApiKey(known).should.equal(true); + setup_app(env, function (ctx) { - // console.log(this.app.enabled('api')); ctx.app.enabled('api').should.equal(true); - // ping_status(ctx.app, done); - // ping_authorized_endpoint(ctx.app, 200, done); ping_status(ctx.app, again); function again ( ) { ctx.app.api_secret = ''; @@ -44,16 +44,13 @@ describe('API_SECRET', function ( ) { var known = 'b723e97aa97846eb92d5264f084b2823f57c4aa1'; delete process.env.API_SECRET; process.env.API_SECRET = 'this is my long pass phrase'; - var env = require('../env')( ); - env.api_secret.should.equal(known); + var env = require('../lib/server/env')( ); + env.enclave.isApiKey(known).should.equal(true); setup_app(env, function (ctx) { - // console.log(this.app.enabled('api')); ctx.app.enabled('api').should.equal(true); - // ping_status(ctx.app, done); - // ping_authorized_endpoint(ctx.app, 200, done); ping_status(ctx.app, again); function again ( ) { - ctx.app.api_secret = env.api_secret; + ctx.app.api_secret = known; ping_authorized_endpoint(ctx.app, 200, done); } }); @@ -63,7 +60,7 @@ describe('API_SECRET', function ( ) { it('should not work short', function ( ) { delete process.env.API_SECRET; process.env.API_SECRET = 'tooshort'; - var env = require('../env')( ); + var env = require('../lib/server/env')( ); should.not.exist(env.api_secret); env.err[0].desc.should.startWith('API_SECRET should be at least'); }); @@ -73,10 +70,8 @@ describe('API_SECRET', function ( ) { .get('/status.json') .expect(200) .end(function (err, res) { - // console.log(res.body); res.body.status.should.equal('ok'); fn( ); - // console.log('err', err, 'res', res); }); } @@ -90,7 +85,6 @@ describe('API_SECRET', function ( ) { res.body.status.should.equal('ok'); } fn( ); - // console.log('err', err, 'res', res); }); } diff --git a/tests/sensorage.test.js b/tests/sensorage.test.js index 9901d636366..11a6953cb37 100644 --- a/tests/sensorage.test.js +++ b/tests/sensorage.test.js @@ -5,7 +5,7 @@ var times = require('../lib/times'); var levels = require('../lib/levels'); describe('sage', function ( ) { - var env = require('../env')(); + var env = require('../lib/server/env')(); var ctx = {}; ctx.levels = levels; ctx.ddata = require('../lib/data/ddata')(); diff --git a/tests/simplealarms.test.js b/tests/simplealarms.test.js index 8c6ee17bb6b..eb72210da4d 100644 --- a/tests/simplealarms.test.js +++ b/tests/simplealarms.test.js @@ -2,7 +2,7 @@ var should = require('should'); var levels = require('../lib/levels'); describe('simplealarms', function ( ) { - var env = require('../env')(); + var env = require('../lib/server/env')(); var ctx = { settings: {} , language: require('../lib/language')() diff --git a/tests/timeago.test.js b/tests/timeago.test.js index c4058ca9fb8..e7fc56904ec 100644 --- a/tests/timeago.test.js +++ b/tests/timeago.test.js @@ -13,7 +13,7 @@ describe('timeago', function() { var timeago = require('../lib/plugins/timeago')(ctx); - var env = require('../env')(); + var env = require('../lib/server/env')(); function freshSBX () { //set extendedSettings right before calling withExtendedSettings, there's some strange test interference here diff --git a/tests/treatmentnotify.test.js b/tests/treatmentnotify.test.js index e6d497872fb..7507410aaeb 100644 --- a/tests/treatmentnotify.test.js +++ b/tests/treatmentnotify.test.js @@ -4,7 +4,7 @@ var levels = require('../lib/levels'); describe('treatmentnotify', function ( ) { - var env = require('../env')(); + var env = require('../lib/server/env')(); var ctx = {}; ctx.ddata = require('../lib/data/ddata')(); ctx.notifications = require('../lib/notifications')(env, ctx); diff --git a/tests/verifyauth.test.js b/tests/verifyauth.test.js index c03b51573ca..7e97b11d61c 100644 --- a/tests/verifyauth.test.js +++ b/tests/verifyauth.test.js @@ -24,10 +24,12 @@ describe('verifyauth', function ( ) { it('should return defaults when called without secret', function (done) { var known = 'b723e97aa97846eb92d5264f084b2823f57c4aa1'; + var known512 = '8c8743d38cbe00debe4b3ba8d0ffbb85e4716c982a61bb9e57bab203178e3718b2965831c1a5e42b9da16f082fdf8a6cecf993b49ed67e3a8b1cd475885d8070'; delete process.env.API_SECRET; process.env.API_SECRET = 'this is my long pass phrase'; - var env = require('../env')( ); - env.api_secret.should.equal(known); + var env = require('../lib/server/env')( ); + env.enclave.isApiKey(known).should.equal(true); + env.enclave.isApiKey(known512).should.equal(true); setup_app(env, function (ctx) { ctx.app.enabled('api').should.equal(true); ctx.app.api_secret = ''; @@ -39,8 +41,8 @@ describe('verifyauth', function ( ) { var known = 'b723e97aa97846eb92d5264f084b2823f57c4aa1'; delete process.env.API_SECRET; process.env.API_SECRET = 'this is my long pass phrase'; - var env = require('../env')( ); - env.api_secret.should.equal(known); + var env = require('../lib/server/env')( ); + env.enclave.isApiKey(known).should.equal(true); setup_app(env, function (ctx) { ctx.app.enabled('api').should.equal(true); ctx.app.api_secret = 'wrong secret'; @@ -59,8 +61,8 @@ describe('verifyauth', function ( ) { var known = 'b723e97aa97846eb92d5264f084b2823f57c4aa1'; delete process.env.API_SECRET; process.env.API_SECRET = 'this is my long pass phrase'; - var env = require('../env')( ); - env.api_secret.should.equal(known); + var env = require('../lib/server/env')( ); + env.enclave.isApiKey(known).should.equal(true); setup_app(env, function (ctx) { ctx.app.enabled('api').should.equal(true); ctx.app.api_secret = 'wrong secret'; @@ -88,8 +90,8 @@ describe('verifyauth', function ( ) { var known = 'b723e97aa97846eb92d5264f084b2823f57c4aa1'; delete process.env.API_SECRET; process.env.API_SECRET = 'this is my long pass phrase'; - var env = require('../env')( ); - env.api_secret.should.equal(known); + var env = require('../lib/server/env')( ); + env.enclave.isApiKey(known).should.equal(true); setup_app(env, function (ctx) { ctx.app.enabled('api').should.equal(true); ctx.app.api_secret = env.api_secret; diff --git a/views/foodindex.html b/views/foodindex.html index 38606b00d32..c75770bbe35 100644 --- a/views/foodindex.html +++ b/views/foodindex.html @@ -112,7 +112,7 @@ <%- include('partials/authentication-status') %> - + diff --git a/views/partials/toolbar.ejs b/views/partials/toolbar.ejs index e81e06bb8fa..356f2da56fc 100644 --- a/views/partials/toolbar.ejs +++ b/views/partials/toolbar.ejs @@ -23,7 +23,7 @@ - + <% } %> diff --git a/views/profileindex.html b/views/profileindex.html index a24bb0b7193..742ba5d3540 100644 --- a/views/profileindex.html +++ b/views/profileindex.html @@ -166,7 +166,7 @@ <%- include('partials/authentication-status') %> - + diff --git a/views/reportindex.html b/views/reportindex.html index 235dea41b61..02a815604ce 100644 --- a/views/reportindex.html +++ b/views/reportindex.html @@ -122,7 +122,7 @@ <%- include('partials/authentication-status') %> - + diff --git a/views/service-worker.js b/views/service-worker.js index d52441d303a..75e7d608de3 100644 --- a/views/service-worker.js +++ b/views/service-worker.js @@ -29,7 +29,6 @@ const CACHE_LIST = [ '/css/main.css', '/bundle/js/bundle.app.js', '/bundle/js/bundle.clock.js', - '/bundle/js/bundle.report.js', '/socket.io/socket.io.js', '/js/client.js', '/images/logo2.png' diff --git a/webpack.config.js b/webpack.config.js index 885d72fd53f..2c4f27518ef 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -107,7 +107,6 @@ const rules = [ const appEntry = ['./bundle/bundle.source.js']; const clockEntry = ['./bundle/bundle.clocks.source.js']; -const reportEntry = ['./bundle/bundle.reports.source.js']; let mode = 'production'; let publicPath = '/bundle/'; @@ -122,7 +121,6 @@ if (process.env.NODE_ENV == 'development') { appEntry.unshift(hot); clockEntry.unshift(hot); - reportEntry.unshift(hot); rules.unshift({ enforce: "pre", @@ -162,11 +160,10 @@ module.exports = { context: path.resolve(__dirname, '.'), entry: { app: appEntry, - clock: clockEntry, - report: reportEntry + clock: clockEntry }, output: { - path: path.resolve(__dirname, './tmp'), + path: path.resolve(__dirname, './tmp/public'), publicPath, filename: 'js/bundle.[name].js', sourceMapFilename: 'js/bundle.[name].js.map',