|
|
@ -21,6 +21,7 @@ import request from 'request';
|
|
|
|
import FileType from 'file-type';
|
|
|
|
import FileType from 'file-type';
|
|
|
|
import express from 'express';
|
|
|
|
import express from 'express';
|
|
|
|
import bodyParser from 'body-parser';
|
|
|
|
import bodyParser from 'body-parser';
|
|
|
|
|
|
|
|
import fetch from 'node-fetch';
|
|
|
|
|
|
|
|
|
|
|
|
// Save script start time for ignoring older messages
|
|
|
|
// Save script start time for ignoring older messages
|
|
|
|
var boottimestamp = Date.now();
|
|
|
|
var boottimestamp = Date.now();
|
|
|
@ -112,6 +113,25 @@ function checkSMS() {
|
|
|
|
req.end();
|
|
|
|
req.end();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Connect to the server and get the room ID and stuff
|
|
|
|
|
|
|
|
* @param {type} alias
|
|
|
|
|
|
|
|
* @returns {undefined}
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
async function getRoomIDFromAlias(alias) {
|
|
|
|
|
|
|
|
var info = await client.getRoomIdForAlias(alias);
|
|
|
|
|
|
|
|
if (typeof info.room_id != "undefined") {
|
|
|
|
|
|
|
|
return info;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var response = await fetch(settings.homeserver + "/_matrix/client/v3/directory/room/" + encodeURIComponent(alias));
|
|
|
|
|
|
|
|
if (response.status != 200) {
|
|
|
|
|
|
|
|
throw new Error("Fetch returned invalid status code " + response.status);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
var json = await response.json();
|
|
|
|
|
|
|
|
return json;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Join or create+join a room with alias #SMS_{tel}. If already joined, do nothing.
|
|
|
|
* Join or create+join a room with alias #SMS_{tel}. If already joined, do nothing.
|
|
|
@ -120,17 +140,21 @@ function checkSMS() {
|
|
|
|
* @param {function} callback function with the room ID as an argument.
|
|
|
|
* @param {function} callback function with the room ID as an argument.
|
|
|
|
* @returns {undefined}
|
|
|
|
* @returns {undefined}
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
function createOrJoinSMSRoom(tel, ournumber, callback) {
|
|
|
|
async function createOrJoinSMSRoom(tel, ournumber, callback) {
|
|
|
|
var roomName = "#SMS_" + tel + "_" + ournumber + ":" + settings.matrixdomain;
|
|
|
|
var roomName = "#SMS_" + tel + "_" + ournumber + ":" + settings.matrixdomain;
|
|
|
|
logger.debug("Checking if room " + roomName + " exists.");
|
|
|
|
logger.debug("Checking if room " + roomName + " exists.");
|
|
|
|
client.getRoomIdForAlias(roomName).then((res) => {
|
|
|
|
try {
|
|
|
|
|
|
|
|
var res = await getRoomIDFromAlias(roomName);
|
|
|
|
|
|
|
|
logger.info(JSON.stringify(res));
|
|
|
|
logger.debug("Room " + roomName + " exists!");
|
|
|
|
logger.debug("Room " + roomName + " exists!");
|
|
|
|
var inRoom = false;
|
|
|
|
var inRoom = false;
|
|
|
|
var rooms = client.getRooms();
|
|
|
|
if (!res.error) {
|
|
|
|
for (var i = 0; i < rooms.length; i++) {
|
|
|
|
var rooms = (await client.getJoinedRooms()).joined_rooms;
|
|
|
|
if (rooms[i].roomId == res.room_id) {
|
|
|
|
for (var i = 0; i < rooms.length; i++) {
|
|
|
|
inRoom = true;
|
|
|
|
if (rooms[i] == res.room_id) {
|
|
|
|
break;
|
|
|
|
inRoom = true;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (inRoom) {
|
|
|
|
if (inRoom) {
|
|
|
@ -143,11 +167,11 @@ function createOrJoinSMSRoom(tel, ournumber, callback) {
|
|
|
|
client.joinRoom(res.room_id).then((room) => {
|
|
|
|
client.joinRoom(res.room_id).then((room) => {
|
|
|
|
logger.debug("Room " + roomName + " joined.");
|
|
|
|
logger.debug("Room " + roomName + " joined.");
|
|
|
|
client.setRoomTag(room.room_id, "u.matrix-bridge-voxtelesys-sms", {tel: tel, ournumber: ournumber, order: 0.5});
|
|
|
|
client.setRoomTag(room.room_id, "u.matrix-bridge-voxtelesys-sms", {tel: tel, ournumber: ournumber, order: 0.5});
|
|
|
|
callback(room.room_id);
|
|
|
|
callback(res.room_id);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}).catch((err) => {
|
|
|
|
} catch (err) {
|
|
|
|
// room doesn't exist, create it
|
|
|
|
// room doesn't exist, create it
|
|
|
|
logger.debug(err);
|
|
|
|
logger.debug(err);
|
|
|
|
logger.debug("Room " + roomName + " does not exist. Creating it now.");
|
|
|
|
logger.debug("Room " + roomName + " does not exist. Creating it now.");
|
|
|
@ -156,41 +180,42 @@ function createOrJoinSMSRoom(tel, ournumber, callback) {
|
|
|
|
userPowerLevels[settings.inviteusers[i]] = 50;
|
|
|
|
userPowerLevels[settings.inviteusers[i]] = 50;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
userPowerLevels[settings["matrixuser"]] = 100;
|
|
|
|
userPowerLevels[settings["matrixuser"]] = 100;
|
|
|
|
client.createRoom({
|
|
|
|
try {
|
|
|
|
room_alias_name: "SMS_" + tel + "_" + ournumber,
|
|
|
|
var room = await client.createRoom({
|
|
|
|
preset: "trusted_private_chat",
|
|
|
|
room_alias_name: "SMS_" + tel + "_" + ournumber,
|
|
|
|
visibility: "private",
|
|
|
|
preset: "trusted_private_chat",
|
|
|
|
invite: settings.inviteusers,
|
|
|
|
visibility: "private",
|
|
|
|
power_level_content_override: {
|
|
|
|
invite: settings.inviteusers,
|
|
|
|
"events": {
|
|
|
|
power_level_content_override: {
|
|
|
|
"m.room.name": 50,
|
|
|
|
"events": {
|
|
|
|
"m.room.power_levels": 50,
|
|
|
|
"m.room.name": 50,
|
|
|
|
"m.room.canonical_alias": 100
|
|
|
|
"m.room.power_levels": 50,
|
|
|
|
},
|
|
|
|
"m.room.canonical_alias": 100
|
|
|
|
"events_default": 0,
|
|
|
|
},
|
|
|
|
"invite": 50,
|
|
|
|
"events_default": 0,
|
|
|
|
"kick": 50,
|
|
|
|
"invite": 50,
|
|
|
|
"notifications": {
|
|
|
|
"kick": 50,
|
|
|
|
"room": 50
|
|
|
|
"notifications": {
|
|
|
|
|
|
|
|
"room": 50
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
"redact": 50,
|
|
|
|
|
|
|
|
"state_default": 50,
|
|
|
|
|
|
|
|
"users": userPowerLevels,
|
|
|
|
|
|
|
|
"users_default": 50
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"redact": 50,
|
|
|
|
is_direct: true,
|
|
|
|
"state_default": 50,
|
|
|
|
name: formatPhoneNumber(tel, "(NNN) NNN-NNNN"),
|
|
|
|
"users": userPowerLevels,
|
|
|
|
topic: "SMS conversation with " + formatPhoneNumber(tel, "(NNN) NNN-NNNN") + " (using " + formatPhoneNumber(ournumber, "(NNN) NNN-NNNN") + ")"
|
|
|
|
"users_default": 50
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
is_direct: true,
|
|
|
|
|
|
|
|
name: formatPhoneNumber(tel, "(NNN) NNN-NNNN"),
|
|
|
|
|
|
|
|
topic: "SMS conversation with " + formatPhoneNumber(tel, "(NNN) NNN-NNNN") + " (using " + formatPhoneNumber(ournumber, "(NNN) NNN-NNNN") + ")"
|
|
|
|
|
|
|
|
}).then((room) => {
|
|
|
|
|
|
|
|
logger.debug("Room" + roomName + " created with ID " + room.room_id);
|
|
|
|
logger.debug("Room" + roomName + " created with ID " + room.room_id);
|
|
|
|
// The first message or two we send doesn't go through unless we do this.
|
|
|
|
// 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.
|
|
|
|
// It just spits out "Error sending event M_FORBIDDEN: Unknown room" instead.
|
|
|
|
createOrJoinSMSRoom(tel, ournumber, callback);
|
|
|
|
createOrJoinSMSRoom(tel, ournumber, callback);
|
|
|
|
}).catch((err) => {
|
|
|
|
} catch (errr) {
|
|
|
|
logger.error("Could not create " + roomName + ".");
|
|
|
|
logger.error("Could not create " + roomName + ".");
|
|
|
|
logger.error(err);
|
|
|
|
logger.error(errr);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function getAndUploadFile(url, callback) {
|
|
|
|
function getAndUploadFile(url, callback) {
|
|
|
@ -229,16 +254,24 @@ function getAndUploadFile(url, callback) {
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Send a message to a Matrix room.
|
|
|
|
* Send a message to a Matrix room.
|
|
|
|
* @param {string} roomid the room to post the message in.
|
|
|
|
* @param {string} room the room to post the message in.
|
|
|
|
* @param {string} body message content.
|
|
|
|
* @param {string} body message content.
|
|
|
|
* @param {array} media Array of media URLs to download via HTTP(s) and send to Matrix.
|
|
|
|
* @param {array} media Array of media URLs to download via HTTP(s) and send to Matrix.
|
|
|
|
* @param {function|undefined} callback passes true when successful, false on failure.
|
|
|
|
|
|
|
|
* @returns {undefined}
|
|
|
|
* @returns {undefined}
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
function sendMatrix(roomid, body, media, callback) {
|
|
|
|
async function sendMatrix(room, body, media) {
|
|
|
|
|
|
|
|
var roomid = room;
|
|
|
|
|
|
|
|
if (room.startsWith("#")) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
roomid = (await getRoomIDFromAlias()).room_id;
|
|
|
|
|
|
|
|
logger.info("Translated alias " + room + " to room ID " + roomid);
|
|
|
|
|
|
|
|
} catch (err) {
|
|
|
|
|
|
|
|
logger.error(err);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
if (Array.isArray(media)) {
|
|
|
|
if (Array.isArray(media)) {
|
|
|
|
for (var i = 0; i < media.length; i++) {
|
|
|
|
for (var i = 0; i < media.length; i++) {
|
|
|
|
getAndUploadFile(media[i], function (uri, mimetype) {
|
|
|
|
getAndUploadFile(media[i], async function (uri, mimetype) {
|
|
|
|
if (mimetype == "image/jpg" || mimetype == "image/jpeg" || mimetype == "image/png" || mimetype == "image/gif") {
|
|
|
|
if (mimetype == "image/jpg" || mimetype == "image/jpeg" || mimetype == "image/png" || mimetype == "image/gif") {
|
|
|
|
var content = {
|
|
|
|
var content = {
|
|
|
|
body: "Image",
|
|
|
|
body: "Image",
|
|
|
@ -258,13 +291,16 @@ function sendMatrix(roomid, body, media, callback) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
client.sendEvent(roomid, "m.room.message", content, "").then((res) => {
|
|
|
|
|
|
|
|
}).catch((err) => {
|
|
|
|
try {
|
|
|
|
|
|
|
|
await client.sendEvent(roomid, "m.room.message", content, "");
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
} catch (err) {
|
|
|
|
if (err.data.error == "Unknown room") {
|
|
|
|
if (err.data.error == "Unknown room") {
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
logger.error(err);
|
|
|
|
logger.error(err);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -274,23 +310,17 @@ function sendMatrix(roomid, body, media, callback) {
|
|
|
|
body: body,
|
|
|
|
body: body,
|
|
|
|
msgtype: "m.text"
|
|
|
|
msgtype: "m.text"
|
|
|
|
};
|
|
|
|
};
|
|
|
|
client.sendEvent(roomid, "m.room.message", content, "").then((res) => {
|
|
|
|
try {
|
|
|
|
if (typeof callback == "function") {
|
|
|
|
await client.sendEvent(roomid, "m.room.message", content, "");
|
|
|
|
callback(true);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
}).catch((err) => {
|
|
|
|
|
|
|
|
if (typeof callback == "function") {
|
|
|
|
|
|
|
|
callback(false);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err.data.error == "Unknown room") {
|
|
|
|
if (err.data.error == "Unknown room") {
|
|
|
|
return;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
logger.error(err);
|
|
|
|
logger.error(err);
|
|
|
|
});
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
if (typeof callback == "function") {
|
|
|
|
|
|
|
|
callback(true);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -448,6 +478,7 @@ function handleHTTPRequest(req, res) {
|
|
|
|
if (settings.smsonlyto.length > 0 && settings.smsonlyto.indexOf(msg.to) != -1) {
|
|
|
|
if (settings.smsonlyto.length > 0 && settings.smsonlyto.indexOf(msg.to) != -1) {
|
|
|
|
logger.info("Received SMS from " + msg.from + " for " + msg.to + ": " + msg.body);
|
|
|
|
logger.info("Received SMS from " + msg.from + " for " + msg.to + ": " + msg.body);
|
|
|
|
createOrJoinSMSRoom(msg.from, msg.to, function (roomid) {
|
|
|
|
createOrJoinSMSRoom(msg.from, msg.to, function (roomid) {
|
|
|
|
|
|
|
|
logger.info("Sending to room " + roomid);
|
|
|
|
sendMatrix(roomid, msg.body, msg.media);
|
|
|
|
sendMatrix(roomid, msg.body, msg.media);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
res.sendStatus(204);
|
|
|
|
res.sendStatus(204);
|
|
|
@ -520,7 +551,7 @@ if (settings.matrixaccesstoken == false) {
|
|
|
|
client.startClient({initialSyncLimit: 10});
|
|
|
|
client.startClient({initialSyncLimit: 10});
|
|
|
|
logger.info("Plugged into the matrix.");
|
|
|
|
logger.info("Plugged into the matrix.");
|
|
|
|
|
|
|
|
|
|
|
|
client.once('sync', function (state, prevState, res) {
|
|
|
|
client.once("sync", function (state, prevState, res) {
|
|
|
|
logger.debug("Initial sync complete (" + state + ")");
|
|
|
|
logger.debug("Initial sync complete (" + state + ")");
|
|
|
|
initialsynccomplete = true;
|
|
|
|
initialsynccomplete = true;
|
|
|
|
httpserver.post("*", jsonParser, (req, res) => {
|
|
|
|
httpserver.post("*", jsonParser, (req, res) => {
|
|
|
@ -630,7 +661,6 @@ if (settings.matrixaccesstoken == false) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var matches = room.name.match(/SMS_([1-9][0-9]+)(?:_([1-9][0-9]+))?/g);
|
|
|
|
var matches = room.name.match(/SMS_([1-9][0-9]+)(?:_([1-9][0-9]+))?/g);
|
|
|
|
console.log(event.getRoomId());
|
|
|
|
|
|
|
|
if (matches == null || (matches.length != 1 && matches.length != 2)) {
|
|
|
|
if (matches == null || (matches.length != 1 && matches.length != 2)) {
|
|
|
|
client.getRoomTags(event.getRoomId()).then((response) => {
|
|
|
|
client.getRoomTags(event.getRoomId()).then((response) => {
|
|
|
|
console.log(response);
|
|
|
|
console.log(response);
|
|
|
|