diff --git a/.npmrc b/.npmrc
index 4fd02195..d1cdf2f0 100644
--- a/.npmrc
+++ b/.npmrc
@@ -1 +1 @@
-engine-strict=true
\ No newline at end of file
+engine-strict = true
\ No newline at end of file
diff --git a/MeshCentralServer.njsproj b/MeshCentralServer.njsproj
index cfd70d9f..3974731b 100644
--- a/MeshCentralServer.njsproj
+++ b/MeshCentralServer.njsproj
@@ -681,6 +681,7 @@
+
@@ -723,6 +724,7 @@
+
diff --git a/meshcentral.js b/meshcentral.js
index 8ed85fc8..3576c614 100644
--- a/meshcentral.js
+++ b/meshcentral.js
@@ -3876,7 +3876,8 @@ var ServerWarnings = {
22: "Failed to sign agent {0}: {1}",
23: "Unable to load agent icon file: {0}.",
24: "Unable to load agent logo file: {0}.",
- 25: "This NodeJS version does not support OpenID."
+ 25: "This NodeJS version does not support OpenID.",
+ 26: "This NodeJS version does not support Discord.js."
};
*/
@@ -4028,6 +4029,7 @@ function mainStart() {
// Messaging support
if (config.messaging != null) {
if (config.messaging.telegram != null) { modules.push('telegram'); modules.push('input'); }
+ 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.', 25); } }
}
// Setup web based push notifications
diff --git a/meshmessaging.js b/meshmessaging.js
index f502239e..e88eac4c 100644
--- a/meshmessaging.js
+++ b/meshmessaging.js
@@ -32,16 +32,25 @@
"bottoken": "00000000:aaaaaaaaaaaaaaaaaaaaaaaa"
}
}
+
+// For Discord login, add this in config.json
+"messaging": {
+ "discord": {
+ "inviteurl": "https://discord.gg/xxxxxxxxx",
+ "token": "xxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxx"
+ }
+}
*/
// Construct a messaging server object
module.exports.CreateServer = function (parent) {
var obj = {};
obj.parent = parent;
- obj.providers = 0; // 1 = Telegram, 2 = Signal
+ obj.providers = 0; // 1 = Telegram, 2 = Signal, 4 = Discord
obj.telegramClient = null;
+ obj.discordClient = null;
- // Messaging client setup
+ // Telegram client setup
if (parent.config.messaging.telegram) {
// Validate Telegram configuration values
var telegramOK = true;
@@ -80,16 +89,85 @@ module.exports.CreateServer = function (parent) {
}
}
+ // Discord client setup
+ if (parent.config.messaging.discord) {
+ // Validate Discord configuration values
+ var discordOK = true;
+ if (typeof parent.config.messaging.discord.inviteurl != 'string') { console.log('Invalid or missing Discord invite URL.'); discordOK = false; }
+ if (typeof parent.config.messaging.discord.token != 'string') { console.log('Invalid or missing Discord token.'); discordOK = false; }
+
+ if (discordOK) {
+ // Setup Discord
+ const { Client, GatewayIntentBits } = require('discord.js');
+ var discordClient = new Client({
+ intents: [
+ GatewayIntentBits.Guilds,
+ GatewayIntentBits.GuildMessages,
+ GatewayIntentBits.MessageContent,
+ GatewayIntentBits.GuildMembers,
+ GatewayIntentBits.DirectMessages
+ ]
+ });
+
+ // Called when Discord client is connected
+ discordClient.on('ready', function() {
+ console.log(`MeshCentral Discord client is connected as ${discordClient.user.tag}!`);
+ obj.discordClient = discordClient;
+ obj.providers += 4; // Enable Discord messaging
+ });
+
+ // Receives incoming messages, ignore for now
+ discordClient.on('messageCreate', function(message) {
+ if (message.author.bot) return false;
+ console.log(`Discord message from ${message.author.username}: ${message.content}`, message.channel.type);
+ //message.channel.send("Channel Hello");
+ //message.author.send('Private Hello');
+ });
+
+ // Called when Discord client received an interaction
+ discordClient.on('interactionCreate', async function(interaction) {
+ console.log('Discord interaction', interaction);
+ if (!interaction.isChatInputCommand()) return;
+ if (interaction.commandName === 'ping') { await interaction.reply('Pong!'); }
+ });
+
+ // Connect Discord client
+ discordClient.login(parent.config.messaging.discord.token);
+ }
+ }
+
+ // 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; });
+ if (!user) return;
+ await user.send(message).catch(function (ex) { console.log('Discord Error', ex); });
+ }
+
+ // Convert a userTag to a userId. We need to query the Discord server to find this information.
+ // Example: findUserByTab('aaaa#0000', function (userid) { sendMsg(userid, 'message'); });
+ async function discordFindUserByTag(userTag, func) {
+ var username = userTag.split('#')[0];
+ const guilds = await obj.discordClient.guilds.fetch();
+ guilds.forEach(async function (value, key) {
+ var guild = await value.fetch();
+ const guildMembers = await guild.members.search({ query: username });
+ guildMembers.forEach(async function (value, key) {
+ if ((value.user.username + '#' + value.user.discriminator) == userTag) { func(key); return; }
+ });
+ });
+ }
+
// Send an user message
obj.sendMessage = function(to, msg, func) {
- // Telegram
- if ((to.startsWith('telegram:')) && (obj.telegramClient != null)) {
+ if ((to.startsWith('telegram:')) && (obj.telegramClient != null)) { // Telegram
async function sendTelegramMessage(to, msg, func) {
if (obj.telegramClient == null) return;
parent.debug('email', 'Sending Telegram message to: ' + to.substring(9) + ': ' + msg);
try { await obj.telegramClient.sendMessage(to.substring(9), { message: msg }); if (func != null) { func(true); } } catch (ex) { if (func != null) { func(false, ex); } }
}
sendTelegramMessage(to, msg, func);
+ } else if ((to.startsWith('discord:')) && (obj.discordClient != null)) { // Discord
+ discordFindUserByTag(to.substring(8), function (userid) { discordSendMsg(userid, msg); 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 086128ec..e5b7c9d9 100644
--- a/meshuser.js
+++ b/meshuser.js
@@ -6691,6 +6691,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Setup the handle for the right messaging service
var handle = null;
if ((command.service == 1) && ((parent.parent.msgserver.providers & 1) != 0)) { handle = 'telegram:@' + command.handle; }
+ if ((command.service == 4) && ((parent.parent.msgserver.providers & 4) != 0)) { handle = 'discord:' + command.handle; }
if (handle == null) return;
// Send a verification message
@@ -6831,7 +6832,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
if (cmdData.cmdargs['_'].length != 2) {
var r = [];
if ((parent.parent.msgserver.providers & 1) != 0) { r.push("Usage: MSG \"telegram:@UserHandle\" \"Message\"."); }
- if ((parent.parent.msgserver.providers & 2) != 0) { r.push("Usage: MSG \"signal:@UserHandle\" \"Message\"."); }
+ if ((parent.parent.msgserver.providers & 2) != 0) { r.push("Usage: MSG \"signal:UserHandle\" \"Message\"."); }
+ if ((parent.parent.msgserver.providers & 4) != 0) { r.push("Usage: MSG \"discord:Username#0000\" \"Message\"."); }
cmdData.result = r.join('\r\n');
} else {
parent.parent.msgserver.sendMessage(cmdData.cmdargs['_'][0], cmdData.cmdargs['_'][1], function (status, msg) {
diff --git a/views/default.handlebars b/views/default.handlebars
index 4d71cd1a..4d79383b 100644
--- a/views/default.handlebars
+++ b/views/default.handlebars
@@ -2354,7 +2354,8 @@
22: "Failed to sign agent {0}: {1}",
23: "Unable to load agent icon file: {0}.",
24: "Unable to load agent logo file: {0}.",
- 25: "This NodeJS version does not support OpenID."
+ 25: "This NodeJS version does not support OpenID.",
+ 26: "This NodeJS version does not support Discord.js."
};
var x = '';
for (var i in message.warnings) {
@@ -11983,6 +11984,7 @@
var y = '';
x += '