From 00c26eef866507190deb4db838c930026e567c08 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 3 Dec 2017 11:29:32 +0200 Subject: [PATCH] Add supergroup upgrade handling and experimental updatesTooLong handling --- README.md | 2 +- src/portal.js | 26 ++++++++++++++++++++++++-- src/telegram-peer.js | 27 +++++++++++++++++++++++++++ src/telegram-puppet.js | 33 +++++++++++++++++++++++++++++---- src/telegram-user.js | 14 ++++++++++++++ 5 files changed, 95 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 171da96e..6879aa1f 100644 --- a/README.md +++ b/README.md @@ -94,5 +94,5 @@ does not do this automatically. * [ ] Creating Telegram chats for existing Matrix rooms * Misc * [ ] Use optional bot to relay messages for unauthenticated Matrix users - * [ ] Properly handle upgrading groups to supergroups + * [x] Properly handle upgrading groups to supergroups * [ ] Handle public channel username changes diff --git a/src/portal.js b/src/portal.js index 4a1838fe..dea3384d 100644 --- a/src/portal.js +++ b/src/portal.js @@ -221,10 +221,19 @@ class Portal { * MessageAction} object. */ async handleTelegramServiceMessage(evt) { + if (!this.isMatrixRoomCreated()) { + if (evt.action._ === "messageActionChatDeleteUser") { + // We don't care about user deletions on chats without portals + return + } + console.log("Service message received, creating room for", evt.to.id) + await this.createMatrixRoom(evt.source, { invite: [evt.source.matrixUser.userID] }) + return + } let matrixUser, telegramUser switch (evt.action._) { case "messageActionChatCreate": - await this.createMatrixRoom(evt.source, { invite: [evt.source.matrixUser.userID] }) + // Portal gets created at beginning if it doesn't exist // Falls through to invite everyone in initial user list case "messageActionChatAddUser": for (const userID of evt.action.users) { @@ -238,8 +247,21 @@ class Portal { } break case "messageActionChannelCreate": + // Portal gets created at beginning if it doesn't exist // Channels don't send initial user lists 3:< - await this.createMatrixRoom(evt.source, { invite: [evt.source.matrixUser.userID] }) + break + case "messageActionChatMigrateTo": + this.peer.id = evt.action.channel_id + this.peer.type = "channel" + const accessHash = await this.peer.fetchAccessHashFromServer(evt.source) + if (!accessHash) { + console.error("Failed to fetch access hash for mirgrated channel!") + break + } + this.accessHashes.set(evt.source.userID, accessHash) + await this.save() + const sender = await this.app.getTelegramUser(evt.from) + await sender.sendEmote(this.roomID, "upgraded this group to a supergroup.") break case "messageActionChatDeleteUser": matrixUser = await this.app.getMatrixUserByTelegramID(evt.action.user_id) diff --git a/src/telegram-peer.js b/src/telegram-peer.js index 96032be0..c5efa2ed 100644 --- a/src/telegram-peer.js +++ b/src/telegram-peer.js @@ -108,6 +108,33 @@ class TelegramPeer { return changed } + async fetchAccessHashFromServer(telegramPOV) { + const data = await this.getInfoFromDialogs(telegramPOV) + if (!data) { + return undefined + } + this.accessHash = data.access_hash + return this.accessHash + } + + async getInfoFromDialogs(telegramPOV) { + const dialogs = await telegramPOV.client("messages.getDialogs", {}) + if (this.type === "user") { + for (const user of dialogs.users) { + if (user.id === this.id) { + return user + } + } + } else { + for (const chat of dialogs.chats) { + if (chat.id === this.id) { + return chat + } + } + } + return undefined + } + /** * Get info about this peer from the Telegram servers. * diff --git a/src/telegram-puppet.js b/src/telegram-puppet.js index 46631e57..fd4788c2 100644 --- a/src/telegram-puppet.js +++ b/src/telegram-puppet.js @@ -96,6 +96,9 @@ class TelegramPuppet { this.apiHash = api_hash this.apiID = api_id + this.pts = 0 + this.date = 0 + this.puppetStorage = { get: async (key) => { let value = this.data[key] @@ -108,7 +111,6 @@ class TelegramPuppet { if (Array.isArray(value)) { value = `b64:${Buffer.from(value).toString("base64")}` } - console.warn("SET", key, "=", JSON.stringify(value)) if (this.data[key] === value) { return } @@ -117,12 +119,10 @@ class TelegramPuppet { await this.matrixUser.save() }, remove: async (...keys) => { - console.warn("DEL", JSON.stringify(keys)) keys.forEach((key) => delete this.data[key]) await this.matrixUser.save() }, clear: async () => { - console.warn("CLR") this.data = {} await this.matrixUser.save() }, @@ -322,19 +322,32 @@ class TelegramPuppet { // TODO figure out how channel message signing works from = -1 case "updateNewMessage": + this.pts = update.pts update = update.message // Message defined at message#90dddc11 in layer 71 from = update.from_id || from to = TelegramPeer.fromTelegramData(update.to_id, update.from_id, this.userID) break + case "updateReadMessages": + case "updateDeleteMessages": + case "updateRestoreMessages": + this.pts = update.pts + break default: // Unknown update type console.log(`Update of unknown type ${update._} received:\n${JSON.stringify(update, "", " ")}`) return } + if (!to) { + // This shouldn't happen + console.warn("No target found for update", update) + return + } + if (update._ === "messageService" && update.action._ === "messageActionChannelMigrateFrom") { + return + } portal = await this.app.getPortalByPeer(to) - if (update._ === "messageService") { await portal.handleTelegramServiceMessage({ from, @@ -344,6 +357,7 @@ class TelegramPuppet { }) return } + console.log(update) await portal.handleTelegramMessage({ from, to, @@ -369,9 +383,11 @@ class TelegramPuppet { try { switch (data._) { case "updateShort": + this.date = data.date this.onUpdate(data.update) break case "updates": + this.date = data.date for (const update of data.updates) { this.onUpdate(update) } @@ -380,6 +396,15 @@ class TelegramPuppet { case "updateShortChatMessage": this.onUpdate(data) break + case "updatesTooLong": + console.log("Handling updatesTooLong") + this.client("updates.getDifference", { + pts: this.pts, + date: this.date, + qts: -1, + }).then(dat => console.log("getDifference", dat), + err => console.error("getDifferenceFail", err)) + break default: console.log("Unrecognized update type:", data._) } diff --git a/src/telegram-user.js b/src/telegram-user.js index 6969f962..22ed87de 100644 --- a/src/telegram-user.js +++ b/src/telegram-user.js @@ -153,6 +153,20 @@ class TelegramUser { }) } + sendNotice(roomID, text) { + return this.intent.sendMessage(roomID, { + msgtype: "m.notice", + body: text, + }) + } + + sendEmote(roomID, text) { + return this.intent.sendMessage(roomID, { + msgtype: "m.emote", + body: text, + }) + } + sendText(roomID, text) { return this.intent.sendText(roomID, text) }