From 0b1bf704aafe9029d9fe8de3fbe9ce8137dd3b9a Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Fri, 28 Oct 2022 17:44:06 -0700 Subject: [PATCH] Added CallMeBot messaging integration (#4688) --- meshmessaging.js | 50 ++++++++++++++++++++++++++++++++++++++-- meshuser.js | 9 ++++++-- views/default.handlebars | 38 ++++++++++++++++++++---------- 3 files changed, 81 insertions(+), 16 deletions(-) diff --git a/meshmessaging.js b/meshmessaging.js index cbe308b8..88e3ea9c 100644 --- a/meshmessaging.js +++ b/meshmessaging.js @@ -53,18 +53,28 @@ } } } + +// For CallMeBot +// For Signal Messenger: https://www.callmebot.com/blog/free-api-signal-send-messages/ +{ + "messaging": { + "callmebot": true + } +} + */ // 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 + obj.providers = 0; // 1 = Telegram, 2 = Signal, 4 = Discord, 8 = XMPP, 16 = CallMeBot obj.telegramClient = null; obj.discordClient = null; obj.discordUrl = null; obj.xmppClient = null; var xmppXml = null; + obj.callMeBotClient = null; // Telegram client setup if (parent.config.messaging.telegram) { @@ -154,7 +164,7 @@ module.exports.CreateServer = function (parent) { // XMPP client setup if (parent.config.messaging.xmpp) { - // Validate Discord configuration values + // Validate XMPP configuration values var xmppOK = true; if (typeof parent.config.messaging.xmpp.service != 'string') { console.log('Invalid or missing XMPP service.'); xmppOK = false; } @@ -176,6 +186,12 @@ module.exports.CreateServer = function (parent) { } } + // CallMeBot client setup + if (parent.config.messaging.callmebot) { + obj.callMeBotClient = true; + obj.providers += 16; // Enable CallMeBot 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; }); @@ -221,12 +237,42 @@ module.exports.CreateServer = function (parent) { } else if ((to.startsWith('xmpp:')) && (obj.xmppClient != null)) { // XMPP parent.debug('email', 'Sending XMPP message to: ' + to.substring(5) + ': ' + msg); sendXmppMessage(to, msg, func); + } else if ((to.startsWith('callmebot:')) && (obj.callMeBotClient != null)) { // CallMeBot + parent.debug('email', 'Sending CallMeBot message to: ' + to.substring(10) + ': ' + msg); + console.log('Sending CallMeBot message to: ' + to.substring(10) + ': ' + msg); + var toData = to.substring(10).split('|'); + if ((toData[0] == 'signal') && (toData.length == 3)) { + var url = 'https://api.callmebot.com/signal/send.php?phone=' + encodeURIComponent(toData[1]) + '&apikey=' + encodeURIComponent(toData[2]) + '&text=' + encodeURIComponent(msg); + require('https').get(url, function (r) { if (func != null) { func(r.statusCode == 200); } }); + } else if ((toData[0] == 'whatsapp') && (toData.length == 3)) { + var url = 'https://api.callmebot.com/whatsapp.php?phone=' + encodeURIComponent(toData[1]) + '&apikey=' + encodeURIComponent(toData[2]) + '&text=' + encodeURIComponent(msg); + require('https').get(url, function (r) { if (func != null) { func(r.statusCode == 200); } }); + } else if ((toData[0] == 'facebook') && (toData.length == 2)) { + var url = 'https://api.callmebot.com/facebook/send.php?apikey=' + encodeURIComponent(toData[1]) + '&text=' + encodeURIComponent(msg); + require('https').get(url, function (r) { if (func != null) { func(r.statusCode == 200); } }); + } } else { // No providers found func(false, "No messaging providers found for this message."); } } + // Convert a CallMeBot URL into a handle + obj.callmebotUrlToHandle = function (xurl) { + var url = null; + try { url = require('url').parse(xurl); } catch (ex) { return; } + if ((url == null) || (url.host != 'api.callmebot.com') || (url.protocol != 'https:') || (url.query == null)) return; + var urlArgs = {}, urlArgs2 = url.query.split('&'); + for (var i in urlArgs2) { var j = urlArgs2[i].indexOf('='); if (j > 0) { urlArgs[urlArgs2[i].substring(0, j)] = urlArgs2[i].substring(j + 1); } } + if ((urlArgs['phone'] != null) && (urlArgs['phone'].indexOf('|') >= 0)) return; + if ((urlArgs['apikey'] != null) && (urlArgs['apikey'].indexOf('|') >= 0)) return; + // Signal Messenger, Whatapp and Facebook + if (url.path.startsWith('/signal') && (urlArgs['phone'] != null) && (urlArgs['apikey'] != null)) { return 'callmebot:signal|' + urlArgs['phone'] + '|' + urlArgs['apikey']; } + if (url.path.startsWith('/whatsapp') && (urlArgs['phone'] != null) && (urlArgs['apikey'] != null)) { return 'callmebot:whatsapp|' + urlArgs['phone'] + '|' + urlArgs['apikey']; } + if (url.path.startsWith('/facebook') && (urlArgs['apikey'] != null)) { return 'callmebot:facebook|' + urlArgs['apikey']; } + return null; + } + // Get the correct SMS template function getTemplate(templateNumber, domain, lang) { parent.debug('email', 'Getting SMS template #' + templateNumber + ', lang: ' + lang); diff --git a/meshuser.js b/meshuser.js index 811b5ae6..a4389878 100644 --- a/meshuser.js +++ b/meshuser.js @@ -1390,7 +1390,11 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (command.resetNextLogin === true) { chguser.passchange = -1; } if ((command.consent != null) && (typeof command.consent == 'number')) { if (command.consent == 0) { delete chguser.consent; } else { chguser.consent = command.consent; } change = 1; } if ((command.phone != null) && (typeof command.phone == 'string') && ((command.phone == '') || isPhoneNumber(command.phone))) { if (command.phone == '') { delete chguser.phone; } else { chguser.phone = command.phone; } change = 1; } - if ((command.msghandle != null) && (typeof command.msghandle == 'string')) { if (command.msghandle == '') { delete chguser.msghandle; } else { chguser.msghandle = command.msghandle; } change = 1; } + if ((command.msghandle != null) && (typeof command.msghandle == 'string')) { + if (command.msghandle.startsWith('callmebot:https://')) { const h = parent.parent.msgserver.callmebotUrlToHandle(command.msghandle.substring(10)); if (h) { command.msghandle = h; } else { command.msghandle = ''; } } + if (command.msghandle == '') { delete chguser.msghandle; } else { chguser.msghandle = command.msghandle; } + change = 1; + } if ((command.flags != null) && (typeof command.flags == 'number')) { // Flags: 1 = Account Image, 2 = Session Recording if ((command.flags == 0) && (chguser.flags != null)) { delete chguser.flags; change = 1; } else { if (command.flags !== chguser.flags) { chguser.flags = command.flags; change = 1; } } @@ -6689,13 +6693,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return; // If this account is settings locked, return here. if (parent.parent.msgserver == null) return; - if (common.validateString(command.handle, 1, 64) == false) return; // Check handle length + if (common.validateString(command.handle, 1, 1024) == false) return; // Check handle length // 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 ((command.service == 8) && ((parent.parent.msgserver.providers & 8) != 0)) { handle = 'xmpp:' + command.handle; } + if ((command.service == 16) && ((parent.parent.msgserver.providers & 16) != 0)) { handle = parent.parent.msgserver.callmebotUrlToHandle(command.handle); } if (handle == null) return; // Send a verification message diff --git a/views/default.handlebars b/views/default.handlebars index 4abe71ac..c37dd625 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -11982,15 +11982,16 @@ x = '
'; x += '' + "Enter your messaging service and handle. Once verified, this server can send you login verification and other notifications." + '

'; var y = ''; x += '
' + "Service" + '' + y; - x += '
' + "Handle" + ''; + x += '
' + "Handle" + ''; x += '
'; - if (serverinfo.discordUrl) { x += '' } + if (serverinfo.discordUrl) { x += ''; } + x += ''; setDialogMode(2, "Messaging Notifications", 3, account_manageMessagingAdd, x, 'verifyMessaging'); Q('d2handleinput').focus(); account_manageMessagingValidate(); @@ -11999,8 +12000,10 @@ function account_manageMessagingValidate(x) { if (serverinfo.discordUrl) { QV('d2discordurl', Q('d2serviceselect').value == 4); } + QV('d2callmebotinfo', Q('d2serviceselect').value == 16); if (Q('d2serviceselect').value == 4) { Q('d2handleinput')['placeholder'] = "Username:0000"; } else if (Q('d2serviceselect').value == 8) { Q('d2handleinput')['placeholder'] = "username@server.com"; } + else if (Q('d2serviceselect').value == 16) { Q('d2handleinput')['placeholder'] = "https://api.callmebot.com/..."; } else { Q('d2handleinput')['placeholder'] = "Username"; } var ok = (Q('d2handleinput').value.length > 0); QE('idx_dlgOkButton', ok); if ((x == 1) && ok) { dialogclose(1); } } @@ -15860,21 +15863,29 @@ var x = '
'; x += '' + "Messaging account for this user."; var y = ''; x += '
' + "Service" + '' + y; - x += '
' + "Handle" + ''; + x += '
' + "Handle" + ''; x += '
'; if (serverinfo.discordUrl) { x += '' } + x += ''; setDialogMode(2, "Messaging Notifications", 3, p30editMessagingEx, x, 'verifyMessaging'); Q('d2handleinput').focus(); if (userinfo.msghandle) { if (userinfo.msghandle.startsWith('telegram:') && ((serverinfo.userMsgProviders & 1) != 0)) { Q('d2serviceselect').value = 1; Q('d2handleinput').value = userinfo.msghandle.substring(10); } if (userinfo.msghandle.startsWith('discord:') && ((serverinfo.userMsgProviders & 4) != 0)) { Q('d2serviceselect').value = 4; Q('d2handleinput').value = userinfo.msghandle.substring(8); } - if (userinfo.msghandle.startsWith('xmpp:') && ((serverinfo.userMsgProviders & 8) != 0)) { Q('d2serviceselect').value = 4; Q('d2handleinput').value = userinfo.msghandle.substring(5); } + if (userinfo.msghandle.startsWith('xmpp:') && ((serverinfo.userMsgProviders & 8) != 0)) { Q('d2serviceselect').value = 8; Q('d2handleinput').value = userinfo.msghandle.substring(5); } + if (userinfo.msghandle.startsWith('callmebot:') && ((serverinfo.userMsgProviders & 16) != 0)) { + Q('d2serviceselect').value = 16; + var toData = userinfo.msghandle.substring(10).split('|'); + if ((toData[0] == 'signal') && (toData.length == 3)) { Q('d2handleinput').value = 'https://api.callmebot.com/signal/send.php?phone=' + decodeURIComponent(toData[1]) + '&apikey=' + decodeURIComponent(toData[2]); } + if ((toData[0] == 'whatsapp') && (toData.length == 3)) { Q('d2handleinput').value = 'https://api.callmebot.com/whatsapp.php?phone=' + decodeURIComponent(toData[1]) + '&apikey=' + decodeURIComponent(toData[2]); } + if ((toData[0] == 'facebook') && (toData.length == 2)) { Q('d2handleinput').value = 'https://api.callmebot.com/facebook/send.php?apikey=' + decodeURIComponent(toData[1]); } + } } p30editMessagingValidate(); } @@ -15882,9 +15893,11 @@ function p30editMessagingValidate(x) { QE('d2handleinput', Q('d2serviceselect').value != 0); if (serverinfo.discordUrl) { QV('d2discordurl', Q('d2serviceselect').value == 4); } + QV('d2callmebotinfo', Q('d2serviceselect').value == 16); if (Q('d2serviceselect').value == 0) { Q('d2handleinput')['placeholder'] = ''; } else if (Q('d2serviceselect').value == 4) { Q('d2handleinput')['placeholder'] = "Username:0000"; } else if (Q('d2serviceselect').value == 8) { Q('d2handleinput')['placeholder'] = "username@server.com"; } + else if (Q('d2serviceselect').value == 16) { Q('d2handleinput')['placeholder'] = "https://api.callmebot.com/..."; } else { Q('d2handleinput')['placeholder'] = "Username"; } if (x == 1) { dialogclose(1); } } @@ -15896,6 +15909,7 @@ else if (Q('d2serviceselect').value == 1) { handle = 'telegram:@' + Q('d2handleinput').value; } else if (Q('d2serviceselect').value == 4) { handle = 'discord:' + Q('d2handleinput').value; } else if (Q('d2serviceselect').value == 8) { handle = 'xmpp:' + Q('d2handleinput').value; } + else if (Q('d2serviceselect').value == 16) { handle = 'callmebot:' + Q('d2handleinput').value; } if (handle != null) { meshserver.send({ action: 'edituser', id: currentUser._id, msghandle: handle }); } }