diff --git a/meshcentral-config-schema.json b/meshcentral-config-schema.json
index ccdd562a..a0abb392 100644
--- a/meshcentral-config-schema.json
+++ b/meshcentral-config-schema.json
@@ -1417,6 +1417,14 @@
"userurl": { "type": "string", "description": "A URL given to users to help them setup this service." }
},
"description": "Enabled ntfy.sh integration support."
+ },
+ "zulip": {
+ "type": "object",
+ "properties": {
+ "email": { "type": "string", "description": "Bot email address to login as." },
+ "api_key": { "type": "string", "description": "Bot api key." }
+ },
+ "description": "Enabled Zulip integration support."
}
}
}
diff --git a/meshcentral.js b/meshcentral.js
index c3d4836e..b554e3d3 100644
--- a/meshcentral.js
+++ b/meshcentral.js
@@ -4032,6 +4032,7 @@ function mainStart() {
if (config.messaging.discord != null) { if (nodeVersion >= 17) { modules.push('discord.js@14.6.0'); } else { delete config.messaging.discord; addServerWarning('This NodeJS version does not support Discord.js.', 26); } }
if (config.messaging.xmpp != null) { modules.push('@xmpp/client'); }
if (config.messaging.pushover != null) { modules.push('node-pushover'); }
+ if (config.messaging.zulip != null) { modules.push('zulip'); }
}
// Setup web based push notifications
diff --git a/meshmessaging.js b/meshmessaging.js
index c52adf3a..b63f4bbb 100644
--- a/meshmessaging.js
+++ b/meshmessaging.js
@@ -78,13 +78,21 @@
}
}
+// For zulip
+{
+ "messaging": {
+ email: "your-bot@zulip.com",
+ api_key: "your_32_character_api_key"
+ }
+}
+
*/
// Construct a messaging server object
module.exports.CreateServer = function (parent) {
var obj = {};
obj.parent = parent;
- obj.providers = 0; // 1 = Telegram, 2 = Signal, 4 = Discord, 8 = XMPP, 16 = CallMeBot, 32 = Pushover
+ obj.providers = 0; // 1 = Telegram, 2 = Signal, 4 = Discord, 8 = XMPP, 16 = CallMeBot, 32 = Pushover, 64 = ntfy, 128 = Zulip
obj.telegramClient = null;
obj.discordClient = null;
obj.discordUrl = null;
@@ -92,6 +100,7 @@ module.exports.CreateServer = function (parent) {
var xmppXml = null;
obj.callMeBotClient = null;
obj.pushoverClient = null;
+ obj.zulipClient = null;
// Telegram client setup
if (parent.config.messaging.telegram) {
@@ -228,6 +237,13 @@ module.exports.CreateServer = function (parent) {
obj.providers += 64; // Enable ntfy messaging
}
+ // Zulip client setup (https://zulip.com/)
+ if (typeof parent.config.messaging.zulip == 'object') {
+ var zulip = require('zulip');
+ obj.zulipClient = new zulip.Client(parent.config.messaging.zulip);
+ obj.providers += 128; // Enable zulip messaging
+ }
+
// Send a direct message to a specific userid
async function discordSendMsg(userId, message) {
const user = await obj.discordClient.users.fetch(userId).catch(function () { return null; });
@@ -296,6 +312,14 @@ module.exports.CreateServer = function (parent) {
const req = require('https').request(new URL(url), { method: 'POST' }, function (res) { if (func != null) { func(true); } });
req.on('error', function (err) { if (func != null) { func(false); } });
req.end(msg);
+ } else if ((to.startsWith('zulip:')) && (obj.zulipClient != null)) { // zulip
+ obj.zulipClient.sendMessage({
+ type: 'private',
+ content: msg,
+ to: [ to.substring(6) ],
+ subject: domain.title ? domain.title : 'MeshCentral'
+ });
+ if (func != null) { func(true); }
} else {
// No providers found
func(false, "No messaging providers found for this message.");
diff --git a/meshuser.js b/meshuser.js
index c06121ec..f3c36a07 100644
--- a/meshuser.js
+++ b/meshuser.js
@@ -6706,6 +6706,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
if ((command.service == 16) && ((parent.parent.msgserver.providers & 16) != 0)) { handle = parent.parent.msgserver.callmebotUrlToHandle(command.handle); }
if ((command.service == 32) && ((parent.parent.msgserver.providers & 32) != 0)) { handle = 'pushover:' + command.handle; }
if ((command.service == 64) && ((parent.parent.msgserver.providers & 64) != 0)) { handle = 'ntfy:' + command.handle; }
+ if ((command.service == 128) && ((parent.parent.msgserver.providers & 128) != 0)) { handle = 'zulip:' + command.handle; }
if (handle == null) return;
// Send a verification message
@@ -6851,6 +6852,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
if ((parent.parent.msgserver.providers & 8) != 0) { r.push("Usage: MSG \"xmpp:[username@server.com]\" \"Message\"."); }
if ((parent.parent.msgserver.providers & 32) != 0) { r.push("Usage: MSG \"pushover:[userkey]\" \"Message\"."); }
if ((parent.parent.msgserver.providers & 64) != 0) { r.push("Usage: MSG \"ntfy:[topic]\" \"Message\"."); }
+ if ((parent.parent.msgserver.providers & 128) != 0) { r.push("Usage: MSG \"zulip:[topic]\" \"Message\"."); }
cmdData.result = r.join('\r\n');
} else {
parent.parent.msgserver.sendMessage(cmdData.cmdargs['_'][0], cmdData.cmdargs['_'][1], domain, function (status, msg) {
diff --git a/package.json b/package.json
index 605d456f..8d0a7ffb 100644
--- a/package.json
+++ b/package.json
@@ -37,6 +37,7 @@
"sample-config-advanced.json"
],
"dependencies": {
+ "@yetzt/nedb": "^1.8.0",
"archiver": "^5.3.1",
"body-parser": "^1.19.0",
"cbor": "~5.2.0",
@@ -48,10 +49,10 @@
"ipcheck": "^0.1.0",
"minimist": "^1.2.5",
"multiparty": "^4.2.1",
- "@yetzt/nedb": "^1.8.0",
"node-forge": "^1.0.0",
"ws": "^5.2.3",
- "yauzl": "^2.10.0"
+ "yauzl": "^2.10.0",
+ "zulip": "^0.1.0"
},
"engines": {
"node": ">=10.0.0"
diff --git a/views/default.handlebars b/views/default.handlebars
index 9130f56a..79dbcd16 100644
--- a/views/default.handlebars
+++ b/views/default.handlebars
@@ -11988,6 +11988,7 @@
if ((serverinfo.userMsgProviders & 16) != 0) { y += ''; }
if ((serverinfo.userMsgProviders & 32) != 0) { y += ''; }
if ((serverinfo.userMsgProviders & 64) != 0) { y += ''; }
+ if ((serverinfo.userMsgProviders & 128) != 0) { y += ''; }
y += '';
x += '