Allow starting private chats by inviting Telegram user. Fixes #13

This commit is contained in:
Tulir Asokan
2017-11-26 14:40:11 +02:00
parent 02ab9bb6df
commit 84d92cab25
2 changed files with 97 additions and 15 deletions
+2 -1
View File
@@ -168,6 +168,7 @@
"no-bitwise": "off",
"no-case-declarations": "off",
"no-template-curly-in-string": "off",
"no-await-in-loop": "off"
"no-await-in-loop": "off",
"no-restricted-globals": "off"
}
}
+95 -14
View File
@@ -64,6 +64,13 @@ class MautrixTelegram {
*/
this.managementRooms = []
this.usernameRegex = new RegExp(
`^@${
this.config.bridge.username_template.replace("${ID}", "([0-9]+)")
}:${
this.config.homeserver.domain
}$`)
const self = this
/**
* The matrix-appservice-bridge Bridge instance.
@@ -354,11 +361,13 @@ class MautrixTelegram {
/**
* Get the members in the given room.
* @param {string} roomID The ID of the room to search.
* @returns {Array} The list of MXIDs who are in the room.
*
* @param {string} roomID The ID of the room to search.
* @param {Intent} [intent] The Intent object to use when reading the room state.
* @returns {Array} The list of MXIDs who are in the room.
*/
async getRoomMembers(roomID) {
const roomState = await this.botIntent.roomState(roomID)
async getRoomMembers(roomID, intent = this.botIntent) {
const roomState = await intent.roomState(roomID)
const members = []
for (const event of roomState) {
if (event.type === "m.room.member" && event.membership === "join") {
@@ -368,6 +377,86 @@ class MautrixTelegram {
return members
}
async handleInvite(sender, evt) {
console.log(evt)
const asBotID = this.bridge.getBot().getUserId()
if (evt.state_key === asBotID) {
// Accept all AS bot invites.
try {
await this.botIntent.join(evt.room_id)
} catch (err) {
console.error(`Failed to join room ${evt.room_id}:`, err)
if (err instanceof Error) {
console.error(err.stack)
}
}
return
}
// Check if the invited user is a Telegram user.
const capture = this.usernameRegex.exec(evt.state_key)
console.log(capture)
if (!capture) {
return
}
const telegramID = +capture[1]
console.log(telegramID)
if (!telegramID || isNaN(telegramID)) {
return
}
const intent = this.getIntentForTelegramUser(telegramID)
try {
await intent.join(evt.room_id)
const members = await this.getRoomMembers(evt.room_id, intent)
if (members.length < 2) {
console.warn(`No members in room ${evt.room_id}`)
await intent.leave(evt.room_id)
} else if (members.length === 2) {
const user = await this.getTelegramUser(telegramID)
const peer = user.toPeer(sender.telegramPuppet)
const portal = await this.getPortalByPeer(peer)
if (portal.roomID) {
await intent.sendMessage(evt.room_id, {
msgtype: "m.notice",
body: "You already have a private chat room with me!\nI'll re-invite you to that room.",
})
try {
await intent.invite(portal.roomID, sender.userID)
} catch (_) {}
await intent.leave(evt.room_id)
} else {
portal.roomID = evt.room_id
await portal.save()
await intent.sendMessage(portal.roomID, {
msgtype: "m.notice",
body: "Portal to Telegram private chat created.",
})
}
} else {
if (!members.includes(asBotID)) {
await intent.sendMessage(evt.room_id, {
msgtype: "m.notice",
body: "Inviting additional Telegram users to private chats or non-portal rooms is not supported.",
})
} else {
// TODO Allow inviting Telegram users to group/channel portal rooms.
await intent.sendMessage(evt.room_id, {
msgtype: "m.notice",
body: "Inviting Telegram users to portal rooms is not (yet) supported.",
})
}
await intent.leave(evt.room_id)
}
} catch (err) {
console.error(`Failed to process invite to room ${evt.room_id} for Telegram user ${telegramID}: ${err}`)
if (err instanceof Error) {
console.error(err.stack)
}
}
}
/**
* Handle a single received Matrix event.
*
@@ -380,16 +469,8 @@ class MautrixTelegram {
}
const asBotID = this.bridge.getBot().getUserId()
if (evt.type === "m.room.member" && evt.state_key === asBotID && evt.content.membership === "invite") {
// Accept all invites
try {
await this.botIntent.join(evt.room_id)
} catch (err) {
console.error(`Failed to join room ${evt.room_id}:`, err)
if (err instanceof Error) {
console.error(err.stack)
}
}
if (evt.type === "m.room.member" && evt.content.membership === "invite") {
await this.handleInvite(user, evt)
return
}