123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- /**
- * @description MeshCentral SMS gateway communication module
- * @author Ylian Saint-Hilaire
- * @copyright Intel Corporation 2018-2022
- * @license Apache-2.0
- * @version v0.0.1
- */
- /*xjslint node: true */
- /*xjslint plusplus: true */
- /*xjslint maxlen: 256 */
- /*jshint node: true */
- /*jshint strict: false */
- /*jshint esversion: 6 */
- "use strict";
- /*
- // For Twilio, add this in config.json
- "sms": {
- "provider": "twilio",
- "sid": "ACxxxxxxxxx",
- "auth": "xxxxxxx",
- "from": "+15555555555"
- },
- // For Plivo, add this in config.json
- "sms": {
- "provider": "plivo",
- "id": "xxxxxxx",
- "token": "xxxxxxx",
- "from": "15555555555"
- }
- // For Telnyx, add this in config.json
- "sms": {
- "provider": "telnyx",
- "apikey": "xxxxxxx",
- "from": "15555555555"
- }
- // For URL, add this in config.json
- "sms": {
- "provider": "url",
- "url": "https://sample.com/?phone={{phone}}&msg={{message}}"
- }
- */
- // Construct a SMS server object
- module.exports.CreateMeshSMS = function (parent) {
- var obj = {};
- obj.parent = parent;
- obj.provider = null;
- // SMS gateway provider setup
- switch (parent.config.sms.provider) {
- case 'twilio': {
- // Validate Twilio configuration values
- if (typeof parent.config.sms.sid != 'string') { console.log('Invalid or missing SMS gateway provider sid.'); return null; }
- if (typeof parent.config.sms.auth != 'string') { console.log('Invalid or missing SMS gateway provider auth.'); return null; }
- if (typeof parent.config.sms.from != 'string') { console.log('Invalid or missing SMS gateway provider from.'); return null; }
- // Setup Twilio
- var Twilio = require('twilio');
- obj.provider = new Twilio(parent.config.sms.sid, parent.config.sms.auth);
- break;
- }
- case 'plivo': {
- // Validate Plivo configuration values
- if (typeof parent.config.sms.id != 'string') { console.log('Invalid or missing SMS gateway provider id.'); return null; }
- if (typeof parent.config.sms.token != 'string') { console.log('Invalid or missing SMS gateway provider token.'); return null; }
- if (typeof parent.config.sms.from != 'string') { console.log('Invalid or missing SMS gateway provider from.'); return null; }
- // Setup Plivo
- var plivo = require('plivo');
- obj.provider = new plivo.Client(parent.config.sms.id, parent.config.sms.token);
- break;
- }
- case 'telnyx': {
- // Validate Telnyx configuration values
- if (typeof parent.config.sms.apikey != 'string') { console.log('Invalid or missing SMS gateway provider apikey.'); return null; }
- if (typeof parent.config.sms.from != 'string') { console.log('Invalid or missing SMS gateway provider from.'); return null; }
- // Setup Telnyx
- obj.provider = require('telnyx')(parent.config.sms.apikey);
- break;
- }
- case 'url': {
- // Validate URL configuration values
- if (parent.config.sms.url != 'console') {
- if (typeof parent.config.sms.url != 'string') { console.log('Invalid or missing SMS gateway URL value.'); return null; }
- if (!parent.config.sms.url.toLowerCase().startsWith('http://') && !parent.config.sms.url.toLowerCase().startsWith('https://')) { console.log('Invalid or missing SMS gateway, URL must start with http:// or https://.'); return null; }
- if (parent.config.sms.url.indexOf('{{message}}') == -1) { console.log('Invalid or missing SMS gateway, URL must include {{message}}.'); return null; }
- if (parent.config.sms.url.indexOf('{{phone}}') == -1) { console.log('Invalid or missing SMS gateway, URL must include {{phone}}.'); return null; }
- }
- break;
- }
- default: {
- // Unknown SMS gateway provider
- console.log('Unknown SMS gateway provider: ' + parent.config.sms.provider);
- return null;
- }
- }
- // Send an SMS message
- obj.sendSMS = function (to, msg, func) {
- parent.debug('email', 'Sending SMS to: ' + to + ': ' + msg);
- if (parent.config.sms.provider == 'twilio') { // Twilio
- obj.provider.messages.create({
- from: parent.config.sms.from,
- to: to,
- body: msg
- }, function (err, result) {
- if (err != null) { parent.debug('email', 'SMS error: ' + err.message); } else { parent.debug('email', 'SMS result: ' + JSON.stringify(result)); }
- if (func != null) { func((err == null) && (result.status == 'queued'), err ? err.message : null, result); }
- });
- } else if (parent.config.sms.provider == 'plivo') { // Plivo
- if (to.split('-').join('').split(' ').join('').split('+').join('').length == 10) { to = '1' + to; } // If we only have 10 digits, add a 1 in front.
- obj.provider.messages.create(
- parent.config.sms.from,
- to,
- msg
- ).then(function (result) {
- parent.debug('email', 'SMS result: ' + JSON.stringify(result));
- if (func != null) { func((result != null) && (result.messageUuid != null), null, result); }
- }
- ).catch(function (err) {
- var msg = null;
- if ((err != null) && err.message) { msg = JSON.parse(err.message).error; }
- parent.debug('email', 'SMS error: ' + msg);
- if (func != null) { func(false, msg, null); }
- }
- );
- } else if (parent.config.sms.provider == 'telnyx') { // Telnyx
- obj.provider.messages.create({
- from: parent.config.sms.from,
- to: to,
- text: msg
- }, function (err, result) {
- if (err != null) { parent.debug('email', 'SMS error: ' + err.type); } else { parent.debug('email', 'SMS result: ' + JSON.stringify(result)); }
- if (func != null) { func((err == null), err ? err.type : null, result); }
- });
- } else if (parent.config.sms.provider == 'url') { // URL
- if (parent.config.sms.url == 'console') {
- // This is for debugging, just display the SMS to the console
- console.log('SMS (' + to + '): ' + msg);
- if (func != null) { func(true, null, null); }
- } else {
- var sms = parent.config.sms.url.split('{{phone}}').join(encodeURIComponent(to)).split('{{message}}').join(encodeURIComponent(msg));
- parent.debug('email', 'SMS URL: ' + sms);
- sms = require('url').parse(sms);
- if (sms.protocol == 'https:') {
- // HTTPS GET request
- const options = { hostname: sms.hostname, port: sms.port ? sms.port : 443, path: sms.path, method: 'GET', rejectUnauthorized: false };
- const request = require('https').request(options, function (res) { parent.debug('email', 'SMS result: ' + res.statusCode); if (func != null) { func(res.statusCode == 200, (res.statusCode == 200) ? null : res.statusCode, null); } res.on('data', function (d) { }); });
- request.on('error', function (err) { parent.debug('email', 'SMS error: ' + err); if (func != null) { func(false, err, null); } });
- request.end();
- } else {
- // HTTP GET request
- const options = { hostname: sms.hostname, port: sms.port ? sms.port : 80, path: sms.path, method: 'GET' };
- const request = require('http').request(options, function (res) { parent.debug('email', 'SMS result: ' + res.statusCode); if (func != null) { func(res.statusCode == 200, (res.statusCode == 200) ? null : res.statusCode, null); } res.on('data', function (d) { }); });
- request.on('error', function (err) { parent.debug('email', 'SMS error: ' + err); if (func != null) { func(false, err, null); } });
- request.end();
- }
- }
- }
- }
- // Get the correct SMS template
- function getTemplate(templateNumber, domain, lang) {
- parent.debug('email', 'Getting SMS template #' + templateNumber + ', lang: ' + lang);
- if (Array.isArray(lang)) { lang = lang[0]; } // TODO: For now, we only use the first language given.
- var r = {}, emailsPath = null;
- if ((domain != null) && (domain.webemailspath != null)) { emailsPath = domain.webemailspath; }
- else if (obj.parent.webEmailsOverridePath != null) { emailsPath = obj.parent.webEmailsOverridePath; }
- else if (obj.parent.webEmailsPath != null) { emailsPath = obj.parent.webEmailsPath; }
- if ((emailsPath == null) || (obj.parent.fs.existsSync(emailsPath) == false)) { return null }
- // Get the non-english email if needed
- var txtfile = null;
- if ((lang != null) && (lang != 'en')) {
- var translationsPath = obj.parent.path.join(emailsPath, 'translations');
- var translationsPathTxt = obj.parent.path.join(emailsPath, 'translations', 'sms-messages_' + lang + '.txt');
- if (obj.parent.fs.existsSync(translationsPath) && obj.parent.fs.existsSync(translationsPathTxt)) {
- txtfile = obj.parent.fs.readFileSync(translationsPathTxt).toString();
- }
- }
- // Get the english email
- if (txtfile == null) {
- var pathTxt = obj.parent.path.join(emailsPath, 'sms-messages.txt');
- if (obj.parent.fs.existsSync(pathTxt)) {
- txtfile = obj.parent.fs.readFileSync(pathTxt).toString();
- }
- }
- // No email templates
- if (txtfile == null) { return null; }
- // Decode the TXT file
- var lines = txtfile.split('\r\n').join('\n').split('\n')
- if (lines.length <= templateNumber) return null;
- return lines[templateNumber];
- }
- // Send phone number verification SMS
- obj.sendPhoneCheck = function (domain, phoneNumber, verificationCode, language, func) {
- parent.debug('email', "Sending verification SMS to " + phoneNumber);
- var sms = getTemplate(0, domain, language);
- if (sms == null) { parent.debug('email', "Error: Failed to get SMS template"); return; } // No SMS template found
- // Setup the template
- sms = sms.split('[[0]]').join(domain.title ? domain.title : 'MeshCentral');
- sms = sms.split('[[1]]').join(verificationCode);
- // Send the SMS
- obj.sendSMS(phoneNumber, sms, func);
- };
- // Send phone number verification SMS
- obj.sendToken = function (domain, phoneNumber, verificationCode, language, func) {
- parent.debug('email', "Sending login token SMS to " + phoneNumber);
- var sms = getTemplate(1, domain, language);
- if (sms == null) { parent.debug('email', "Error: Failed to get SMS template"); return; } // No SMS template found
- // Setup the template
- sms = sms.split('[[0]]').join(domain.title ? domain.title : 'MeshCentral');
- sms = sms.split('[[1]]').join(verificationCode);
- // Send the SMS
- obj.sendSMS(phoneNumber, sms, func);
- };
- return obj;
- };
|