Added Firebase Cloud Messaging support.
Ylian Saint-Hilaire committed
Jan 30, 2021 at 16:15 UTC
3b2abf8498ba4eee1557ba4fee17014bdc88cc19
5 files changed
+62
-9
meshagent.js
+3
@@ -1584,6 +1584,9 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1584
if (JSON.stringify(device.wsc) != JSON.stringify(command.wsc)) { /*changes.push('Windows Security Center status');*/ device.wsc = command.wsc; change = 1; log = 1; }
1585
}
1586
1587
+ // Push Messaging Token
1588
+ if ((command.pmt != null) && (typeof command.pmt == 'string') && (device.pmt != command.pmt)) { device.pmt = command.pmt; change = 1; } // Don't save this as an event to the db.
1589
+
1590
if ((command.users != null) && (Array.isArray(command.users)) && (device.users != command.users)) { device.users = command.users; change = 1; } // Don't save this to the db.
1591
if ((mesh.mtype == 2) && (!args.wanonly)) {
1592
// In WAN mode, the hostname of a computer is not important. Don't log hostname changes.
meshcentral.js
+16
-1
@@ -678,7 +678,7 @@ function CreateMeshCentralServer(config, args) {
678
}
679
680
// Check top level configuration for any unreconized values
681
- if (config) { for (var i in config) { if ((typeof i == 'string') && (i.length > 0) && (i[0] != '_') && (['settings', 'domaindefaults', 'domains', 'configfiles', 'smtp', 'letsencrypt', 'peers', 'sms', 'sendgrid', '$schema'].indexOf(i) == -1)) { addServerWarning('Unrecognized configuration option \"' + i + '\".'); } } }
681
+ if (config) { for (var i in config) { if ((typeof i == 'string') && (i.length > 0) && (i[0] != '_') && (['settings', 'domaindefaults', 'domains', 'configfiles', 'smtp', 'letsencrypt', 'peers', 'sms', 'sendgrid', 'firebase', '$schema'].indexOf(i) == -1)) { addServerWarning('Unrecognized configuration option \"' + i + '\".'); } } }
682
683
if (typeof obj.args.userallowedip == 'string') { if (obj.args.userallowedip == '') { config.settings.userallowedip = obj.args.userallowedip = null; } else { config.settings.userallowedip = obj.args.userallowedip = obj.args.userallowedip.split(','); } }
684
if (typeof obj.args.userblockedip == 'string') { if (obj.args.userblockedip == '') { config.settings.userblockedip = obj.args.userblockedip = null; } else { config.settings.userblockedip = obj.args.userblockedip = obj.args.userblockedip.split(','); } }
@@ -1544,6 +1544,18 @@ function CreateMeshCentralServer(config, args) {
1544
if ((obj.smsserver != null) && (obj.args.lanonly == true)) { addServerWarning("SMS gateway has limited use in LAN mode."); }
1545
}
1546
1547
+ // Setup Firebase
1548
+ if (config.firebase != null) {
1549
+ try {
1550
+ obj.firebase = require('firebase-admin');
1551
+ var firebaseServiceAccount = require(obj.path.join(obj.datapath, config.firebase.serviceaccountkeyfile));
1552
+ obj.firebase.initializeApp({ credential: obj.firebase.credential.cert(firebaseServiceAccount) });
1553
+ } catch (ex) {
1554
+ console.log('Unable to setup Firebase: ' + ex);
1555
+ delete obj.firebase;
1556
+ }
1557
+ }
1558
+
1559
// Start periodic maintenance
1560
obj.maintenanceTimer = setInterval(obj.maintenanceActions, 1000 * 60 * 60); // Run this every hour
1561
@@ -3053,6 +3065,9 @@ function mainStart() {
3065
if (NodeJSVer < 8) { console.log("SMS Plivo support requires Node v8 or above, current version is " + process.version + "."); } else { modules.push('plivo'); }
3066
}
3067
3068
+ // Firebase Support
3069
+ if (config.firebase != null) { modules.push('firebase-admin'); }
3070
+
3071
// Syslog support
3072
if ((require('os').platform() != 'win32') && (config.settings.syslog || config.settings.syslogjson)) { modules.push('modern-syslog'); }
3073
meshuser.js
+29
-1
@@ -686,6 +686,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
686
if (!r[meshid]) { r[meshid] = []; }
687
delete docs[i].meshid;
688
689
+ // Remove push messaging token if present
690
+ if (docs[i].pmt != null) { docs[i].pmt = 1; }
691
+
692
// Remove Intel AMT credential if present
693
if (docs[i].intelamt != null) {
694
if (docs[i].intelamt.pass != null) { docs[i].intelamt.pass = 1; }
@@ -4060,7 +4063,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
4063
// Check if this user has rights on this nodeid
4064
if (common.validateString(command.nodeid, 1, 1024) == false) break; // Check nodeid
4065
db.Get(command.nodeid, function (err, nodes) { // TODO: Make a NodeRights(user) method that also does not do a db call if agent is connected (???)
4063
- if ((nodes == null) || (nodes.length == 1)) {
4066
+ if ((err == null) && (nodes.length == 1)) {
4067
if ((parent.GetMeshRights(user, nodes[0].meshid) & MESHRIGHT_REMOTECONTROL) != 0) {
4068
// Add a user authentication cookie to a url
4069
var cookieContent = { userid: user._id, domainid: user.domain };
@@ -5191,6 +5194,31 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
5194
try { ws.send(JSON.stringify(responseCmd)); } catch (ex) { }
5195
break;
5196
}
5197
+ case 'pushmessage': {
5198
+ // Check if this user has rights on this nodeid
5199
+ if (parent.parent.firebase == null) return;
5200
+ if (common.validateString(command.nodeid, 1, 1024) == false) break; // Check nodeid
5201
+ if (common.validateString(command.title, 1, 1024) == false) break; // Check title
5202
+ if (common.validateString(command.msg, 1, 1024) == false) break; // Check message
5203
+ db.Get(command.nodeid, function (err, nodes) { // TODO: Make a NodeRights(user) method that also does not do a db call if agent is connected (???)
5204
+ if ((err == null) && (nodes.length == 1)) {
5205
+ const node = nodes[0];
5206
+ if (((parent.GetMeshRights(user, node.meshid) & MESHRIGHT_REMOTECONTROL) != 0) && (typeof node.pmt == 'string')) {
5207
+ // Send out a push message to the device
5208
+ var payload = { notification: { title: command.title, body: command.msg } };
5209
+ var options = { priority: "Normal", timeToLive: 5 * 60 }; // TTL: 5 minutes
5210
+ parent.parent.firebase.messaging().sendToDevice(node.pmt, payload, options)
5211
+ .then(function (response) {
5212
+ parent.parent.debug('email', 'Successfully send push message to device ' + node.name + ', title: ' + command.title + ', msg: ' + command.msg);
5213
+ })
5214
+ .catch(function (error) {
5215
+ parent.parent.debug('email', 'Failed to send push message to device ' + node.name + ', title: ' + command.title + ', msg: ' + command.msg + ', error: ' + error);
5216
+ });
5217
+ }
5218
+ }
5219
+ });
5220
+ break;
5221
+ }
5222
case 'print': {
5223
console.log(command.value);
5224
break;
views/default.handlebars
+7
-3
@@ -5974,7 +5974,7 @@
5974
}
5975
x += '<input type=button value="' + "Notes" + '" title="' + "View notes about this device" + '" onclick=showNotes(' + ((meshrights & 128) == 0) + ',"' + encodeURIComponentEx(node._id) + '") />';
5976
x += '<input type=button value="' + "Log Event" + '" title="' + "Write an event for this device" + '" onclick=writeDeviceEvent("' + encodeURIComponentEx(node._id) + '") />';
5977
- if ((connectivity & 1) && (meshrights & 8) && (node.agent.id != 14)) { x += '<input type=button value="' + "Message" + '" title="' + "Display a text message on the remote device" + '" onclick=deviceMessageFunction() />'; }
5977
+ if ((meshrights & 8) && ((connectivity & 1) || (node.pmt == 1))) { x += '<input type=button value="' + "Message" + '" title="' + "Display a text message on the remote device" + '" onclick=deviceMessageFunction() />'; }
5978
//if ((connectivity & 1) && (meshrights & 8) && (node.agent.id < 5)) { x += '<input type=button value=Toast title="' + "Display a text message of the remote device" + '" onclick=deviceToastFunction() />'; }
5979
if ((connectivity & 1) && (meshrights & 8) && (node.agent.id == 14)) { x += '<input type=button value="' + "Chat" + '" title="' + "Open chat window to this computer" + '" onclick=deviceChat(event) />'; }
5980
if ((serverinfo.guestdevicesharing !== false) && (node.agent != null) && (node.agent.caps & 3) && (connectivity & 1) && (meshrights & 0x80008) && ((meshrights == 0xFFFFFFFF) || ((meshrights & 0x1000) == 0))) { x += '<input type=button value="' + "Share" + '" title="' + "Create a link to share this device with a guest" + '" onclick=showShareDevice() />'; }
@@ -6338,7 +6338,11 @@
6338
}
6339
6340
function deviceMessageFunctionEx() {
6341
- meshserver.send({ action: 'msg', type: 'messagebox', nodeid: currentNode._id, title: decodeURIComponent('{{{extitle}}}'), msg: Q('d2devMessage').value });
6341
+ if (currentNode.pmt == 1) {
6342
+ meshserver.send({ action: 'pushmessage', nodeid: currentNode._id, title: decodeURIComponent('{{{extitle}}}'), msg: Q('d2devMessage').value });
6343
+ } else {
6344
+ meshserver.send({ action: 'msg', type: 'messagebox', nodeid: currentNode._id, title: decodeURIComponent('{{{extitle}}}'), msg: Q('d2devMessage').value });
6345
+ }
6346
}
6347
6348
function deskClipboardInFunction() {
@@ -13752,7 +13756,7 @@
13756
x += '<div><label><input type=checkbox id=p41c14 ' + ((serverTraceSources.indexOf('agentupdate') >= 0) ? 'checked' : '') + '>' + "MeshAgent update" + '</label></div>';
13757
x += '<div><label><input type=checkbox id=p41c16 ' + ((serverTraceSources.indexOf('cert') >= 0) ? 'checked' : '') + '>' + "Server Certificate" + '</label></div>';
13758
x += '<div><label><input type=checkbox id=p41c17 ' + ((serverTraceSources.indexOf('db') >= 0) ? 'checked' : '') + '>' + "Server Database" + '</label></div>';
13755
- x += '<div><label><input type=checkbox id=p41c18 ' + ((serverTraceSources.indexOf('email') >= 0) ? 'checked' : '') + '>' + "Email/SMS Traffic" + '</label></div>';
13759
+ x += '<div><label><input type=checkbox id=p41c18 ' + ((serverTraceSources.indexOf('email') >= 0) ? 'checked' : '') + '>' + "Email/SMS/Push Traffic" + '</label></div>';
13760
x += '<div style="width:100%;border-bottom:1px solid gray;margin-bottom:5px;margin-top:5px"><b>' + "Web Server" + '</b></div>';
13761
x += '<div><label><input type=checkbox id=p41c5 ' + ((serverTraceSources.indexOf('web') >= 0) ? 'checked' : '') + '>' + "Web Server" + '</label></div>';
13762
x += '<div><label><input type=checkbox id=p41c6 ' + ((serverTraceSources.indexOf('webrequest') >= 0) ? 'checked' : '') + '>' + "Web Server Requests" + '</label></div>';
webserver.js
+7
-4
@@ -6293,11 +6293,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
6293
obj.CloneSafeNode = function (node) {
6294
if (typeof node != 'object') { return node; }
6295
var r = node;
6296
- if ((r.intelamt != null) && ((r.intelamt.pass != null) || (r.intelamt.mpspass != null))) {
6296
+ if ((r.pmt != null) || ((r.intelamt != null) && ((r.intelamt.pass != null) || (r.intelamt.mpspass != null)))) {
6297
r = Object.assign({}, r); // Shallow clone
6298
- r.intelamt = Object.assign({}, r.intelamt); // Shallow clone
6299
- if (r.intelamt.pass != null) { r.intelamt.pass = 1; }; // Remove the Intel AMT administrator password from the node
6300
- if (r.intelamt.mpspass != null) { r.intelamt.mpspass = 1; }; // Remove the Intel AMT MPS password from the node
6298
+ if (r.pmt != null) { r.pmt = 1; }
6299
+ if ((r.intelamt != null) && ((r.intelamt.pass != null) || (r.intelamt.mpspass != null))) {
6300
+ r.intelamt = Object.assign({}, r.intelamt); // Shallow clone
6301
+ if (r.intelamt.pass != null) { r.intelamt.pass = 1; }; // Remove the Intel AMT administrator password from the node
6302
+ if (r.intelamt.mpspass != null) { r.intelamt.mpspass = 1; }; // Remove the Intel AMT MPS password from the node
6303
+ }
6304
}
6305
return r;
6306
}