mirror of
https://github.com/bckelley/cgm-remote-monitor.git
synced 2026-08-24 03:14:12 -05:00
* extended .gitignore for Visual Studio 2017 * creating a lib for api3 and exposing it's swagger file * adding pilot test (for /swagger.yaml) * implementing public GET /version * setting api version to 3.0.0-alpha * creating authorization skeleton + fetching some API env variables * reusing authorization library * implementing security * forcing HTTPS and removing x-powered-by from response * moving messages to constants, creating https instance fixture * testing HTTPS requiring * testing Date header * testing permission check * testing allowed operation * refactoring + storage stub * create architecture for generic operations * beginning of READ operation * tidying the code up * basic READ part * going further with READ operation * DELETE operation * handling fields parameter * refactoring to classes * going further with SEARCH operation * refactoring file structure * filtering for SEARCH operation * preparations for fallback deduplication * CREATE operation * UPDATE operation * PATCH operation * HISTORY operation * creating more precise variant of HISTORY operation * autopruning * long for timestamps in swagger * bug fix (when search fields=srvCreated) * creating skeleton for generic collection API test * specific HISTORY skeleton * distinguish between collection logical and storage name * renaming operation to LAST MODIFIED and getting it to work * fallback for LAST MODIFIED operation * tidying a bit * LAST MODIFIED documentation * bugfix + emitting data-received * adding some validations * bugfix - remove 'token' parameter from filtering * testing and debugging generic workflow * test fix for empty db * fixing security test fixture * trying to fix Travis CI testing DB problem * multiple auth callback bugfix + adding user field on authed create/update * messages for Travis CI debugging * messages for Travis CI debugging * messages for Travis CI debugging * test fix (to be prepared for future dates in db) * test fix * adding fallback created_at filling on each create/update * STATUS operation with API permissions * querying srvDate from storage + include storage version info * bugfix of missing apiConst require * getting mongo version with read-only user rights * getting mongo current date with read-only user rights * trying to diagnose travis CI timeout * refactoring storage version caching (due to some environments problems) * making VERSION work on empty database * more fixes * skipping API HTTPS test for node 8 * making code more readable using ES6 (Promises, async + await) * extending treatments collection docs by inspecting the careportal code * tidying existing API3 tests up to allow further grow * tidying the authorization code up to increase readability and performance a bit * more refactoring to ES6 and making APIv3 files structure more extendable * normalizing incoming dates to UTC and storing utcOffset * fixing srvDate to be of node.js server, not the mongo DB * preparing test fixtures for permissions testing + skeleton for CREATE operation test * intensive CREATE operation testing + minor bug fixes * correcting the deduplication test * more deduplication testing of CREATE operation * adding test skeletons for other generic operations * added variability in filtering by date, created_at, srvModified, srvCreated fields * fixing test accordingly to previous commit * adding new collection settings for centralized apps' settings storage * trying to solve travis CI testing problem - adding default collections names * another attempt to travis CI test fix * adding some tests for READ operation * adding custom error handler (overriding bodyparser's errors) * securing settings collection more and updating swagger accordingly * making HISTORY timestamp parameter more flexible + updating swagger documentation * more testing and bug fixing * sending only HTTP status with empty body, when there is no message + minor bug fixing * more refactoring and testing (especially of UPDATE operation) * PATCH testing + adding userModified field for troubleshooting purposes * basic SEARCH operation testing * more SEARCH operation testing * adding alternative 'now' query parameter to 'Date' header to make GET easier * adding 'now' to reserved query parameters for SEARCH operation * more testing * renaming field user to subject (and modifiedBy) * bugfix - fixing RFC 2822 constant for moment parsing * storageSocket: creating skeleton for new Socket.IO namespace * storageSocket: authentication by accessToken * storageSocket: authorizing to subscribe rooms * storageSocket: emitting create, update and delete events * APIv3: adding support for swagger UI at /api/v3/swagger-ui-dist * solving some problems detected by eslint * solving some problems detected by eslint * APIv3: testing and debugging Socket.IO * APIv3: testing and debugging Socket.IO * APIv3: Socket.IO documentation * APIv3: making the sample real * APIv3: starting to create a simple tutorial MD file * APIv3: small corrections * APIv3: minor corrections after dev merge * APIv3: adding CREATE and READ operations to the tutorial.md * APIv3: adding SEARCH, LAST MODIFIED, UPDATE operations to the tutorial.md * APIv3: finishing the tutorial.md * APIv3: minor bugfix (bad location after upsert) * APIv3: refactoring SEARCH complexity * APIv3: refactoring mongoCollection complexity * APIv3: refactoring complexity * APIv3: tidying up a bit * APIv3: refactoring security (start) * APIv3: refactoring lastModified * APIv3: refactoring create (start) * APIv3: refactoring create (finish) * APIv3: refactoring delete * APIv3: refactoring history * APIv3: refactoring update * APIv3: refactoring patch * APIv3: refactoring read * APIv3: refactoring search + removing deprecated authorizationBuilder * APIv3: adding best practise for identifier constructing * APIv3: refactoring and enhancing the validation (immutable fields) * APIv3: adding security.md documentation file * APIv3: refactoring - splitting index.js into multiple files * APIv3: calculating identifier on server side + deduplicating * APIv3: refactoring cosmetics * APIv3: updating the documentation * APIv3: making basic and security tests more readable using async/await * APIv3: making the rest of tests more readable using async/await * APIv3: adapting test of previous API * APIv3: adapting test of previous API
204 lines
6.6 KiB
JavaScript
204 lines
6.6 KiB
JavaScript
'use strict';
|
|
|
|
var _each = require('lodash/each');
|
|
var _trim = require('lodash/trim');
|
|
var _forIn = require('lodash/forIn');
|
|
var _startsWith = require('lodash/startsWith');
|
|
var _camelCase = require('lodash/camelCase');
|
|
|
|
var fs = require('fs');
|
|
var crypto = require('crypto');
|
|
var consts = require('./lib/constants');
|
|
|
|
var env = {
|
|
settings: require('./lib/settings')()
|
|
};
|
|
|
|
// Module to constrain all config and environment parsing to one spot.
|
|
// See the
|
|
function config ( ) {
|
|
/*
|
|
* See README.md for info about all the supported ENV VARs
|
|
*/
|
|
env.DISPLAY_UNITS = readENV('DISPLAY_UNITS', 'mg/dl');
|
|
|
|
// be lenient at accepting the mmol input
|
|
if (env.DISPLAY_UNITS.toLowerCase().includes('mmol')) {
|
|
env.DISPLAY_UNITS = 'mmol';
|
|
} else {
|
|
// also ensure the mg/dl is set with expected case
|
|
env.DISPLAY_UNITS = 'mg/dl';
|
|
}
|
|
|
|
console.log('Units set to', env.DISPLAY_UNITS );
|
|
|
|
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.debug = {
|
|
minify: readENVTruthy('DEBUG_MINIFY', true)
|
|
};
|
|
|
|
if (env.err) {
|
|
delete env.err;
|
|
}
|
|
|
|
setSSL();
|
|
setAPISecret();
|
|
setVersion();
|
|
setStorage();
|
|
updateSettings();
|
|
|
|
return env;
|
|
}
|
|
|
|
function setSSL() {
|
|
env.SSL_KEY = readENV('SSL_KEY');
|
|
env.SSL_CERT = readENV('SSL_CERT');
|
|
env.SSL_CA = readENV('SSL_CA');
|
|
env.ssl = false;
|
|
if (env.SSL_KEY && env.SSL_CERT) {
|
|
env.ssl = {
|
|
key: fs.readFileSync(env.SSL_KEY), cert: fs.readFileSync(env.SSL_CERT)
|
|
};
|
|
if (env.SSL_CA) {
|
|
env.ca = fs.readFileSync(env.SSL_CA);
|
|
}
|
|
}
|
|
|
|
env.insecureUseHttp = readENVTruthy("INSECURE_USE_HTTP", false);
|
|
env.secureHstsHeader = readENVTruthy("SECURE_HSTS_HEADER", true);
|
|
env.secureHstsHeaderIncludeSubdomains = readENVTruthy("SECURE_HSTS_HEADER_INCLUDESUBDOMAINS", false);
|
|
env.secureHstsHeaderPreload= readENVTruthy("SECURE_HSTS_HEADER_PRELOAD", false);
|
|
env.secureCsp = readENVTruthy("SECURE_CSP", false);
|
|
env.secureCspReportOnly = readENVTruthy("SECURE_CSP_REPORT_ONLY", false);
|
|
}
|
|
|
|
// A little ugly, but we don't want to read the secret into a var
|
|
function setAPISecret() {
|
|
var useSecret = (readENV('API_SECRET') && readENV('API_SECRET').length > 0);
|
|
//TODO: should we clear API_SECRET from process env?
|
|
env.api_secret = null;
|
|
// if a passphrase was provided, get the hex digest to mint a single token
|
|
if (useSecret) {
|
|
if (readENV('API_SECRET').length < consts.MIN_PASSPHRASE_LENGTH) {
|
|
var msg = ['API_SECRET should be at least', consts.MIN_PASSPHRASE_LENGTH, 'characters'].join(' ');
|
|
console.error(msg);
|
|
env.err = {desc: msg};
|
|
} else {
|
|
var shasum = crypto.createHash('sha1');
|
|
shasum.update(readENV('API_SECRET'));
|
|
env.api_secret = shasum.digest('hex');
|
|
|
|
if (!readENV('TREATMENTS_AUTH', true)) {
|
|
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
function setVersion() {
|
|
var software = require('./package.json');
|
|
env.version = software.version;
|
|
env.name = software.name;
|
|
}
|
|
|
|
function setStorage() {
|
|
env.storageURI = readENV('STORAGE_URI') || readENV('MONGO_CONNECTION') || readENV('MONGO') || readENV('MONGOLAB_URI') || readENV('MONGODB_URI');
|
|
env.entries_collection = readENV('ENTRIES_COLLECTION') || readENV('MONGO_COLLECTION', 'entries');
|
|
env.authentication_collections_prefix = readENV('MONGO_AUTHENTICATION_COLLECTIONS_PREFIX', 'auth_');
|
|
env.treatments_collection = readENV('MONGO_TREATMENTS_COLLECTION', 'treatments');
|
|
env.profile_collection = readENV('MONGO_PROFILE_COLLECTION', 'profile');
|
|
env.settings_collection = readENV('MONGO_SETTINGS_COLLECTION', 'settings');
|
|
env.devicestatus_collection = readENV('MONGO_DEVICESTATUS_COLLECTION', 'devicestatus');
|
|
env.food_collection = readENV('MONGO_FOOD_COLLECTION', 'food');
|
|
env.activity_collection = readENV('MONGO_ACTIVITY_COLLECTION', 'activity');
|
|
|
|
// 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'),
|
|
DB_URL = DB.url ? DB.url : env.storageURI,
|
|
DB_COLLECTION = DB.collection ? DB.collection : env.entries_collection;
|
|
env.storageURI = DB_URL;
|
|
env.entries_collection = DB_COLLECTION;
|
|
}
|
|
|
|
function updateSettings() {
|
|
|
|
var envNameOverrides = {
|
|
UNITS: 'DISPLAY_UNITS'
|
|
};
|
|
|
|
env.settings.eachSettingAsEnv(function settingFromEnv (name) {
|
|
var envName = envNameOverrides[name] || name;
|
|
return readENV(envName);
|
|
});
|
|
|
|
//should always find extended settings last
|
|
env.extendedSettings = findExtendedSettings(process.env);
|
|
|
|
if (!readENVTruthy('TREATMENTS_AUTH', true)) {
|
|
env.settings.authDefaultRoles = env.settings.authDefaultRoles || "";
|
|
env.settings.authDefaultRoles += ' careportal';
|
|
}
|
|
|
|
|
|
}
|
|
|
|
function readENV(varName, defaultValue) {
|
|
//for some reason Azure uses this prefix, maybe there is a good reason
|
|
var value = process.env['CUSTOMCONNSTR_' + varName]
|
|
|| process.env['CUSTOMCONNSTR_' + varName.toLowerCase()]
|
|
|| process.env[varName]
|
|
|| process.env[varName.toLowerCase()];
|
|
|
|
|
|
return value != null ? value : defaultValue;
|
|
}
|
|
|
|
function readENVTruthy(varName, defaultValue) {
|
|
var value = readENV(varName, defaultValue);
|
|
if (typeof value === 'string' && (value.toLowerCase() === 'on' || value.toLowerCase() === 'true')) { value = true; }
|
|
else if (typeof value === 'string' && (value.toLowerCase() === 'off' || value.toLowerCase() === 'false')) { value = false; }
|
|
else { value=defaultValue }
|
|
return value;
|
|
}
|
|
|
|
function findExtendedSettings (envs) {
|
|
var extended = {};
|
|
|
|
extended.devicestatus = {};
|
|
extended.devicestatus.advanced = true;
|
|
|
|
function normalizeEnv (key) {
|
|
return key.toUpperCase().replace('CUSTOMCONNSTR_', '');
|
|
}
|
|
|
|
_each(env.settings.enable, function eachEnable(enable) {
|
|
if (_trim(enable)) {
|
|
_forIn(envs, function eachEnvPair (value, key) {
|
|
var env = normalizeEnv(key);
|
|
if (_startsWith(env, enable.toUpperCase() + '_')) {
|
|
var split = env.indexOf('_');
|
|
if (split > -1 && split <= env.length) {
|
|
var exts = extended[enable] || {};
|
|
extended[enable] = exts;
|
|
var ext = _camelCase(env.substring(split + 1).toLowerCase());
|
|
if (!isNaN(value)) { value = Number(value); }
|
|
if (typeof value === 'string' && (value.toLowerCase() === 'on' || value.toLowerCase() === 'true')) { value = true; }
|
|
if (typeof value === 'string' && (value.toLowerCase() === 'off' || value.toLowerCase() === 'false')) { value = false; }
|
|
exts[ext] = value;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
return extended;
|
|
}
|
|
|
|
module.exports = config;
|