You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
224 lines
6.9 KiB
JavaScript
224 lines
6.9 KiB
JavaScript
4 years ago
|
/*
|
||
|
* Copyright 2020 Netsyms Technologies.
|
||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||
|
*/
|
||
|
|
||
|
console.log("Starting up...");
|
||
|
|
||
|
import sdk from 'matrix-js-sdk';
|
||
|
import fs from 'fs';
|
||
|
import log4js from 'log4js';
|
||
|
import https from 'https';
|
||
|
|
||
|
// Load settings from config.json
|
||
|
let rawdata = fs.readFileSync('config.json');
|
||
|
let settings = JSON.parse(rawdata);
|
||
|
console.log("config.json loaded.");
|
||
|
|
||
|
var logger = log4js.getLogger();
|
||
|
logger.level = settings.loglevel;
|
||
|
logger.info("Log initialized.");
|
||
|
|
||
|
var initialsynccomplete = false;
|
||
|
|
||
|
function checkSMS() {
|
||
|
logger.debug("Checking SMS");
|
||
|
|
||
|
const options = {
|
||
|
hostname: 'smsapi.voxtelesys.net',
|
||
|
port: 443,
|
||
|
path: '/api/v1/msgs/inbound?unread_only=true',
|
||
|
method: 'GET',
|
||
|
headers: {
|
||
|
"Authorization": "Token token=" + settings.smstoken
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const req = https.request(options, res => {
|
||
|
res.on('data', d => {
|
||
|
try {
|
||
|
var json = JSON.parse(d);
|
||
|
var messages = json.results;
|
||
|
|
||
|
if (messages.length == 0) {
|
||
|
logger.debug("No new SMS messages.");
|
||
|
}
|
||
|
|
||
|
for (var i = 0; i < messages.length; i++) {
|
||
|
var msg = messages[i];
|
||
|
logger.info("Received SMS from " + msg.from + ": " + msg.body);
|
||
|
createOrJoinSMSRoom(msg.from, function (roomid) {
|
||
|
sendMatrix(roomid, msg.body);
|
||
|
});
|
||
|
}
|
||
|
} catch (ex) {
|
||
|
logger.error(ex);
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
|
||
|
req.on('error', error => {
|
||
|
logger.warning(error);
|
||
|
});
|
||
|
|
||
|
req.end();
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Join or create+join a room with alias #SMS_{tel}. If already joined, do nothing.
|
||
|
* @param {string} tel
|
||
|
* @param {function} callback function with the room ID as an argument.
|
||
|
* @returns {undefined}
|
||
|
*/
|
||
|
function createOrJoinSMSRoom(tel, callback) {
|
||
|
logger.debug("Checking if room #SMS_" + tel + ":" + settings.matrixdomain + " exists.");
|
||
|
client.getRoomIdForAlias("#SMS_" + tel + ":" + settings.matrixdomain).then((res) => {
|
||
|
logger.debug("Room #SMS_" + tel + ":" + settings.matrixdomain + " exists!");
|
||
|
var inRoom = false;
|
||
|
var rooms = client.getRooms();
|
||
|
for (var i = 0; i < rooms.length; i++) {
|
||
|
if (rooms[i].roomId == res.room_id) {
|
||
|
inRoom = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (inRoom) {
|
||
|
// we're already in the room, do nothing
|
||
|
logger.debug("Room #SMS_" + tel + ":" + settings.matrixdomain + " already joined.");
|
||
|
callback(res.room_id);
|
||
|
} else {
|
||
|
// not in the room, join it
|
||
|
client.joinRoom(res.room_id).then((room) => {
|
||
|
logger.debug("Room #SMS_" + tel + ":" + settings.matrixdomain + " joined.");
|
||
|
callback(room.room_id);
|
||
|
});
|
||
|
}
|
||
|
}).catch((err) => {
|
||
|
// room doesn't exist, create it
|
||
|
//logger.debug(err);
|
||
|
logger.debug("Room #SMS_" + tel + ":" + settings.matrixdomain + " does not exist. Creating it now.");
|
||
|
client.createRoom({
|
||
|
room_alias_name: "SMS_" + tel,
|
||
|
visibility: "private",
|
||
|
invite: settings.inviteusers,
|
||
|
name: "SMS: " + tel,
|
||
|
topic: "SMS conversation with " + tel
|
||
|
}).then((room) => {
|
||
|
logger.debug("Room #SMS_" + tel + ":" + settings.matrixdomain + " created with ID " + room.room_id);
|
||
|
|
||
|
// The first message or two we send doesn't go through unless we do this.
|
||
|
// It just spits out "Error sending event M_FORBIDDEN: Unknown room" instead.
|
||
|
createOrJoinSMSRoom(tel, callback);
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Send a message to a Matrix room.
|
||
|
* @param {string} roomid the room to post the message in.
|
||
|
* @param {string} body message content.
|
||
|
* @param {function|undefined} callback passes true when successful, false on failure.
|
||
|
* @returns {undefined}
|
||
|
*/
|
||
|
function sendMatrix(roomid, body, callback) {
|
||
|
|
||
|
var content = {
|
||
|
body: body,
|
||
|
msgtype: "m.text"
|
||
|
}
|
||
|
client.sendEvent(roomid, "m.room.message", content, "").then((res) => {
|
||
|
if (typeof callback == "function") {
|
||
|
callback(true);
|
||
|
}
|
||
|
}).catch((err) => {
|
||
|
if (typeof callback == "function") {
|
||
|
callback(false);
|
||
|
}
|
||
|
if (err.data.error == "Unknown room") {
|
||
|
return;
|
||
|
}
|
||
|
logger.error(err);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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 sendSMS(number, body, callback) {
|
||
|
logger.info("Sending SMS to " + number);
|
||
|
const data = JSON.stringify({
|
||
|
to: [number],
|
||
|
from: settings.smsfrom,
|
||
|
body: body
|
||
|
});
|
||
|
|
||
|
const options = {
|
||
|
hostname: 'smsapi.voxtelesys.net',
|
||
|
port: 443,
|
||
|
path: '/api/v1/sms',
|
||
|
method: 'POST',
|
||
|
headers: {
|
||
|
"Authorization": "Token token=" + settings.smstoken,
|
||
|
"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);
|
||
|
});
|
||
|
|
||
|
req.write(data);
|
||
|
req.end();
|
||
|
if (typeof callback == "function") {
|
||
|
callback(true);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const client = sdk.createClient(settings.homeserver);
|
||
|
client.login("m.login.password", {"user": settings.matrixuser, "password": settings.matrixpass}).then((response) => {
|
||
|
client.startClient();
|
||
|
logger.info("Plugged into the matrix.");
|
||
|
|
||
|
client.once('sync', function (state, prevState, res) {
|
||
|
logger.debug("Initial sync complete (" + state + ")");
|
||
|
initialsynccomplete = true;
|
||
|
logger.info("Up and running.");
|
||
|
setInterval(checkSMS, settings.smsinterval * 1000);
|
||
|
checkSMS();
|
||
|
});
|
||
|
|
||
|
|
||
|
client.on("Room.timeline", function (event, room) {
|
||
|
if (!initialsynccomplete) {
|
||
|
return; // ignore anything while we were offline
|
||
|
}
|
||
|
if (event.getType() !== "m.room.message") {
|
||
|
return; // only use messages
|
||
|
}
|
||
|
if (client.getUserId() == event.event.sender) {
|
||
|
return; // skip own messages to prevent loop
|
||
|
}
|
||
|
//sendMatrix(room.roomId, "echo " + event.event.content.body);
|
||
|
//console.log(room);
|
||
|
const matches = room.name.match(/([1-9][0-9]+)/g);
|
||
|
if (matches.length == 1) {
|
||
|
var tel = matches[0];
|
||
|
logger.info("Got message for " + tel + " from " + event.event.sender + ", relaying.");
|
||
|
sendSMS(tel, event.event.content.body);
|
||
|
}
|
||
|
});
|
||
|
});
|