mirror of
https://github.com/bckelley/cgm-remote-monitor.git
synced 2026-08-24 03:14:12 -05:00
Security improvement batch (#6622)
* Adds a new method for the server to push notifies to the client, which require administration privileges from the user. If there are messages in queue but user is not privileged, she is notified of pending messages * Fix unit tests * Increase timeouts on tests * Add translations * * Aggregate admin messages * Send admin message on auth fail * Sending messages over bus * XSS filtering of objects sent over the REST API * Warn users if their instance is world readable * Fix adminnotifies init() * Fix couple issues from Codacy
This commit is contained in:
@@ -28,5 +28,4 @@ npm-debug.log
|
||||
/cgm-remote-monitor.njsproj
|
||||
/cgm-remote-monitor.sln
|
||||
/obj/Debug
|
||||
/bin
|
||||
/*.bat
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,117 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const axios = require('axios');
|
||||
const moment = require('moment');
|
||||
const crypto = require('crypto');
|
||||
const shasum = crypto.createHash('sha1');
|
||||
|
||||
const FIVE_MINUTES = 1000 * 60 * 5;
|
||||
|
||||
if (process.argv.length < 4) {
|
||||
console.error('This is an utility to send continuous CGM entry data to a test Nightscout server')
|
||||
console.error('USAGE: node testdatarunner.js <SERVER BASE URL> <API_SECRET>');
|
||||
process.exit();
|
||||
}
|
||||
|
||||
const URL = process.argv[2];
|
||||
const SECRET = process.argv[3];
|
||||
shasum.update(SECRET);
|
||||
const SECRET_SHA1 = shasum.digest('hex');
|
||||
|
||||
const HEADERS = {'api-secret': SECRET_SHA1};
|
||||
|
||||
const ENTRIES_URL = URL + '/api/v1/entries';
|
||||
|
||||
var done = (function wait () { if (!done) setTimeout(wait, 1000); })();
|
||||
|
||||
console.log('NS data filler active');
|
||||
|
||||
const entry = {
|
||||
device: 'Dev simulator',
|
||||
date: 1609061083612,
|
||||
dateString: '2020-12-27T09:24:43.612Z',
|
||||
sgv: 100,
|
||||
delta: 0,
|
||||
direction: 'Flat',
|
||||
type: 'sgv'
|
||||
};
|
||||
|
||||
function addEntry () {
|
||||
console.log('Sending add new entry');
|
||||
sendEntry(Date.now());
|
||||
setTimeout(addEntry, FIVE_MINUTES);
|
||||
}
|
||||
|
||||
function oscillator(time, frequency = 1, amplitude = 1, phase = 0, offset = 0){
|
||||
return Math.sin(time * frequency * Math.PI * 2 + phase * Math.PI * 2) * amplitude + offset;
|
||||
}
|
||||
|
||||
async function sendFail() {
|
||||
try {
|
||||
console.log('Sending fail');
|
||||
const response = await axios.post(ENTRIES_URL, entry, {headers: {'api-secret': 'incorrect' }});
|
||||
} catch (e) { }
|
||||
}
|
||||
|
||||
async function sendEntry (date) {
|
||||
const m = moment(date);
|
||||
entry.date = date;
|
||||
entry.dateString = m.toISOString();
|
||||
entry.sgv = 100 + Math.round(oscillator(date / 1000, 1/(60*60), 30));
|
||||
|
||||
console.log('Adding entry', entry);
|
||||
const response = await axios.post(ENTRIES_URL, entry, {headers: HEADERS});
|
||||
|
||||
if (date > Date.now() - 5000) sendFail();
|
||||
}
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
console.log('GETTING', ENTRIES_URL);
|
||||
const response = await axios.get(ENTRIES_URL, {headers: HEADERS} );
|
||||
const latestEntry = response.data ? response.data[0] : null;
|
||||
|
||||
if (!latestEntry) {
|
||||
// Fill in history
|
||||
console.log('I would fill in history');
|
||||
const totalToSave = 24;
|
||||
const now = Date.now();
|
||||
const start = now - ( totalToSave * FIVE_MINUTES);
|
||||
let current = start;
|
||||
while (current <= now) {
|
||||
await sendEntry(current);
|
||||
current += FIVE_MINUTES;
|
||||
}
|
||||
|
||||
setTimeout(addEntry, 1000*60*5);
|
||||
|
||||
} else {
|
||||
let latestDate = latestEntry.date;
|
||||
const now = Date.now();
|
||||
if ((now - latestDate) > FIVE_MINUTES) {
|
||||
console.log('We got data but it is older than 5 minutes, makign a partial fill');
|
||||
|
||||
let current = latestDate + FIVE_MINUTES;
|
||||
|
||||
while (current < now) {
|
||||
await sendEntry(current);
|
||||
current += FIVE_MINUTES;
|
||||
}
|
||||
|
||||
latestDate = current;
|
||||
|
||||
} else {
|
||||
console.log('Looks like we got history, not filling');
|
||||
}
|
||||
setTimeout(addEntry, Date.now() - latestDate);
|
||||
}
|
||||
|
||||
sendFail();
|
||||
sendFail();
|
||||
|
||||
} catch (error) {
|
||||
console.log(error.response.data);
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
'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');
|
||||
const _each = require('lodash/each');
|
||||
const _trim = require('lodash/trim');
|
||||
const _forIn = require('lodash/forIn');
|
||||
const _startsWith = require('lodash/startsWith');
|
||||
const _camelCase = require('lodash/camelCase');
|
||||
|
||||
var fs = require('fs');
|
||||
var crypto = require('crypto');
|
||||
var consts = require('./lib/constants');
|
||||
const owasp = require('owasp-password-strength-test');
|
||||
|
||||
var env = {
|
||||
|
||||
const fs = require('fs');
|
||||
const crypto = require('crypto');
|
||||
const consts = require('./lib/constants');
|
||||
|
||||
const env = {
|
||||
settings: require('./lib/settings')()
|
||||
};
|
||||
|
||||
@@ -36,9 +39,8 @@ function config ( ) {
|
||||
minify: readENVTruthy('DEBUG_MINIFY', true)
|
||||
};
|
||||
|
||||
if (env.err) {
|
||||
delete env.err;
|
||||
}
|
||||
env.err = [];
|
||||
env.notifies = [];
|
||||
|
||||
setSSL();
|
||||
setAPISecret();
|
||||
@@ -81,10 +83,21 @@ function setAPISecret() {
|
||||
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};
|
||||
env.err.push({ desc: msg });
|
||||
} else {
|
||||
var shasum = crypto.createHash('sha1');
|
||||
shasum.update(readENV('API_SECRET'));
|
||||
|
||||
var testresult = owasp.test(readENV('API_SECRET'));
|
||||
const messages = testresult.errors;
|
||||
|
||||
if (messages) {
|
||||
messages.forEach(message => {
|
||||
const m = message.replace('The password must', 'API_SECRET should');
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
|
||||
function init (ctx) {
|
||||
|
||||
const adminnotifies = {};
|
||||
|
||||
adminnotifies.addNotify = function addnotify (notify) {
|
||||
if (!notify) return;
|
||||
|
||||
notify.title = notify.title || 'No title';
|
||||
notify.message = notify.message || 'No message';
|
||||
|
||||
const existingMessage = _.find(adminnotifies.notifies, function findExisting (obj) {
|
||||
return obj.message == notify.message;
|
||||
});
|
||||
|
||||
if (existingMessage) {
|
||||
existingMessage.count += 1;
|
||||
existingMessage.lastRecorded = Date.now();
|
||||
} else {
|
||||
notify.count = 1;
|
||||
notify.lastRecorded = Date.now();
|
||||
adminnotifies.notifies.push(notify);
|
||||
}
|
||||
}
|
||||
|
||||
adminnotifies.getNotifies = function getNotifies () {
|
||||
return adminnotifies.notifies;
|
||||
}
|
||||
|
||||
ctx.bus.on('admin-notify', adminnotifies.addNotify);
|
||||
|
||||
adminnotifies.clean = function cleanNotifies () {
|
||||
adminnotifies.notifies = _.filter(adminnotifies.notifies, function findExisting (obj) {
|
||||
return obj.persistent || ((Date.now() - obj.lastRecorded) < 1000 * 60 * 60 * 12);
|
||||
});
|
||||
}
|
||||
|
||||
adminnotifies.cleanAll = function cleanAll() {
|
||||
adminnotifies.notifies = [];
|
||||
}
|
||||
|
||||
adminnotifies.cleanAll();
|
||||
|
||||
ctx.bus.on('tick', adminnotifies.clean);
|
||||
|
||||
return adminnotifies;
|
||||
}
|
||||
|
||||
module.exports = init;
|
||||
@@ -0,0 +1,35 @@
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
const consts = require('../constants');
|
||||
|
||||
function configure (ctx) {
|
||||
const express = require('express')
|
||||
, api = express.Router();
|
||||
|
||||
api.get('/adminnotifies', function(req, res) {
|
||||
ctx.authorization.resolveWithRequest(req, function resolved (err, result) {
|
||||
|
||||
const isAdmin = ctx.authorization.checkMultiple('*:*:admin', result.shiros); //full admin permissions
|
||||
const response = {
|
||||
notifies: []
|
||||
, notifyCount: 0
|
||||
};
|
||||
|
||||
if (ctx.adminnotifies) {
|
||||
const notifies = _.filter(ctx.adminnotifies.getNotifies(), function isOld (obj) {
|
||||
return (obj.persistent || (Date.now() - obj.lastRecorded) < 1000 * 60 * 60 * 8);
|
||||
});
|
||||
|
||||
if (isAdmin) { response.notifies = notifies }
|
||||
response.notifyCount = notifies.length;
|
||||
}
|
||||
|
||||
res.sendJSONStatus(res, consts.HTTP_OK, response);
|
||||
});
|
||||
});
|
||||
|
||||
return api;
|
||||
}
|
||||
|
||||
module.exports = configure;
|
||||
@@ -67,6 +67,9 @@ function configure (app, wares, ctx, env) {
|
||||
|
||||
function doPost (req, res) {
|
||||
var obj = req.body;
|
||||
|
||||
ctx.purifier.purifyObject(obj);
|
||||
|
||||
ctx.devicestatus.create(obj, function(err, created) {
|
||||
if (err) {
|
||||
res.sendJSONStatus(res, consts.HTTP_INTERNAL_ERROR, 'Mongo Error', err);
|
||||
|
||||
@@ -274,6 +274,11 @@ function configure (app, wares, ctx, env) {
|
||||
incoming = incoming.concat(req.body);
|
||||
}
|
||||
|
||||
for (let i = 0; i < incoming.length; i++) {
|
||||
const e = incoming[i];
|
||||
ctx.purifier.purifyObject(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @function persist
|
||||
* @returns {WritableStream} a writable persistent storage stream
|
||||
|
||||
@@ -58,6 +58,9 @@ function create (env, ctx) {
|
||||
app.all('/activity*', require('./activity/')(app, wares, ctx));
|
||||
|
||||
app.use('/', wares.sendJSONStatus, require('./verifyauth')(ctx));
|
||||
|
||||
app.use('/', wares.sendJSONStatus, require('./adminnotifiesapi')(ctx));
|
||||
|
||||
app.all('/food*', require('./food/')(app, wares, ctx));
|
||||
|
||||
// Status first
|
||||
|
||||
@@ -61,6 +61,7 @@ function configure (app, wares, ctx) {
|
||||
// create new record
|
||||
api.post('/profile/', ctx.authorization.isPermitted('api:profile:create'), function(req, res) {
|
||||
var data = req.body;
|
||||
ctx.purifier.purifyObject(data);
|
||||
ctx.profile.create(data, function (err, created) {
|
||||
if (err) {
|
||||
res.sendJSONStatus(res, consts.HTTP_INTERNAL_ERROR, 'Mongo Error', err);
|
||||
|
||||
@@ -119,6 +119,8 @@ function configure (app, wares, ctx, env) {
|
||||
t.created_at = new Date().toISOString();
|
||||
}
|
||||
|
||||
ctx.purifier.purifyObject(t);
|
||||
|
||||
/*
|
||||
if (!t.created_at) {
|
||||
console.log('Trying to create treatment without created_at field', t);
|
||||
|
||||
@@ -9,8 +9,6 @@ function init (env) {
|
||||
const DELAY_ON_FAIL = _.get(env, 'settings.authFailDelay') || 5000;
|
||||
const FAIL_AGE = 60000;
|
||||
|
||||
const sleep = require('util').promisify(setTimeout);
|
||||
|
||||
ipDelayList.addFailedRequest = function addFailedRequest (ip) {
|
||||
const ipString = String(ip);
|
||||
let entry = ipDelayList[ipString];
|
||||
|
||||
@@ -5,10 +5,8 @@ const jwt = require('jsonwebtoken');
|
||||
const shiroTrie = require('shiro-trie');
|
||||
|
||||
const consts = require('./../constants');
|
||||
|
||||
const sleep = require('util').promisify(setTimeout);
|
||||
|
||||
|
||||
function getRemoteIP (req) {
|
||||
return req.headers['x-forwarded-for'] || req.connection.remoteAddress;
|
||||
}
|
||||
@@ -208,7 +206,13 @@ function init (env, ctx) {
|
||||
|
||||
console.error('Resolving secret/token to permissions failed');
|
||||
addFailedRequest(data.ip);
|
||||
if (callback) { callback('All validation failed', {}); }
|
||||
|
||||
ctx.bus.emit('admin-notify', {
|
||||
title: ctx.language.translate('Failed authentication')
|
||||
, message: ctx.language.translate('A device at IP number') + ' ' + data.ip + ' ' + ctx.language.translate('attempted authenticating with Nightscout with wrong credentials. Check if you have an uploader setup with wrong API_SECRET or token?')
|
||||
});
|
||||
|
||||
if (callback) { callback('All validation failed', {}); }
|
||||
return {};
|
||||
|
||||
};
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
'use strict';
|
||||
|
||||
function init (client, $) {
|
||||
|
||||
var notifies = {};
|
||||
|
||||
client.notifies = notifies;
|
||||
|
||||
notifies.notifies = [];
|
||||
notifies.drawer = $('#adminNotifiesDrawer');
|
||||
notifies.button = $('#adminnotifies');
|
||||
|
||||
notifies.updateAdminNotifies = function updateAdminNotifies() {
|
||||
|
||||
var src = '/api/v1/adminnotifies?t=' + new Date().getTime();
|
||||
|
||||
$.ajax({
|
||||
method: 'GET'
|
||||
, url: src
|
||||
, headers: client.headers()
|
||||
}).done(function success (results) {
|
||||
if (results.message) {
|
||||
var m = results.message;
|
||||
client.notifies.notifies = m.notifies;
|
||||
client.notifies.notifyCount = m.notifyCount;
|
||||
if (m.notifyCount > 0) {
|
||||
notifies.button.show();
|
||||
}
|
||||
}
|
||||
window.setTimeout(notifies.updateAdminNotifies, 1000*60);
|
||||
}).fail(function fail () {
|
||||
console.error('Failed to load notifies');
|
||||
window.setTimeout(notifies.updateAdminNotifies, 1000*60);
|
||||
});
|
||||
}
|
||||
|
||||
notifies.updateAdminNotifies();
|
||||
|
||||
function wrapmessage(title, message, count, ago, persistent) {
|
||||
let html = '<hr><p><b>' + title + '</b></p><p class="adminNotifyMessage">' + message + '</p>';
|
||||
|
||||
let additional = '';
|
||||
|
||||
if (count > 1) additional += 'Event repeated ' + count + ' times.' + ' ';
|
||||
let units = 'minutes';
|
||||
if (ago > 60) {
|
||||
ago = ago / 60;
|
||||
units = 'hours';
|
||||
}
|
||||
if (!persistent) additional += 'Last recorded ' + ago + ' '+ units + ' ago.';
|
||||
|
||||
if (additional) html += '<p class="adminNotifyMessageAdditionalInfo">' + additional + '</p>'
|
||||
return html;
|
||||
}
|
||||
|
||||
notifies.prepare = function prepare() {
|
||||
|
||||
var translate = client.translate;
|
||||
|
||||
var html = '<div id="adminNotifyContent">';
|
||||
var messages = client.notifies.notifies;
|
||||
var messageCount = client.notifies.notifyCount;
|
||||
|
||||
if (messages && messages.length > 0) {
|
||||
html += '<p><b>' + translate('You have administration messages') + '</b></p>';
|
||||
for(var i = 0 ; i < messages.length; i++) {
|
||||
var m = messages[i];
|
||||
const ago = Math.round((Date.now() - m.lastRecorded) / 60000);
|
||||
html += wrapmessage(m.title, m.message, m.count, ago, m.persistent);
|
||||
}
|
||||
} else {
|
||||
if (messageCount > 0) {
|
||||
html = wrapmessage(translate('Admin messages in queue'), translate('Please sign in using the API_SECRET to see your administration messages'));
|
||||
} else {
|
||||
html = wrapmessage(translate('Queue empty'), translate('There are no admin messages in queue'));
|
||||
}
|
||||
}
|
||||
html += '<hr></div>';
|
||||
notifies.drawer.html(html);
|
||||
}
|
||||
|
||||
function maybePrevent (event) {
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
notifies.toggleDrawer = function toggleDrawer (event) {
|
||||
client.browserUtils.toggleDrawer('#adminNotifiesDrawer', notifies.prepare);
|
||||
maybePrevent(event);
|
||||
};
|
||||
|
||||
notifies.button.click(notifies.toggleDrawer);
|
||||
notifies.button.css('color','red');
|
||||
|
||||
return notifies;
|
||||
|
||||
}
|
||||
|
||||
module.exports = init;
|
||||
@@ -237,6 +237,8 @@ client.load = function load (serverSettings, callback) {
|
||||
//After plugins are initialized with browser settings;
|
||||
browserSettings.loadAndWireForm();
|
||||
|
||||
client.adminnotifies = require('./adminnotifiesclient')(client, $);
|
||||
|
||||
if (serverSettings && serverSettings.authorized) {
|
||||
client.authorized = serverSettings.authorized;
|
||||
client.authorized.lat = Date.now();
|
||||
@@ -266,6 +268,8 @@ client.load = function load (serverSettings, callback) {
|
||||
$('#treatmentDrawerToggle').toggle(treatmentCreateAllowed && client.settings.showPlugins.indexOf('careportal') > -1);
|
||||
$('#boluscalcDrawerToggle').toggle(treatmentCreateAllowed && client.settings.showPlugins.indexOf('boluscalc') > -1);
|
||||
|
||||
if (isAuthenticated) client.notifies.updateAdminNotifies();
|
||||
|
||||
// Edit mode
|
||||
editButton.toggle(client.settings.editMode && treatmentUpdateAllowed);
|
||||
editButton.click(function editModeClick (event) {
|
||||
|
||||
+20
-16
@@ -1,8 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
|
||||
var UPDATE_THROTTLE = 5000;
|
||||
const _ = require('lodash');
|
||||
const UPDATE_THROTTLE = 5000;
|
||||
|
||||
function boot (env, language) {
|
||||
|
||||
@@ -11,23 +10,19 @@ function boot (env, language) {
|
||||
console.log('Executing startBoot');
|
||||
|
||||
ctx.runtimeState = 'booting';
|
||||
ctx.bus = require('../bus')(env.settings, ctx);
|
||||
ctx.adminnotifies = require('../adminnotifies')(ctx);
|
||||
if (env.notifies) {
|
||||
ctx.adminnotifies.addNotify(env.notifies[0]); // TODO iterate all
|
||||
}
|
||||
|
||||
next();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// Check Node version.
|
||||
// Latest Node 8 LTS and Latest Node 10 LTS are recommended and supported.
|
||||
// Latest Node version on Azure is tolerated, but not recommended
|
||||
// Latest Node (non LTS) version works, but is not recommended
|
||||
// Latest Node 10 to 14 LTS are recommended and supported.
|
||||
// Older Node versions or Node versions with known security issues will not work.
|
||||
// More explicit:
|
||||
// < 8 does not work, not supported
|
||||
// >= 8.15.1 works, supported and recommended
|
||||
// == 9.x does not work, not supported
|
||||
// == 10.15.2 works, not fully supported and not recommended (Azure version)
|
||||
// >= 10.16.0 works, supported and recommended
|
||||
// == 11.x does not work, not supported
|
||||
// >= 12.6.0 does work, not recommended, will not be supported. We only support Node LTS releases
|
||||
///////////////////////////////////////////////////
|
||||
function checkNodeVersion (ctx, next) {
|
||||
|
||||
@@ -56,7 +51,7 @@ function boot (env, language) {
|
||||
console.log('Executing checkEnv');
|
||||
|
||||
ctx.language = language;
|
||||
if (env.err) {
|
||||
if (env.err.length > 0) {
|
||||
ctx.bootErrors = ctx.bootErrors || [ ];
|
||||
ctx.bootErrors.push({'desc': 'ENV Error', err: env.err});
|
||||
}
|
||||
@@ -121,6 +116,15 @@ function boot (env, language) {
|
||||
err: 'API_SECRET setting is missing, cannot enable REST API'});
|
||||
}
|
||||
|
||||
if (env.settings.authDefaultRoles == 'readable') {
|
||||
const message = {
|
||||
title: "Nightscout readable by world"
|
||||
,message: "Your Nightscout installation is readable by anyone who knows the web page URL. Please consider closing access to the site by following the instructions in the <a href=\"http://nightscout.github.io/nightscout/admin_tools/#turn-off-unauthorized-access\" target=\"_new\">Nightscout documentation</a>."
|
||||
,persistent: true
|
||||
};
|
||||
ctx.adminnotifies.addNotify(message);
|
||||
}
|
||||
|
||||
next();
|
||||
}
|
||||
|
||||
@@ -215,11 +219,11 @@ function boot (env, language) {
|
||||
ctx.food = require('./food')(env, ctx);
|
||||
ctx.pebble = require('./pebble')(env, ctx);
|
||||
ctx.properties = require('../api/properties')(env, ctx);
|
||||
ctx.bus = require('../bus')(env.settings, ctx);
|
||||
ctx.ddata = require('../data/ddata')();
|
||||
ctx.cache = require('./cache')(env,ctx);
|
||||
ctx.dataloader = require('../data/dataloader')(env, ctx);
|
||||
ctx.notifications = require('../notifications')(env, ctx);
|
||||
ctx.purifier = require('./purifier')(env,ctx);
|
||||
|
||||
if (env.settings.isEnabled('alexa') || env.settings.isEnabled('googlehome')) {
|
||||
ctx.virtAsstBase = require('../plugins/virtAsstBase')(env, ctx);
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
'use strict';
|
||||
|
||||
const createDOMPurify = require('dompurify');
|
||||
const { JSDOM } = require('jsdom');
|
||||
const window = new JSDOM('').window;
|
||||
const DOMPurify = createDOMPurify(window);
|
||||
|
||||
function init (env, ctx) {
|
||||
|
||||
const purifier = {};
|
||||
|
||||
function iterate (obj) {
|
||||
for (var property in obj) {
|
||||
if (obj.hasOwnProperty(property)) {
|
||||
if (typeof obj[property] == 'object')
|
||||
iterate(obj[property]);
|
||||
else
|
||||
if (isNaN(obj[property])) {
|
||||
const clean = DOMPurify.sanitize(obj[property]);
|
||||
if (obj[property] !== clean) {
|
||||
obj[property] = clean;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
purifier.purifyObject = function purifyObject (obj) {
|
||||
return iterate(obj);
|
||||
}
|
||||
|
||||
return purifier;
|
||||
|
||||
}
|
||||
|
||||
module.exports = init;
|
||||
Generated
+86
-61
@@ -1217,9 +1217,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"acorn": {
|
||||
"version": "6.4.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz",
|
||||
"integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA=="
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
|
||||
"integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1551,6 +1551,15 @@
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz",
|
||||
"integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA=="
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.21.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
|
||||
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"follow-redirects": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"babel-code-frame": {
|
||||
"version": "6.26.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
|
||||
@@ -2992,9 +3001,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"abab": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.4.tgz",
|
||||
"integrity": "sha512-Eu9ELJWCz/c1e9gTiCY+FceWxcqzjYEbqMgtndnuSqZSUCOL73TWNK2mHfIj4Cw2E/ongOp+JISVNCmovt2KYQ=="
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz",
|
||||
"integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q=="
|
||||
},
|
||||
"whatwg-url": {
|
||||
"version": "7.1.0",
|
||||
@@ -3171,6 +3180,11 @@
|
||||
"webidl-conversions": "^4.0.2"
|
||||
}
|
||||
},
|
||||
"dompurify": {
|
||||
"version": "2.2.6",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.2.6.tgz",
|
||||
"integrity": "sha512-7b7ZArhhH0SP6W2R9cqK6RjaU82FZ2UPM7RO8qN1b1wyvC/NY1FNWcX1Pu00fFOAnzEORtwXe4bPaClg6pUybQ=="
|
||||
},
|
||||
"dot-prop": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.1.tgz",
|
||||
@@ -3566,6 +3580,18 @@
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||
},
|
||||
"escodegen": {
|
||||
"version": "1.14.3",
|
||||
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz",
|
||||
"integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==",
|
||||
"requires": {
|
||||
"esprima": "^4.0.1",
|
||||
"estraverse": "^4.2.0",
|
||||
"esutils": "^2.0.2",
|
||||
"optionator": "^0.8.1",
|
||||
"source-map": "~0.6.1"
|
||||
}
|
||||
},
|
||||
"eslint": {
|
||||
"version": "6.8.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz",
|
||||
@@ -3761,6 +3787,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"esprima": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
|
||||
},
|
||||
"esquery": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz",
|
||||
@@ -3793,6 +3824,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"estraverse": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
|
||||
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="
|
||||
},
|
||||
"esutils": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
||||
@@ -4075,6 +4111,11 @@
|
||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
|
||||
},
|
||||
"fast-levenshtein": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
|
||||
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
|
||||
},
|
||||
"fastparse": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
|
||||
@@ -4253,6 +4294,12 @@
|
||||
"readable-stream": "^2.3.6"
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.13.1",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz",
|
||||
"integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==",
|
||||
"dev": true
|
||||
},
|
||||
"for-in": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
|
||||
@@ -5580,65 +5627,10 @@
|
||||
"xml-name-validator": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"escodegen": {
|
||||
"version": "1.14.3",
|
||||
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz",
|
||||
"integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==",
|
||||
"requires": {
|
||||
"esprima": "^4.0.1",
|
||||
"estraverse": "^4.2.0",
|
||||
"esutils": "^2.0.2",
|
||||
"optionator": "^0.8.1",
|
||||
"source-map": "~0.6.1"
|
||||
}
|
||||
},
|
||||
"esprima": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
|
||||
},
|
||||
"estraverse": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
|
||||
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="
|
||||
},
|
||||
"fast-levenshtein": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
|
||||
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
|
||||
},
|
||||
"levn": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
|
||||
"integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
|
||||
"requires": {
|
||||
"prelude-ls": "~1.1.2",
|
||||
"type-check": "~0.3.2"
|
||||
}
|
||||
},
|
||||
"optionator": {
|
||||
"version": "0.8.3",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
|
||||
"integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
|
||||
"requires": {
|
||||
"deep-is": "~0.1.3",
|
||||
"fast-levenshtein": "~2.0.6",
|
||||
"levn": "~0.3.0",
|
||||
"prelude-ls": "~1.1.2",
|
||||
"type-check": "~0.3.2",
|
||||
"word-wrap": "~1.2.3"
|
||||
}
|
||||
},
|
||||
"sax": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -5792,6 +5784,15 @@
|
||||
"leven": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"levn": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
|
||||
"integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
|
||||
"requires": {
|
||||
"prelude-ls": "~1.1.2",
|
||||
"type-check": "~0.3.2"
|
||||
}
|
||||
},
|
||||
"load-json-file": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
|
||||
@@ -8551,6 +8552,19 @@
|
||||
"integrity": "sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==",
|
||||
"dev": true
|
||||
},
|
||||
"optionator": {
|
||||
"version": "0.8.3",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
|
||||
"integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
|
||||
"requires": {
|
||||
"deep-is": "~0.1.3",
|
||||
"fast-levenshtein": "~2.0.6",
|
||||
"levn": "~0.3.0",
|
||||
"prelude-ls": "~1.1.2",
|
||||
"type-check": "~0.3.2",
|
||||
"word-wrap": "~1.2.3"
|
||||
}
|
||||
},
|
||||
"os-browserify": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
|
||||
@@ -8567,6 +8581,11 @@
|
||||
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
|
||||
},
|
||||
"owasp-password-strength-test": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/owasp-password-strength-test/-/owasp-password-strength-test-1.3.0.tgz",
|
||||
"integrity": "sha1-T2KeQpA+j20nmyMNZXq2HljkSxI="
|
||||
},
|
||||
"p-finally": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
|
||||
@@ -10340,6 +10359,12 @@
|
||||
"resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
|
||||
"integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw=="
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"optional": true
|
||||
},
|
||||
"source-map-resolve": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
|
||||
|
||||
+13
-2
@@ -37,11 +37,19 @@
|
||||
"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",
|
||||
"coverage": "cat ./coverage/lcov.info | env-cmd -f ./ci.test.env codacy-coverage",
|
||||
"dev": "env-cmd -f ./my.env nodemon server.js 0.0.0.0",
|
||||
"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",
|
||||
"lint": "eslint lib"
|
||||
},
|
||||
"main": "server.js",
|
||||
"nodemonConfig": {
|
||||
"ignore": [
|
||||
"tests/*",
|
||||
"node_modules/*",
|
||||
"bin/*"
|
||||
]
|
||||
},
|
||||
"config": {
|
||||
"blanket": {
|
||||
"pattern": [
|
||||
@@ -75,6 +83,7 @@
|
||||
"cssmin": "^0.4.3",
|
||||
"csv-stringify": "^5.5.1",
|
||||
"d3": "^5.16.0",
|
||||
"dompurify": "^2.2.6",
|
||||
"easyxml": "^2.0.1",
|
||||
"ejs": "^2.7.4",
|
||||
"errorhandler": "^1.5.1",
|
||||
@@ -89,7 +98,7 @@
|
||||
"jquery-ui-bundle": "^1.12.1-migrate",
|
||||
"jquery.tooltips": "^1.0.0",
|
||||
"js-storage": "^1.1.0",
|
||||
"jsdom": "~11.11.0",
|
||||
"jsdom": "^11.11.0",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"lodash": "^4.17.20",
|
||||
"memory-cache": "^0.2.0",
|
||||
@@ -102,6 +111,7 @@
|
||||
"mongodb": "^3.6.0",
|
||||
"mongomock": "^0.1.2",
|
||||
"node-cache": "^4.2.1",
|
||||
"owasp-password-strength-test": "^1.3.0",
|
||||
"parse-duration": "^0.1.3",
|
||||
"pem": "^1.14.4",
|
||||
"pushover-notifications": "^1.2.2",
|
||||
@@ -122,6 +132,7 @@
|
||||
"webpack-cli": "^3.3.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"axios": "^0.21.1",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"benv": "^3.3.0",
|
||||
"codacy-coverage": "^3.4.0",
|
||||
|
||||
+14
-1
@@ -49,7 +49,7 @@ input[type=number]:invalid {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#treatmentDrawer {
|
||||
#treatmentDrawer, #adminNotifiesDrawer {
|
||||
background-color: #666;
|
||||
border-left: 1px solid #999;
|
||||
box-shadow: inset 4px 4px 5px 0 rgba(50, 50, 50, 0.75);
|
||||
@@ -66,6 +66,19 @@ input[type=number]:invalid {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#adminNotifyContent {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.adminNotifyMessage {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.adminNotifyMessageAdditionalInfo {
|
||||
margin-left: 10px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
#treatmentDrawer input {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
+3
-2
@@ -16,8 +16,8 @@
|
||||
@font-face {
|
||||
font-family: 'pluginicons';
|
||||
/* Plugin Icons font files content (from WOFF and SVG icon files, base64 encoded) */
|
||||
src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAWAAAsAAAAABTQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABPUy8yAAABCAAAAGAAAABgDxIE8mNtYXAAAAFoAAAAVAAAAFQXVdKJZ2FzcAAAAbwAAAAIAAAACAAAABBnbHlmAAABxAAAAUgAAAFIFA4eR2hlYWQAAAMMAAAANgAAADYXVLrVaGhlYQAAA0QAAAAkAAAAJAdQA8ZobXR4AAADaAAAABQAAAAUCY4AAGxvY2EAAAN8AAAADAAAAAwAKAC4bWF4cAAAA4gAAAAgAAAAIAAJAFxuYW1lAAADqAAAAbYAAAG2DBt7mXBvc3QAAAVgAAAAIAAAACAAAwAAAAMCxwGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAA6QEDwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADgAAAAKAAgAAgACAAEAIOkB//3//wAAAAAAIOkB//3//wAB/+MXAwADAAEAAAAAAAAAAAAAAAEAAf//AA8AAQAAAAAAAAAAAAIAADc5AQAAAAABAAAAAAAAAAAAAgAANzkBAAAAAAEAAAAAAAAAAAACAAA3OQEAAAAAAwAA/8ADjgPAABsAOgBZAAABIgcOAQcGFRQXHgEXFjMyNz4BNzY1NCcuAScmARUUFx4BFxYzMjc+ATc2PQEUBw4BBwYjIicuAScmNREVFBceARcWMzI3PgE3Nj0BFAcOAQcGIyInLgEnJjUBx15TU3skJCQke1NTXl5TU3wjJCQjfFNT/dskJHtTU15eU1N8IyQkI3xTU15eU1N7JCQkJHtTU15eU1N8IyQkI3xTU15eU1N7JCQDwBISPikpMC8pKj0SEhISPSopLzApKT4SEv6rqy8qKT4SEhISPikqL6svKik+EhISEj4pKi/+46owKSk+EhISEj4pKTCqLykqPhESEhE+KikvAAAAAAEAAAABAABgRbaTXw889QALBAAAAAAA2lO7LAAAAADaU7ssAAD/wAOOA8AAAAAIAAIAAAAAAAAAAQAAA8D/wAAABAAAAAAAA44AAQAAAAAAAAAAAAAAAAAAAAUEAAAAAAAAAAAAAAACAAAAA44AAAAAAAAACgAUAB4ApAABAAAABQBaAAMAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAADgCuAAEAAAAAAAEACwAAAAEAAAAAAAIABwCEAAEAAAAAAAMACwBCAAEAAAAAAAQACwCZAAEAAAAAAAUACwAhAAEAAAAAAAYACwBjAAEAAAAAAAoAGgC6AAMAAQQJAAEAFgALAAMAAQQJAAIADgCLAAMAAQQJAAMAFgBNAAMAAQQJAAQAFgCkAAMAAQQJAAUAFgAsAAMAAQQJAAYAFgBuAAMAAQQJAAoANADUcGx1Z2luaWNvbnMAcABsAHUAZwBpAG4AaQBjAG8AbgBzVmVyc2lvbiAxLjAAVgBlAHIAcwBpAG8AbgAgADEALgAwcGx1Z2luaWNvbnMAcABsAHUAZwBpAG4AaQBjAG8AbgBzcGx1Z2luaWNvbnMAcABsAHUAZwBpAG4AaQBjAG8AbgBzUmVndWxhcgBSAGUAZwB1AGwAYQBycGx1Z2luaWNvbnMAcABsAHUAZwBpAG4AaQBjAG8AbgBzRm9udCBnZW5lcmF0ZWQgYnkgSWNvTW9vbi4ARgBvAG4AdAAgAGcAZQBuAGUAcgBhAHQAZQBkACAAYgB5ACAASQBjAG8ATQBvAG8AbgAuAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==) format('woff'),
|
||||
url(data:application/font-svg;charset=utf-8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg0KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIiA+DQo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+DQo8bWV0YWRhdGE+R2VuZXJhdGVkIGJ5IEljb01vb248L21ldGFkYXRhPg0KPGRlZnM+DQo8Zm9udCBpZD0icGx1Z2luaWNvbnMiIGhvcml6LWFkdi14PSIxMDI0Ij4NCjxmb250LWZhY2UgdW5pdHMtcGVyLWVtPSIxMDI0IiBhc2NlbnQ9Ijk2MCIgZGVzY2VudD0iLTY0IiAvPg0KPG1pc3NpbmctZ2x5cGggaG9yaXotYWR2LXg9IjEwMjQiIC8+DQo8Z2x5cGggdW5pY29kZT0iJiN4MjA7IiBob3Jpei1hZHYteD0iNTEyIiBkPSIiIC8+DQo8Z2x5cGggdW5pY29kZT0iJiN4ZTkwMTsiIGdseXBoLW5hbWU9ImRhdGFiYXNlIiBob3Jpei1hZHYteD0iOTEwIiBkPSJNNDU1LjExMSA5NjBjLTI1MS40NDkgMC00NTUuMTExLTEwMS44MzEtNDU1LjExMS0yMjcuNTU2czIwMy42NjItMjI3LjU1NiA0NTUuMTExLTIyNy41NTYgNDU1LjExMSAxMDEuODMxIDQ1NS4xMTEgMjI3LjU1Ni0yMDMuNjYyIDIyNy41NTYtNDU1LjExMSAyMjcuNTU2ek0wIDYxOC42Njd2LTE3MC42NjdjMC0xMjUuNzI0IDIwMy42NjItMjI3LjU1NiA0NTUuMTExLTIyNy41NTZzNDU1LjExMSAxMDEuODMxIDQ1NS4xMTEgMjI3LjU1NnYxNzAuNjY3YzAtMTI1LjcyNC0yMDMuNjYyLTIyNy41NTYtNDU1LjExMS0yMjcuNTU2cy00NTUuMTExIDEwMS44MzEtNDU1LjExMSAyMjcuNTU2ek0wIDMzNC4yMjJ2LTE3MC42NjdjMC0xMjUuNzI0IDIwMy42NjItMjI3LjU1NiA0NTUuMTExLTIyNy41NTZzNDU1LjExMSAxMDEuODMxIDQ1NS4xMTEgMjI3LjU1NnYxNzAuNjY3YzAtMTI1LjcyNC0yMDMuNjYyLTIyNy41NTYtNDU1LjExMS0yMjcuNTU2cy00NTUuMTExIDEwMS44MzEtNDU1LjExMSAyMjcuNTU2eiIgLz4NCjwvZm9udD48L2RlZnM+PC9zdmc+) format('svg');
|
||||
src: url(data:application/font-woff;charset=utf-8;base64,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) format('woff'),
|
||||
url(data:application/font-svg;charset=utf-8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiID4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8bWV0YWRhdGE+R2VuZXJhdGVkIGJ5IEljb01vb248L21ldGFkYXRhPgo8ZGVmcz4KPGZvbnQgaWQ9Imljb21vb24iIGhvcml6LWFkdi14PSIxMDI0Ij4KPGZvbnQtZmFjZSB1bml0cy1wZXItZW09IjEwMjQiIGFzY2VudD0iOTYwIiBkZXNjZW50PSItNjQiIC8+CjxtaXNzaW5nLWdseXBoIGhvcml6LWFkdi14PSIxMDI0IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4MjA7IiBob3Jpei1hZHYteD0iNTEyIiBkPSIiIC8+CjxnbHlwaCB1bmljb2RlPSImI3hlOTAxOyIgZ2x5cGgtbmFtZT0iZGF0YWJhc2UiIGhvcml6LWFkdi14PSI5MTAiIGQ9Ik00NTUuMTExIDk2MGMtMjUxLjQ0OSAwLTQ1NS4xMTEtMTAxLjgzMS00NTUuMTExLTIyNy41NTZzMjAzLjY2Mi0yMjcuNTU2IDQ1NS4xMTEtMjI3LjU1NiA0NTUuMTExIDEwMS44MzEgNDU1LjExMSAyMjcuNTU2LTIwMy42NjIgMjI3LjU1Ni00NTUuMTExIDIyNy41NTZ6TTAgNjE4LjY2N3YtMTcwLjY2N2MwLTEyNS43MjQgMjAzLjY2Mi0yMjcuNTU2IDQ1NS4xMTEtMjI3LjU1NnM0NTUuMTExIDEwMS44MzEgNDU1LjExMSAyMjcuNTU2djE3MC42NjdjMC0xMjUuNzI0LTIwMy42NjItMjI3LjU1Ni00NTUuMTExLTIyNy41NTZzLTQ1NS4xMTEgMTAxLjgzMS00NTUuMTExIDIyNy41NTZ6TTAgMzM0LjIyMnYtMTcwLjY2N2MwLTEyNS43MjQgMjAzLjY2Mi0yMjcuNTU2IDQ1NS4xMTEtMjI3LjU1NnM0NTUuMTExIDEwMS44MzEgNDU1LjExMSAyMjcuNTU2djE3MC42NjdjMC0xMjUuNzI0LTIwMy42NjItMjI3LjU1Ni00NTUuMTExLTIyNy41NTZzLTQ1NS4xMTEgMTAxLjgzMS00NTUuMTExIDIyNy41NTZ6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTkxYTsiIGdseXBoLW5hbWU9Im5vdGlmaWVzIiBkPSJNMTAyNCA1MzAuNzQ0YzAgMjAwLjkyNi01OC43OTIgMzYzLjkzOC0xMzEuNDgyIDM2NS4yMjYgMC4yOTIgMC4wMDYgMC41NzggMC4wMzAgMC44NzIgMC4wMzBoLTgyLjk0MmMwIDAtMTk0LjgtMTQ2LjMzNi00NzUuMjMtMjAzLjc1NC04LjU2LTQ1LjI5Mi0xNC4wMzAtOTkuMjc0LTE0LjAzMC0xNjEuNTAyczUuNDY2LTExNi4yMDggMTQuMDMwLTE2MS41YzI4MC40MjgtNTcuNDE4IDQ3NS4yMy0yMDMuNzU2IDQ3NS4yMy0yMDMuNzU2aDgyLjk0MmMtMC4yOTIgMC0wLjU3OCAwLjAyNC0wLjg3MiAwLjAzMiA3Mi42OTYgMS4yODggMTMxLjQ4MiAxNjQuMjk4IDEzMS40ODIgMzY1LjIyNHpNODY0LjgyNCAyMjAuNzQ4Yy05LjM4MiAwLTE5LjUzMiA5Ljc0Mi0yNC43NDYgMTUuNTQ4LTEyLjYzIDE0LjA2NC0yNC43OTIgMzUuOTYtMzUuMTg4IDYzLjMyOC0yMy4yNTYgNjEuMjMyLTM2LjA2NiAxNDMuMzEtMzYuMDY2IDIzMS4xMjQgMCA4Ny44MSAxMi44MSAxNjkuODkgMzYuMDY2IDIzMS4xMjIgMTAuMzk0IDI3LjM2OCAyMi41NjIgNDkuMjY2IDM1LjE4OCA2My4zMjggNS4yMTQgNS44MTIgMTUuMzY0IDE1LjU1MiAyNC43NDYgMTUuNTUyIDkuMzggMCAxOS41MzYtOS43NDQgMjQuNzQ0LTE1LjU1MiAxMi42MzQtMTQuMDY0IDI0Ljc5Ni0zNS45NTggMzUuMTg4LTYzLjMyOCAyMy4yNTgtNjEuMjMgMzYuMDY4LTE0My4zMTIgMzYuMDY4LTIzMS4xMjIgMC04Ny44MDQtMTIuODEtMTY5Ljg4OC0zNi4wNjgtMjMxLjEyNC0xMC4zOS0yNy4zNjgtMjIuNTYyLTQ5LjI2NC0zNS4xODgtNjMuMzI4LTUuMjA4LTUuODA2LTE1LjM2LTE1LjU0OC0yNC43NDQtMTUuNTQ4ek0yNTEuODEyIDUzMC43NDRjMCA1MS45NSAzLjgxIDEwMi40MyAxMS4wNTIgMTQ5LjA5NC00Ny4zNzItNi41NTQtODguOTQyLTEwLjMyNC0xNDAuMzQtMTAuMzI0LTY3LjA1OCAwLTY3LjA1OCAwLTY3LjA1OCAwbC01NS40NjYtOTQuNjg2di04OC4xN2w1NS40Ni05NC42ODZjMCAwIDAgMCA2Ny4wNjAgMCA1MS4zOTggMCA5Mi45NjgtMy43NzQgMTQwLjM0LTEwLjMyNC03LjIzNiA0Ni42NjQtMTEuMDQ4IDk3LjE0Ni0xMS4wNDggMTQ5LjA5NnpNMzY4LjE1IDMxNy44MjhsLTEyNy45OTggMjQuNTEgODEuODQyLTMyMS41NDRjNC4yMzYtMTYuNjM0IDIwLjc0NC0yNS4wMzggMzYuNjg2LTE4LjY1NGwxMTguNTU2IDQ3LjQ1MmMxNS45NDQgNi4zNzYgMjIuMzI4IDIzLjk2NCAxNC4xOTYgMzkuMDg0bC0xMjMuMjgyIDIyOS4xNTJ6TTg2NC44MjQgNDExLjI3Yy0zLjYxOCAwLTcuNTI4IDMuNzU0LTkuNTM4IDUuOTkyLTQuODcgNS40Mi05LjU1NiAxMy44Ni0xMy41NjIgMjQuNDA4LTguOTYyIDIzLjYtMTMuOSA1NS4yMzQtMTMuOSA4OS4wNzhzNC45MzggNjUuNDc4IDEzLjkgODkuMDc4YzQuMDA2IDEwLjU0OCA4LjY5NiAxOC45ODggMTMuNTYyIDI0LjQwOCAyLjAxMCAyLjI0IDUuOTIgNS45OTQgOS41MzggNS45OTQgMy42MTYgMCA3LjUzLTMuNzU2IDkuNTM4LTUuOTk0IDQuODctNS40MiA5LjU1Ni0xMy44NTggMTMuNTYtMjQuNDA4IDguOTY0LTIzLjU5OCAxMy45MDItNTUuMjM0IDEzLjkwMi04OS4wNzggMC0zMy44NDItNC45MzgtNjUuNDc4LTEzLjkwMi04OS4wNzgtNC4wMDQtMTAuNTQ4LTguNjk2LTE4Ljk4OC0xMy41Ni0yNC40MDgtMi4wMDgtMi4yMzgtNS45Mi01Ljk5Mi05LjUzOC01Ljk5MnoiIC8+CjwvZm9udD48L2RlZnM+PC9zdmc+) format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@@ -85,6 +85,7 @@
|
||||
|
||||
/* Plugin Icons id-s (copy from generated icon style.css) */
|
||||
.plugicon-database:before { content: "\e901"; }
|
||||
.plugicon-notifies:before { content: "\e91a"; }
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
var language = require('../lib/language')();
|
||||
|
||||
describe('Clean MONGO after tests', function ( ) {
|
||||
this.timeout(10000);
|
||||
var self = this;
|
||||
|
||||
var api = require('../lib/api/');
|
||||
beforeEach(function (done) {
|
||||
process.env.API_SECRET = 'this is my long pass phrase';
|
||||
self.env = require('../env')();
|
||||
self.env.settings.authDefaultRoles = 'readable';
|
||||
self.env.settings.enable = ['careportal', 'api'];
|
||||
this.wares = require('../lib/middleware/')(self.env);
|
||||
self.app = require('express')();
|
||||
self.app.enable('api');
|
||||
require('../lib/server/bootevent')(self.env, language).boot(function booted(ctx) {
|
||||
self.ctx = ctx;
|
||||
self.ctx.ddata = require('../lib/data/ddata')();
|
||||
self.app.use('/api', api(self.env, ctx));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('wipe treatment data', function (done) {
|
||||
self.ctx.treatments().remove({ }, function ( ) {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('wipe entries data', function (done) {
|
||||
self.ctx.entries().remove({ }, function ( ) {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const should = require('should');
|
||||
|
||||
const ctx = {};
|
||||
|
||||
ctx.bus = {};
|
||||
ctx.bus.on = function mockOn(channel, f) { };
|
||||
|
||||
const adminnotifies = require('../lib/adminnotifies')(ctx);
|
||||
|
||||
describe('adminnotifies', function ( ) {
|
||||
|
||||
it('should aggregate a message', function () {
|
||||
|
||||
const notify = {
|
||||
title: 'Foo'
|
||||
, message: 'Bar'
|
||||
};
|
||||
|
||||
adminnotifies.addNotify(notify);
|
||||
adminnotifies.addNotify(notify);
|
||||
|
||||
const notifies = adminnotifies.getNotifies();
|
||||
|
||||
notifies.length.should.equal(1);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -70,7 +70,7 @@ describe('admintools', function ( ) {
|
||||
before(function (done) {
|
||||
benv.setup(function() {
|
||||
|
||||
benv.require(__dirname + '/../tmp/js/bundle.report.js');
|
||||
benv.require(__dirname + '/../tmp/js/bundle.app.js');
|
||||
|
||||
self.$ = $;
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ describe('Devicestatus API', function ( ) {
|
||||
.set('api-secret', self.env.api_secret || '')
|
||||
.expect(200)
|
||||
.expect(function (response) {
|
||||
console.log(JSON.stringify(response.body[0]));
|
||||
response.body[0].xdripjs.state.should.equal(6);
|
||||
response.body[0].utcOffset.should.equal(0);
|
||||
})
|
||||
|
||||
@@ -38,7 +38,7 @@ describe('Treatment API', function ( ) {
|
||||
request(self.app)
|
||||
.post('/api/treatments/')
|
||||
.set('api-secret', self.env.api_secret || '')
|
||||
.send({eventType: 'Meal Bolus', created_at: now, carbs: '30', insulin: '2.00', preBolus: '15', glucose: 100, glucoseType: 'Finger', units: 'mg/dl'})
|
||||
.send({eventType: 'Meal Bolus', created_at: now, carbs: '30', insulin: '2.00', preBolus: '15', glucose: 100, glucoseType: 'Finger', units: 'mg/dl', notes: '<IMG SRC="javascript:alert(\'XSS\');">'})
|
||||
.expect(200)
|
||||
.end(function (err) {
|
||||
if (err) {
|
||||
@@ -50,10 +50,10 @@ describe('Treatment API', function ( ) {
|
||||
});
|
||||
sorted.length.should.equal(2);
|
||||
sorted[0].glucose.should.equal(100);
|
||||
sorted[0].notes.should.equal('<img>');
|
||||
should.not.exist(sorted[0].eventTime);
|
||||
sorted[0].insulin.should.equal(2);
|
||||
sorted[1].carbs.should.equal(30);
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -423,7 +423,6 @@ describe('API3 CREATE', function() {
|
||||
delete doc._id; // APIv1 updates input document, we must get rid of _id for the next round
|
||||
oldBody.should.containEql(doc);
|
||||
|
||||
|
||||
const doc2 = Object.assign({}, doc, {
|
||||
eventType: 'Meal Bolus',
|
||||
insulin: 0.4,
|
||||
|
||||
@@ -13,7 +13,7 @@ var nowData = {
|
||||
};
|
||||
|
||||
describe('client', function ( ) {
|
||||
this.timeout(30000); // TODO: see why this test takes longer on Travis to complete
|
||||
this.timeout(40000); // TODO: see why this test takes longer on Travis to complete
|
||||
|
||||
var self = this;
|
||||
|
||||
@@ -47,7 +47,6 @@ describe('client', function ( ) {
|
||||
next(true);
|
||||
};
|
||||
|
||||
|
||||
client.init();
|
||||
client.dataUpdate(nowData, true);
|
||||
|
||||
|
||||
@@ -86,6 +86,9 @@ ctx.ddata.devicestatus = [{uploader: {battery: 100}}];
|
||||
|
||||
var bootevent = require('../lib/server/bootevent');
|
||||
describe('Pebble Endpoint', function ( ) {
|
||||
|
||||
this.timeout(10000);
|
||||
|
||||
var pebble = require('../lib/server/pebble');
|
||||
before(function (done) {
|
||||
var env = require('../env')( );
|
||||
|
||||
@@ -221,7 +221,9 @@ describe('reports', function ( ) {
|
||||
return true;
|
||||
};
|
||||
|
||||
window.setTimeout = function mockSetTimeout (call) {
|
||||
|
||||
window.setTimeout = function mockSetTimeout (call, timer) {
|
||||
if (timer == 60000) return;
|
||||
call();
|
||||
};
|
||||
|
||||
@@ -297,8 +299,9 @@ describe('reports', function ( ) {
|
||||
return true;
|
||||
};
|
||||
|
||||
window.setTimeout = function mockSetTimeout (call) {
|
||||
call();
|
||||
window.setTimeout = function mockSetTimeout (call, timer) {
|
||||
if (timer == 60000) return;
|
||||
call();
|
||||
};
|
||||
|
||||
client.init(function afterInit ( ) {
|
||||
|
||||
@@ -64,7 +64,7 @@ describe('API_SECRET', function ( ) {
|
||||
process.env.API_SECRET = 'tooshort';
|
||||
var env = require('../env')( );
|
||||
should.not.exist(env.api_secret);
|
||||
env.err.desc.should.startWith('API_SECRET should be at least');
|
||||
env.err[0].desc.should.startWith('API_SECRET should be at least');
|
||||
});
|
||||
|
||||
function ping_status (app, fn) {
|
||||
|
||||
@@ -655,6 +655,11 @@
|
||||
,"virtAsstDatabaseSize":"%1 MiB. That is %2% of available database space."
|
||||
,"virtAsstTitleDatabaseSize":"Database file size"
|
||||
,"Carbs/Food/Time":"Carbs/Food/Time"
|
||||
,"You have administration messages":"You have administration messages"
|
||||
,"Admin messages in queue":"Admin messages in queue"
|
||||
,"Queue empty":"Queue empty"
|
||||
,"There are no admin messages in queue":"There are no admin messages in queue"
|
||||
,"Please sign in using the API_SECRET to see your administration messages":"Please sign in using the API_SECRET to see your administration messages"
|
||||
,"Reads enabled in default permissions":"Reads enabled in default permissions"
|
||||
,"Data reads enabled": "Data reads enabled"
|
||||
,"Data writes enabled": "Data writes enabled"
|
||||
@@ -685,4 +690,7 @@
|
||||
,"view without token":"view without token"
|
||||
,"Remove stored token":"Remove stored token"
|
||||
,"Weekly Distribution":"Weekly Distribution"
|
||||
,"Failed authentication":"Failed authentication"
|
||||
,"A device at IP number":"A device at IP number"
|
||||
,"attempted authenticating with Nightscout with wrong credentials. Check if you have an uploader setup with wrong API_SECRET or token?":"attempted authenticating with Nightscout with wrong credentials. Check if you have an uploader setup with wrong API_SECRET or token?"
|
||||
}
|
||||
|
||||
@@ -302,6 +302,9 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="adminNotifiesDrawer" class="drawer">
|
||||
</div>
|
||||
|
||||
<div id="treatmentDrawer">
|
||||
<form id="treatment-form">
|
||||
<fieldset class="treatmentData">
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
<a id="drawerToggle" class="tip" original-title="Settings" aria-label="Settings" href="#"><i class="icon-menu"></i></a>
|
||||
<a id="testAlarms" class="tip" original-title="Alarm Test / Smartphone Enable" aria-label="Alarm Test / Smartphone Enable" href="#"><i class="icon-volume"></i></a>
|
||||
<a id="editbutton" class="tip" original-title="Edit Mode" aria-label="Edit Mode" href="#" style="display:none;"><i class="icon-edit"></i></a>
|
||||
<a id="adminnotifies" class="tip" original-title="Admin ntofications" aria-label="Admin notifications" href="#" style="display:none;"><i class="plugicon-notifies"></i></a>
|
||||
</div>
|
||||
<% } %>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user