Skip to content

Commit

Permalink
Merge pull request #127 from nightscout/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
yeagerm authored Oct 31, 2023
2 parents d9de1cb + 5b440b7 commit 5043577
Show file tree
Hide file tree
Showing 28 changed files with 576 additions and 218 deletions.
2 changes: 1 addition & 1 deletion lib/api/activity/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ function configure(app, wares, ctx) {
api.post('/activity/', ctx.authorization.isPermitted('api:activity:create'), post_response);

api.delete('/activity/:_id', ctx.authorization.isPermitted('api:activity:delete'), function(req, res) {
ctx.activity.deleteOne(req.params._id, function() {
ctx.activity.remove(req.params._id, function() {
res.json({});
});
});
Expand Down
2 changes: 1 addition & 1 deletion lib/api/food/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ function configure (app, wares, ctx) {
});
// delete record
api.delete('/food/:_id', ctx.authorization.isPermitted('api:food:delete'), function(req, res) {
ctx.food.deleteOne(req.params._id, function ( ) {
ctx.food.remove(req.params._id, function ( ) {
res.json({ });
});
});
Expand Down
2 changes: 1 addition & 1 deletion lib/api/profile/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ function configure (app, wares, ctx) {
});

api.delete('/profile/:_id', ctx.authorization.isPermitted('api:profile:delete'), function(req, res) {
ctx.profile.deleteOne(req.params._id, function ( ) {
ctx.profile.remove(req.params._id, function ( ) {
res.json({ });
});
});
Expand Down
84 changes: 65 additions & 19 deletions lib/api3/alarmSocket.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@ function AlarmSocket (app, env, ctx) {
socket.on('subscribe', function onSubscribe (message, returnCallback) {
self.subscribe(socket, message, returnCallback);
});

});

// Turns all notifications on the event bus back into events to be
// broadcast to clients.
ctx.bus.on('notification', self.emitNotification);
};

Expand All @@ -65,7 +67,7 @@ function AlarmSocket (app, env, ctx) {
self.subscribe = function subscribe (socket, message, returnCallback) {
const shouldCallBack = typeof(returnCallback) === 'function';

// Native client
// Native client
if (message && message.accessToken) {
return ctx.authorization.resolveAccessToken(message.accessToken, function resolveFinishForToken (err, auth) {
if (err) {
Expand All @@ -76,24 +78,47 @@ function AlarmSocket (app, env, ctx) {
}
return err;
} else {
// Subscribe for acking alarms
socket.on('ack', function onAck (level, group, silenceTime) {
ctx.notifications.ack(level, group, silenceTime, true);
console.info(LOG + 'ack received ' + level + ' ' + group + ' ' + silenceTime);
});

var okResponse = { success: true, message: 'Subscribed for alarms' }
// Subscribe for acking alarms
// Client sends ack, which sends a notificaiton through our internal bus
socket.on('ack', function onAck (level, group, silenceTime) {
ctx.notifications.ack(level, group, silenceTime, true);
console.info(LOG + 'ack received ' + level + ' ' + group + ' ' + silenceTime);
});

var okResponse = { success: true, message: 'Subscribed for alarms' }
if (shouldCallBack) {
returnCallback(okResponse);
}
return okResponse;
}
});
}

// Web client (jwt access token or api_hash)
if (message && (message.jwtToken || message.secret)) {

if (!message) { message = {}; }
// Web client (jwt access token or api_hash)
/*
* On the web: a client may have saved a secret or using a jwtToken, or may have none.
* Some pages will automatically prompt for authorization, when needed.
* To make the main homepage require authorization as well, set
* AUTHENTICATION_PROMPT_ON_LOAD=true.
*
* If there is missing authorization when authorization is required,
* rejecting the attempt in order to trigger a prompt on the client.
* If there is no authorization required, or there are available
* credentials, attempt to resolve the available permissions.
* When processing ACK messages that dismiss alarms, Authorization should be
* required.
*/
var shouldTry = true;
if (env.settings.authenticationPromptOnLoad) {
if (!message.jwtToken && !message.secret) {
shouldTry = false;
}
}

if (message && shouldTry) {
return ctx.authorization.resolve({ api_secret: message.secret, token: message.jwtToken, ip: getRemoteIP(socket.request) }, function resolveFinish (err, auth) {

if (err) {
console.log(`${LOG_ERROR} Authorization failed for jwtToken:`, message.jwtToken);

Expand All @@ -102,13 +127,34 @@ function AlarmSocket (app, env, ctx) {
}
return err;
} else {
// Subscribe for acking alarms
socket.on('ack', function onAck (level, group, silenceTime) {
ctx.notifications.ack(level, group, silenceTime, true);
console.info(LOG + 'ack received ' + level + ' ' + group + ' ' + silenceTime);
});

var okResponse = { success: true, message: 'Subscribed for alarms' }
var perms = {
read: ctx.authorization.checkMultiple('api:*:read', auth.shiros)
, ack: ctx.authorization.checkMultiple('notifications:*:ack', auth.shiros)
};
// Subscribe for acking alarms
// TODO: does this produce double ACK after the authorizing? Only if reconnecting?
// TODO: how will perms get updated after authorizing?
socket.on('ack', function onAck (level, group, silenceTime) {
if (perms.ack) {
// This goes through the server-wide event bus.
ctx.notifications.ack(level, group, silenceTime, true);
console.info(LOG + 'ack received ' + level + ' ' + group + ' ' + silenceTime);
} else {
// TODO: send a message to client to silence locally, but not
// globally, and request authorization.
// This won't go through th event bus.
// var acked = { silenceTime, group, level };
// socket.emit('authorization_needed', acked);
}
});
/* TODO: need to know when to update the permissions.
// Can we use
socket.on('resubscribe', function update_permissions ( ) {
// perms = { ... };
});
*/

var okResponse = { success: true, message: 'Subscribed for alarms', ...perms };
if (shouldCallBack) {
returnCallback(okResponse);
}
Expand Down
4 changes: 2 additions & 2 deletions lib/api3/storage/mongoCollection/modify.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ function updateOne (col, identifier, setFields) {
if (err) {
reject(err);
} else {
resolve({ updated: result.modifiedCount });
resolve({ updated: result.result.nModified });
}
});
});
Expand All @@ -91,7 +91,7 @@ function deleteOne (col, identifier) {
if (err) {
reject(err);
} else {
resolve({ deleted: result.deletedCount });
resolve({ deleted: result.result.n });
}
});
});
Expand Down
6 changes: 3 additions & 3 deletions lib/api3/storage/mongoCollection/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

const _ = require('lodash')
, checkForHexRegExp = new RegExp("^[0-9a-fA-F]{24}$")
, ObjectID = require('mongodb-legacy').ObjectId
, ObjectID = require('mongodb').ObjectID
;


Expand Down Expand Up @@ -112,7 +112,7 @@ function filterForOne (identifier) {

// fallback to "identifier = _id"
if (checkForHexRegExp.test(identifier)) {
filterOpts.push({ _id: new ObjectID(identifier) });
filterOpts.push({ _id: ObjectID(identifier) });
}

return { $or: filterOpts };
Expand All @@ -137,7 +137,7 @@ function identifyingFilter (identifier, doc, dedupFallbackFields) {

// fallback to "identifier = _id" (APIv1)
if (checkForHexRegExp.test(identifier)) {
filterItems.push({ identifier: { $exists: false }, _id: new ObjectID(identifier) });
filterItems.push({ identifier: { $exists: false }, _id: ObjectID(identifier) });
}
}

Expand Down
21 changes: 6 additions & 15 deletions lib/authorization/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
var _ = require('lodash');
var crypto = require('crypto');
var shiroTrie = require('shiro-trie');
var ObjectID = require('mongodb-legacy').ObjectId;
var ObjectID = require('mongodb').ObjectID;

var find_options = require('../server/query');

Expand All @@ -27,22 +27,22 @@ function init (env, ctx) {
if (!Object.prototype.hasOwnProperty.call(obj, 'created_at')) {
obj.created_at = (new Date()).toISOString();
}
collection.insertOne(obj, function (err, doc) {
collection.insert(obj, function (err, doc) {
if (err != null && err.message) {
console.log('Data insertion error', err.message);
fn(err.message, null);
return;
}
storage.reload(function loaded() {
fn(null, obj);
fn(null, doc.ops);
});
});
}
return doCreate;
}

function list (collection) {
function doList(opts, fn) {
function doList(opts, fn) {
// these functions, find, sort, and limit, are used to
// dynamically configure the request, based on the options we've
// been given
Expand All @@ -65,8 +65,6 @@ function init (env, ctx) {
fn(err, entries);
}

console.log('Loading',opts);

// now just stitch them all together
limit.call(collection
.find(query_for(opts))
Expand All @@ -79,7 +77,7 @@ function init (env, ctx) {

function remove (collection) {
function doRemove (_id, callback) {
collection.deleteOne({ '_id': new ObjectID(_id) }, function (err) {
collection.remove({ '_id': new ObjectID(_id) }, function (err) {
storage.reload(function loaded() {
callback(err, null);
});
Expand All @@ -94,7 +92,7 @@ function init (env, ctx) {
if (!obj.created_at) {
obj.created_at = (new Date()).toISOString();
}
collection.insertOne(obj, function (err) {
collection.save(obj, function (err) {
//id should be added for new docs
storage.reload(function loaded() {
callback(err, obj);
Expand Down Expand Up @@ -137,14 +135,8 @@ function init (env, ctx) {

storage.reload = function reload (callback) {

console.log('Reloading auth data');

storage.listRoles({sort: {name: 1}}, function listResults (err, results) {

console.log('Roles listed');

if (err) {
console.log('Problem listing roles', err);
return callback && callback(err);
}

Expand All @@ -160,7 +152,6 @@ function init (env, ctx) {

storage.listSubjects({sort: {name: 1}}, function listResults (err, results) {
if (err) {
console.log('Problem listing subjects', err);
return callback && callback(err);
}

Expand Down
40 changes: 30 additions & 10 deletions lib/client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ client.init = function init (callback) {
}).done(function success (serverSettings) {
if (serverSettings.runtimeState !== 'loaded') {
console.log('Server is still loading data');
$('#loadingMessageText').html('Nightscout is still starting and should be available within about 15 seconds.');
$('#loadingMessageText').html('Server is starting and still loading data, retrying load in 5 seconds');
window.setTimeout(window.Nightscout.client.init, 5000);
return;
}
Expand Down Expand Up @@ -1146,15 +1146,13 @@ client.load = function load (serverSettings, callback) {
}

console.log('Subscribed for alarms', data);
if (client.settings.authenticationPromptOnLoad && !data.success) {
client.hashauth.requestAuthentication(function afterRequest () {
client.hashauth.updateSocketAuth();
if (callback) {
callback();
}
});
} else if (callback) {
callback();
var shouldAuthenticationPromptOnLoad = client.settings.authenticationPromptOnLoad ;
if (!data.success) {
if (!data.read || !hasRequiredPermission() || shouldAuthenticationPromptOnLoad) {
return client.hashauth.requestAuthentication(function afterRequest () {
return client.hashauth.updateSocketAuth();
});
}
}
}
);
Expand Down Expand Up @@ -1235,6 +1233,28 @@ client.load = function load (serverSettings, callback) {
stopAlarm(false, null, notify);
}
});
/*
*
// TODO: When an unauthorized client attempts to silence an alarm, we should
// allow silencing locally, request for authorization, and if the
// authorization succeeds even republish the ACK notification. something like...
alarmSocket.on('authorization_needed', function(details) {
if (alarmInProgress) {
console.log('clearing alarm');
stopAlarm(true, details.silenceTime, currentNotify);
}
client.hashauth.requestAuthentication(function afterRequest () {
console.log("SUCCESSFULLY AUTHORIZED, REPUBLISHED ACK?");
// easiest way to update permission set on server side is to send another message.
alarmSocket.emit('resubscribe', currentNotify, details);
if (isClient && currentNotify) {
alarmSocket.emit('ack', currentNotify.level, currentNotify.group, details.silenceTime);
}
});
});
*/

$('#testAlarms').click(function(event) {

Expand Down
6 changes: 6 additions & 0 deletions lib/notifications.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,13 +185,19 @@ function init (env, ctx) {
notifications.ack(1, group, time);
}

/*
* TODO: modify with a local clear, this will clear all connected clients,
* globally
*/
if (sendClear) {
var notify = {
clear: true
, title: 'All Clear'
, message: group + ' - ' + ctx.levels.toDisplay(level) + ' was ack\'d'
, group: group
};
// When web client sends ack, this translates the websocket message into
// an event on our internal bus.
ctx.bus.emit('notification', notify);
logEmitEvent(notify);
}
Expand Down
1 change: 1 addition & 0 deletions lib/profile/profileeditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ var init = function init () {

client.init(function loaded () {

console.log("LOADING CLIENT INIT");
if (c_profile !== null) {
return; // already loaded so don't load again
}
Expand Down
4 changes: 2 additions & 2 deletions lib/server/activity.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ var find_options = require('./query');


function storage (env, ctx) {
var ObjectID = require('mongodb-legacy').ObjectId;
var ObjectID = require('mongodb').ObjectID;

function create (obj, fn) {
obj.created_at = (new Date( )).toISOString( );
Expand Down Expand Up @@ -62,7 +62,7 @@ function storage (env, ctx) {

function remove (_id, fn) {
var objId = new ObjectID(_id);
return api( ).deleteOne({ '_id': objId }, fn);
return api( ).remove({ '_id': objId }, fn);
}

function api ( ) {
Expand Down
Loading

0 comments on commit 5043577

Please sign in to comment.