From caaffde231b925bd5e71712ba6bc5e4d3ec2ef7d Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 25 Nov 2017 16:01:27 +0200 Subject: [PATCH] Fix bugs and #12 --- src/app.js | 82 ++++++++++++++++++++++++------------------ src/commands.js | 30 ++++++++++------ src/telegram-puppet.js | 3 +- src/telegram-user.js | 11 +++--- 4 files changed, 74 insertions(+), 52 deletions(-) diff --git a/src/app.js b/src/app.js index 5ba2d1e6..3559056c 100644 --- a/src/app.js +++ b/src/app.js @@ -38,6 +38,7 @@ class MautrixTelegram { this.telegramUsersByID = new Map() this.portalsByPeerID = new Map() this.portalsByRoomID = new Map() + this.managementRooms = [] const self = this this.bridge = new Bridge({ @@ -304,45 +305,69 @@ class MautrixTelegram { }, entry) } + async getRoomMembers(roomID) { + const roomState = await this.botIntent.roomState(roomID) + const members = [] + for (const event of roomState) { + if (event.type === "m.room.member" && event.membership === "join") { + members.push(event.user_id) + } + } + return members + } + /** * Handle a single received Matrix event. * * @param evt The Matrix event that occurred. */ async handleMatrixEvent(evt) { - const asBotID = this.bridge.getBot() - .getUserId() - if (evt.type === "m.room.member" && evt.state_key === asBotID) { - if (evt.content.membership === "invite") { - // Accept all invites - this.botIntent.join(evt.room_id) - .catch(err => { - console.warn(`Failed to join room ${evt.room_id}:`, err) - if (err instanceof Error) { - console.warn(err.stack) - } - }) + const user = await this.getMatrixUser(evt.sender) + if (!user.whitelisted) { + return + } + + 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) + } } return } + // TODO to handle joining telegram groups and initiating private chats, we need to handle room member events. if (evt.sender === asBotID || evt.type !== "m.room.message" || !evt.content) { // Ignore own messages and non-message events. return } - const user = await this.getMatrixUser(evt.sender) + const portal = await this.getPortalByRoomID(evt.room_id) + if (portal) { + portal.handleMatrixEvent(user, evt) + return + } - const cmdprefix = this.config.bridge.commands.prefix - if (evt.content.body.startsWith(`${cmdprefix} `)) { - if (!user.whitelisted) { - this.botIntent.sendText(evt.room_id, "You are not authorized to use this bridge.") - return + let isManagement = this.managementRooms.includes(evt.room_id) + if (!isManagement) { + const roomMembers = await this.getRoomMembers(evt.room_id) + if (roomMembers.length === 2 && roomMembers.includes(asBotID)) { + this.managementRooms.push(evt.room_id) + isManagement = true } - + } + const cmdprefix = this.config.bridge.commands.prefix + if (isManagement || evt.content.body.startsWith(`${cmdprefix} `)) { const prefixLength = cmdprefix.length + 1 - const args = evt.content.body.substr(prefixLength) - .split(" ") + if (evt.content.body.startsWith(`${cmdprefix} `)) { + evt.content.body = evt.content.body.substr(prefixLength) + } + const args = evt.content.body.split(" ") const command = args.shift() const replyFunc = (reply, { allowHTML = false, markdown = true } = {}) => { reply = reply.replace("$cmdprefix", cmdprefix) @@ -351,7 +376,7 @@ class MautrixTelegram { } if (markdown) { reply = marked(reply, { - sanitize: allowHTML, + sanitize: !allowHTML, }) } this.botIntent.sendMessage( @@ -362,18 +387,7 @@ class MautrixTelegram { format: "org.matrix.custom.html", }) } - commands.run(user, command, args, replyFunc, this) - return - } - - if (!user.whitelisted) { - // Non-management command from non-whitelisted user -> fail silently. - return - } - - const portal = await this.getPortalByRoomID(evt.room_id) - if (portal) { - portal.handleMatrixEvent(user, evt) + commands.run(user, command, args, replyFunc, this, evt) } } diff --git a/src/commands.js b/src/commands.js index 6f81974a..8191ddc7 100644 --- a/src/commands.js +++ b/src/commands.js @@ -17,7 +17,7 @@ const makePasswordHash = require("telegram-mtproto").plugins.makePasswordHash const commands = {} -function run(sender, command, args, reply, app) { +function run(sender, command, args, reply, app, evt) { const commandFunc = this.commands[command] if (!commandFunc) { if (sender.commandStatus) { @@ -27,13 +27,13 @@ function run(sender, command, args, reply, app) { return undefined } args.unshift(command) - return sender.commandStatus.next(sender, args, reply, app) + return sender.commandStatus.next(sender, args, reply, app, evt) } reply("Unknown command. Try `$cmdprefix help` for help.") return undefined } try { - return commandFunc(sender, args, reply, app) + return commandFunc(sender, args, reply, app, evt) } catch (err) { reply(`Error running command: ${err}.`) if (err instanceof Error) { @@ -46,17 +46,28 @@ function run(sender, command, args, reply, app) { commands.cancel = () => "Nothing to cancel." -commands.help = (sender, args, reply) => { - reply(`All commands are prefixed with **$cmdprefix**. - +commands.help = (sender, args, reply, app, evt) => { + let replyMsg = "" + if (app.managementRooms.includes(evt.room_id)) { + replyMsg += "This is a management room: prefixing commands with `$cmdprefix` is not required.\n" + } else { + replyMsg += "This is not a management room: you must prefix commands with `$cmdprefix`.\n" + } + replyMsg += ` **help** - Show this help message.
**cancel** - Cancel an ongoing action (such as login). -**login** <_phone_> - Request an authentication code.
+**login** <_phone_> - Request an authentication code.
**logout** - Log out from Telegram. Currently broken. -**api** <_method_> <_args_> - Call a Telegram API method. Args is always a JSON object. Disabled by default. -`, { allowHTML: true }) +**api** <_method_> <_args_> - Call a Telegram API method. Args is always a JSON object. Disabled by default. +` + reply(replyMsg, { allowHTML: true }) +} + +commands.setManagement = async (sender, _, reply, app, evt) => { + app.managementRooms.push(evt.room_id) + reply("Room marked as management room. You can now run commands without the `$cmdprefix` prefix.") } @@ -233,7 +244,6 @@ commands.pm = async (sender, args, reply, app) => { }) } - //////////////////////////// // Debug command handlers // //////////////////////////// diff --git a/src/telegram-puppet.js b/src/telegram-puppet.js index bbd5a951..96e2689e 100644 --- a/src/telegram-puppet.js +++ b/src/telegram-puppet.js @@ -179,8 +179,7 @@ class TelegramPuppet { getDisplayName() { if (this.data.firstName || this.data.lastName) { - return [this.data.firstName, this.data.lastName].filter(s => !!s) - .join(" ") + return [this.data.firstName, this.data.lastName].filter(s => !!s).join(" ") } else if (this.data.username) { return this.data.username } diff --git a/src/telegram-user.js b/src/telegram-user.js index c2d97b87..5dad0e6d 100644 --- a/src/telegram-user.js +++ b/src/telegram-user.js @@ -72,19 +72,19 @@ class TelegramUser { async updateInfo(telegramPOV, user, { updateAvatar = false } = {}) { let changed = false - if (this.firstName !== user.first_name) { + if (user.first_name && this.firstName !== user.first_name) { this.firstName = user.first_name changed = true } - if (this.lastName !== user.last_name) { + if (user.last_name && this.lastName !== user.last_name) { this.lastName = user.last_name changed = true } - if (this.username !== user.username) { + if (user.username && this.username !== user.username) { this.username = user.username changed = true } - if (telegramPOV && this.accessHashes.get(telegramPOV.userID) !== user.access_hash) { + if (user.access_hash && telegramPOV && this.accessHashes.get(telegramPOV.userID) !== user.access_hash) { this.accessHashes.set(telegramPOV.userID, user.access_hash) changed = true } @@ -116,8 +116,7 @@ class TelegramUser { } getFirstAndLastName() { - return [this.firstName, this.lastName].filter(s => !!s) - .join(" ") + return [this.firstName, this.lastName].filter(s => !!s).join(" ") } getDisplayName() {