|
|
|
@ -14,12 +14,11 @@ import sdk from 'matrix-js-sdk';
|
|
|
|
|
import fs from 'fs';
|
|
|
|
|
import log4js from 'log4js';
|
|
|
|
|
import https from 'https';
|
|
|
|
|
import { fileURLToPath }
|
|
|
|
|
from 'url';
|
|
|
|
|
import { dirname }
|
|
|
|
|
from 'path';
|
|
|
|
|
import { fileURLToPath } from 'url';
|
|
|
|
|
import { dirname } from 'path';
|
|
|
|
|
import request from 'request';
|
|
|
|
|
import FileType from 'file-type';
|
|
|
|
|
import http from 'http';
|
|
|
|
|
// Load settings from config.json
|
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
|
|
|
const __dirname = dirname(__filename);
|
|
|
|
@ -293,12 +292,66 @@ function sendMatrixNotice(roomid, body, callback) {
|
|
|
|
|
* @returns {undefined}
|
|
|
|
|
*/
|
|
|
|
|
function sendSMS(number, from, body, callback) {
|
|
|
|
|
if (settings.googleverifiedsms) {
|
|
|
|
|
// Use Google Verified SMS to add business branding to SMS message
|
|
|
|
|
}
|
|
|
|
|
logger.info("Sending SMS to " + number + " from " + from);
|
|
|
|
|
const data = JSON.stringify({
|
|
|
|
|
var data = {
|
|
|
|
|
to: [number],
|
|
|
|
|
from: from,
|
|
|
|
|
body: body
|
|
|
|
|
};
|
|
|
|
|
const jsondata = JSON.stringify(data);
|
|
|
|
|
const options = {
|
|
|
|
|
hostname: 'smsapi.voxtelesys.net',
|
|
|
|
|
port: 443,
|
|
|
|
|
path: '/api/v1/sms',
|
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: {
|
|
|
|
|
"Authorization": "Bearer " + settings.smsapikey,
|
|
|
|
|
"Content-Type": "application/json",
|
|
|
|
|
"Accept": "application/json"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const req = https.request(options, res => {
|
|
|
|
|
res.on('data', d => {
|
|
|
|
|
logger.debug(d.toString('utf8'));
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
req.on('error', error => {
|
|
|
|
|
logger.error(error);
|
|
|
|
|
callback(false);
|
|
|
|
|
});
|
|
|
|
|
req.write(jsondata);
|
|
|
|
|
req.end();
|
|
|
|
|
if (typeof callback == "function") {
|
|
|
|
|
callback(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Send a SMS to a phone number.
|
|
|
|
|
* @param {string} number
|
|
|
|
|
* @param {string} body message content.
|
|
|
|
|
* @param {function|undefined} callback passes true when successful, false on failure.
|
|
|
|
|
* @returns {undefined}
|
|
|
|
|
*/
|
|
|
|
|
function sendMMS(number, from, mediauri, mimetype, callback) {
|
|
|
|
|
logger.info("Sending MMS to " + number + " from " + from);
|
|
|
|
|
var mediauriregex = /^mxc:\/\/([a-zA-Z0-9\-]+\.[a-zA-Z0-9]{2,})\/([a-z0-9]+)$/;
|
|
|
|
|
var matches = mediauriregex.exec(mediauri);
|
|
|
|
|
var httpmediaurl = settings.mediaurlpath;
|
|
|
|
|
|
|
|
|
|
httpmediaurl = httpmediaurl.replace("{{server-name}}", matches[0]);
|
|
|
|
|
httpmediaurl = httpmediaurl.replace("{{media-id}}", matches[1]);
|
|
|
|
|
var data = {
|
|
|
|
|
to: [number],
|
|
|
|
|
from: from,
|
|
|
|
|
body: body,
|
|
|
|
|
media: [httpmediaurl]
|
|
|
|
|
};
|
|
|
|
|
const jsondata = JSON.stringify(data);
|
|
|
|
|
const options = {
|
|
|
|
|
hostname: 'smsapi.voxtelesys.net',
|
|
|
|
|
port: 443,
|
|
|
|
@ -320,13 +373,55 @@ function sendSMS(number, from, body, callback) {
|
|
|
|
|
logger.error(error);
|
|
|
|
|
callback(false);
|
|
|
|
|
});
|
|
|
|
|
req.write(data);
|
|
|
|
|
req.write(jsondata);
|
|
|
|
|
req.end();
|
|
|
|
|
if (typeof callback == "function") {
|
|
|
|
|
callback(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleHTTPRequest(request, response) {
|
|
|
|
|
if (request.url == "/webhook") {
|
|
|
|
|
try {
|
|
|
|
|
logger.debug("Got webhook: " + request.body);
|
|
|
|
|
var msg = JSON.parse(request.body);
|
|
|
|
|
|
|
|
|
|
if (msg.type == "mo") {
|
|
|
|
|
if (settings.smsonlyto.length > 0 && settings.smsonlyto.indexOf(msg.to) != -1) {
|
|
|
|
|
logger.info("Received SMS from " + msg.from + " for " + msg.to + ": " + msg.body);
|
|
|
|
|
createOrJoinSMSRoom(msg.from, msg.to, function (roomid) {
|
|
|
|
|
sendMatrix(roomid, msg.body, msg.media);
|
|
|
|
|
});
|
|
|
|
|
response.status(204);
|
|
|
|
|
response.end();
|
|
|
|
|
} else {
|
|
|
|
|
logger.info("Received SMS from " + msg.from + " for " + msg.to + ", ignoring based on smsonlyto list.");
|
|
|
|
|
response.status(403);
|
|
|
|
|
response.body("403 forbidden (this endpoint doesn't deliver SMS destined for that number)");
|
|
|
|
|
response.end();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
response.status(403);
|
|
|
|
|
response.body("403 forbidden (webhook type not handled by this endpoint)");
|
|
|
|
|
response.end();
|
|
|
|
|
}
|
|
|
|
|
} catch (ex) {
|
|
|
|
|
logger.error("Decoding webhook body: " + ex);
|
|
|
|
|
response.status(500);
|
|
|
|
|
response.body("500 internal server error");
|
|
|
|
|
response.end();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
try {
|
|
|
|
|
response.status(404);
|
|
|
|
|
response.body("404 not found");
|
|
|
|
|
response.end();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
logger.error(err);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const client = sdk.createClient(settings.homeserver);
|
|
|
|
|
client.login("m.login.password", {"user": settings.matrixuser, "password": settings.matrixpass}).then((response) => {
|
|
|
|
|
client.startClient();
|
|
|
|
@ -334,9 +429,14 @@ client.login("m.login.password", {"user": settings.matrixuser, "password": setti
|
|
|
|
|
client.once('sync', function (state, prevState, res) {
|
|
|
|
|
logger.debug("Initial sync complete (" + state + ")");
|
|
|
|
|
initialsynccomplete = true;
|
|
|
|
|
var httpserver = http.createServer(handleHTTPRequest);
|
|
|
|
|
httpserver.listen(settings.listenport);
|
|
|
|
|
logger.info("HTTP server started on port " + settings.listenport);
|
|
|
|
|
logger.info("Up and running.");
|
|
|
|
|
setInterval(checkSMS, settings.smsinterval * 1000);
|
|
|
|
|
checkSMS();
|
|
|
|
|
if (settings.smsinterval > 0) {
|
|
|
|
|
setInterval(checkSMS, settings.smsinterval * 1000);
|
|
|
|
|
checkSMS();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
client.on("Room.timeline", function (event, room) {
|
|
|
|
|
if (!initialsynccomplete) {
|
|
|
|
@ -348,7 +448,7 @@ client.login("m.login.password", {"user": settings.matrixuser, "password": setti
|
|
|
|
|
if (client.getUserId() == event.getSender()) {
|
|
|
|
|
return; // skip own messages to prevent loop
|
|
|
|
|
}
|
|
|
|
|
if (event.getContent().body.startsWith("!sms")) {
|
|
|
|
|
if (event.getContent().body.toLowerCase().startsWith("!sms")) {
|
|
|
|
|
// capture command to start room for new number
|
|
|
|
|
const matches = event.getContent().body.match(/([1-9]?[0-9]{10})/g);
|
|
|
|
|
if (matches.length == 1 || matches.length == 2) {
|
|
|
|
@ -373,7 +473,7 @@ client.login("m.login.password", {"user": settings.matrixuser, "password": setti
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (event.getContent().body.startsWith("!fixnumbers")) {
|
|
|
|
|
if (event.getContent().body.toLowerCase().startsWith("!fixnumbers")) {
|
|
|
|
|
// capture command to start room for new number
|
|
|
|
|
const matches = event.getContent().body.match(/([1-9]?[0-9]{10})/g);
|
|
|
|
|
if (matches.length == 2) {
|
|
|
|
@ -403,25 +503,55 @@ client.login("m.login.password", {"user": settings.matrixuser, "password": setti
|
|
|
|
|
var tel = response.tags["u.matrix-bridge-voxtelesys-sms"].tel;
|
|
|
|
|
var from = response.tags["u.matrix-bridge-voxtelesys-sms"].ournumber;
|
|
|
|
|
logger.info("Got message for " + tel + " from " + event.getSender() + ", relaying to " + from + ".");
|
|
|
|
|
sendSMS(
|
|
|
|
|
tel,
|
|
|
|
|
from,
|
|
|
|
|
event.getContent().body,
|
|
|
|
|
function () {
|
|
|
|
|
client.sendReadReceipt(event, {});
|
|
|
|
|
});
|
|
|
|
|
switch (event.getContent().msgtype) {
|
|
|
|
|
case "m.image":
|
|
|
|
|
sendMMS(
|
|
|
|
|
tel,
|
|
|
|
|
from,
|
|
|
|
|
event.getContent().url,
|
|
|
|
|
event.getContent().info.mimetype,
|
|
|
|
|
function () {
|
|
|
|
|
client.sendReadReceipt(event, {});
|
|
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
case "m.text":
|
|
|
|
|
default:
|
|
|
|
|
sendSMS(
|
|
|
|
|
tel,
|
|
|
|
|
from,
|
|
|
|
|
event.getContent().body,
|
|
|
|
|
function () {
|
|
|
|
|
client.sendReadReceipt(event, {});
|
|
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else if (typeof response.tags["com.netsyms.matrix-bridge-voxtelesys.sms"] != "undefined") {
|
|
|
|
|
var tel = response.tags["com.netsyms.matrix-bridge-voxtelesys.sms"].tel;
|
|
|
|
|
var from = response.tags["com.netsyms.matrix-bridge-voxtelesys.sms"].ournumber;
|
|
|
|
|
client.setRoomTag(event.getRoomId(), "u.matrix-bridge-voxtelesys-sms", {tel: tel, ournumber: from, order: 0.5});
|
|
|
|
|
logger.info("Got message for " + tel + " from " + event.getSender() + ", relaying to " + from + ".");
|
|
|
|
|
sendSMS(
|
|
|
|
|
tel,
|
|
|
|
|
from,
|
|
|
|
|
event.getContent().body,
|
|
|
|
|
function () {
|
|
|
|
|
client.sendReadReceipt(event, {});
|
|
|
|
|
});
|
|
|
|
|
switch (event.getContent().msgtype) {
|
|
|
|
|
case "m.image":
|
|
|
|
|
sendMMS(
|
|
|
|
|
tel,
|
|
|
|
|
from,
|
|
|
|
|
event.getContent().url,
|
|
|
|
|
event.getContent().info.mimetype,
|
|
|
|
|
function () {
|
|
|
|
|
client.sendReadReceipt(event, {});
|
|
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
case "m.text":
|
|
|
|
|
default:
|
|
|
|
|
sendSMS(
|
|
|
|
|
tel,
|
|
|
|
|
from,
|
|
|
|
|
event.getContent().body,
|
|
|
|
|
function () {
|
|
|
|
|
client.sendReadReceipt(event, {});
|
|
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
console.log(response.tags);
|
|
|
|
|
sendMatrixNotice(room.roomId, "Error: couldn't determine correct number to send SMS from.");
|
|
|
|
@ -431,16 +561,40 @@ client.login("m.login.password", {"user": settings.matrixuser, "password": setti
|
|
|
|
|
if (matches.length == 1) {
|
|
|
|
|
var tel = matches[0];
|
|
|
|
|
logger.info("Got message for " + tel + " from " + event.getSender() + ", relaying.");
|
|
|
|
|
sendSMS(tel, settings.smsfrom, event.getContent().body, function () {
|
|
|
|
|
client.sendReadReceipt(event, {});
|
|
|
|
|
});
|
|
|
|
|
switch (event.getContent().msgtype) {
|
|
|
|
|
case "m.image":
|
|
|
|
|
sendMMS(tel, settings.smsfrom, event.getContent().url,
|
|
|
|
|
event.getContent().info.mimetype,
|
|
|
|
|
function () {
|
|
|
|
|
client.sendReadReceipt(event, {});
|
|
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
case "m.text":
|
|
|
|
|
default:
|
|
|
|
|
sendSMS(tel, settings.smsfrom, event.getContent().body, function () {
|
|
|
|
|
client.sendReadReceipt(event, {});
|
|
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else if (matches.length == 2) {
|
|
|
|
|
var tel = matches[0];
|
|
|
|
|
var from = matches[1];
|
|
|
|
|
logger.info("Got message for " + tel + " from " + event.getSender() + ", relaying to " + from + ".");
|
|
|
|
|
sendSMS(tel, from, event.getContent().body, function () {
|
|
|
|
|
client.sendReadReceipt(event, {});
|
|
|
|
|
});
|
|
|
|
|
switch (event.getContent().msgtype) {
|
|
|
|
|
case "m.image":
|
|
|
|
|
sendMMS(tel, from, event.getContent().url,
|
|
|
|
|
event.getContent().info.mimetype,
|
|
|
|
|
function () {
|
|
|
|
|
client.sendReadReceipt(event, {});
|
|
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
case "m.text":
|
|
|
|
|
default:
|
|
|
|
|
sendSMS(tel, settings.smsfrom, event.getContent().body, function () {
|
|
|
|
|
client.sendReadReceipt(event, {});
|
|
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|