Format and maybe break code

This commit is contained in:
Tulir Asokan
2017-11-21 14:30:59 +02:00
parent 5ef0a202a2
commit 674ea9eab4
9 changed files with 275 additions and 264 deletions
+27 -10
View File
@@ -1,6 +1,5 @@
{ {
"env": { "env": {
"browser": false,
"node": true, "node": true,
"es6": true "es6": true
}, },
@@ -36,7 +35,6 @@
"object-curly-newline": [ "object-curly-newline": [
"error", "error",
{ {
"minProperties": 5,
"consistent": true "consistent": true
} }
], ],
@@ -65,17 +63,29 @@
], ],
"max-len": [ "max-len": [
"warn", "warn",
80 120
], ],
"camelcase": [ "no-underscore-dangle": [
"error", "error",
{ {
"properties": "always" "allowAfterThis": true
}
],
"no-unused-vars": [
"error",
{
"vars": "all",
"args": "after-used",
"varsIgnorePattern": "_"
} }
], ],
"space-before-function-paren": [ "space-before-function-paren": [
"error", "error",
"never" {
"anonymous": "never",
"named": "never",
"asyncArrow": "always"
}
], ],
"func-style": [ "func-style": [
"warn", "warn",
@@ -92,11 +102,11 @@
"i", "i",
"x", "x",
"y", "y",
"$" "$",
"_"
] ]
} }
], ],
"import/no-nodejs-modules": "error",
"import/order": [ "import/order": [
"warn", "warn",
{ {
@@ -123,7 +133,8 @@
"warn", "warn",
{ {
"newIsCap": true, "newIsCap": true,
"capIsNew": true "capIsNew": true,
"capIsNewExceptions": ["MTProto"]
} }
], ],
"no-empty": [ "no-empty": [
@@ -151,6 +162,12 @@
"no-prototype-builtins": "off", "no-prototype-builtins": "off",
"no-console": "off", "no-console": "off",
"class-methods-use-this": "off", "class-methods-use-this": "off",
"prefer-destructuring": "off" "prefer-destructuring": "off",
"camelcase": "off",
"spaced-comment": "off",
"no-bitwise": "off",
"no-case-declarations": "off",
"no-template-curly-in-string": "off",
"no-await-in-loop": "off"
} }
} }
+46 -58
View File
@@ -13,9 +13,7 @@
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
const {Bridge} = require("matrix-appservice-bridge") const { Bridge } = require("matrix-appservice-bridge")
const crypto = require("crypto")
const YAML = require("yamljs")
const commands = require("./commands") const commands = require("./commands")
const MatrixUser = require("./matrix-user") const MatrixUser = require("./matrix-user")
const TelegramUser = require("./telegram-user") const TelegramUser = require("./telegram-user")
@@ -54,9 +52,10 @@ class MautrixTelegram {
async run() { async run() {
console.log("Appservice listening on port %s", this.config.appservice.port) console.log("Appservice listening on port %s", this.config.appservice.port)
await this.bridge.run(this.config.appservice.port, {}) await this.bridge.run(this.config.appservice.port, {})
const userEntries = await this.bridge.getUserStore().select({ const userEntries = await this.bridge.getUserStore()
type: "matrix", .select({
}) type: "matrix",
})
for (const entry of userEntries) { for (const entry of userEntries) {
const user = MatrixUser.fromEntry(this, entry) const user = MatrixUser.fromEntry(this, entry)
this.matrixUsersByID.set(entry.id, user) this.matrixUsersByID.set(entry.id, user)
@@ -89,7 +88,8 @@ class MautrixTelegram {
if (peer.type === "user") { if (peer.type === "user") {
query.receiverID = peer.receiverID query.receiverID = peer.receiverID
} }
const entries = await this.bridge.getRoomStore().select(query) const entries = await this.bridge.getRoomStore()
.select(query)
// Handle possible db query race conditions // Handle possible db query race conditions
portal = this.portalsByPeerID.get(peer.id) portal = this.portalsByPeerID.get(peer.id)
@@ -123,10 +123,11 @@ class MautrixTelegram {
} }
} }
const entries = await this.bridge.getRoomStore().select({ const entries = await this.bridge.getRoomStore()
type: "portal", .select({
roomID: id, type: "portal",
}) roomID: id,
})
// Handle possible db query race conditions // Handle possible db query race conditions
portal = this.portalsByRoomID.get(id) portal = this.portalsByRoomID.get(id)
@@ -151,10 +152,11 @@ class MautrixTelegram {
return user return user
} }
const entries = await this.bridge.getUserStore().select({ const entries = await this.bridge.getUserStore()
type: "remote", .select({
id, type: "remote",
}) id,
})
// Handle possible db query race conditions // Handle possible db query race conditions
if (this.telegramUsersByID.has(id)) { if (this.telegramUsersByID.has(id)) {
@@ -176,10 +178,11 @@ class MautrixTelegram {
return user return user
} }
const entries = this.bridge.getUserStore().select({ const entries = this.bridge.getUserStore()
type: "matrix", .select({
id, type: "matrix",
}) id,
})
// Handle possible db query race conditions // Handle possible db query race conditions
if (this.matrixUsersByID.has(id)) { if (this.matrixUsersByID.has(id)) {
@@ -197,30 +200,33 @@ class MautrixTelegram {
putUser(user) { putUser(user) {
const entry = user.toEntry() const entry = user.toEntry()
return this.bridge.getUserStore().upsert({ return this.bridge.getUserStore()
type: entry.type, .upsert({
id: entry.id, type: entry.type,
}, entry) id: entry.id,
}, entry)
} }
putRoom(room) { putRoom(room) {
const entry = room.toEntry() const entry = room.toEntry()
return this.bridge.getRoomStore().upsert({ return this.bridge.getRoomStore()
type: entry.type, .upsert({
id: entry.id, type: entry.type,
}, entry) id: entry.id,
}, entry)
} }
async handleMatrixEvent(evt) { async handleMatrixEvent(evt) {
const asBotID = this.bridge.getBot().getUserId() const asBotID = this.bridge.getBot()
.getUserId()
if (evt.type === "m.room.member" && evt.state_key === asBotID) { if (evt.type === "m.room.member" && evt.state_key === asBotID) {
if (evt.content.membership === "invite") { if (evt.content.membership === "invite") {
// Accept all invites // Accept all invites
this.botIntent.join(evt.room_id) this.botIntent.join(evt.room_id)
.catch(err => { .catch(err => {
console.warn(`Failed to join room ${evt.room_id}:`, err) console.warn(`Failed to join room ${evt.room_id}:`, err)
if (e instanceof Error) { if (err instanceof Error) {
console.warn(e.stack) console.warn(err.stack)
} }
}) })
} }
@@ -229,25 +235,27 @@ class MautrixTelegram {
if (evt.sender === asBotID || evt.type !== "m.room.message" || !evt.content) { if (evt.sender === asBotID || evt.type !== "m.room.message" || !evt.content) {
// Ignore own messages and non-message events. // Ignore own messages and non-message events.
return; return
} }
const user = await this.getMatrixUser(evt.sender) const user = await this.getMatrixUser(evt.sender)
const cmdprefix = this.config.bridge.commands.prefix const cmdprefix = this.config.bridge.commands.prefix
if (evt.content.body.startsWith(cmdprefix + " ")) { if (evt.content.body.startsWith(`${cmdprefix} `)) {
if (!user.whitelisted) { if (!user.whitelisted) {
this.botIntent.sendText(evt.room_id, "You are not authorized to use this bridge.") this.botIntent.sendText(evt.room_id, "You are not authorized to use this bridge.")
return return
} }
const prefixLength = cmdprefix.length + 1 const prefixLength = cmdprefix.length + 1
const args = evt.content.body.substr(prefixLength).split(" ") const args = evt.content.body.substr(prefixLength)
.split(" ")
const command = args.shift() const command = args.shift()
commands.run(user, command, args, reply => commands.run(
this.botIntent.sendText( user, command, args,
evt.room_id, reply => this.botIntent.sendText(
reply.replace("$cmdprefix", cmdprefix)), evt.room_id,
reply.replace("$cmdprefix", cmdprefix)),
this) this)
return return
} }
@@ -260,7 +268,6 @@ class MautrixTelegram {
const portal = await this.getPortalByRoomID(evt.room_id) const portal = await this.getPortalByRoomID(evt.room_id)
if (portal) { if (portal) {
portal.handleMatrixEvent(user, evt) portal.handleMatrixEvent(user, evt)
return
} }
} }
@@ -270,7 +277,7 @@ class MautrixTelegram {
} }
userID = userID.toLowerCase() userID = userID.toLowerCase()
const userIDCapture = /\@.+\:(.+)/.exec(userID) const userIDCapture = /@.+:(.+)/.exec(userID)
const homeserver = userIDCapture && userIDCapture.length > 1 ? userIDCapture[1] : undefined const homeserver = userIDCapture && userIDCapture.length > 1 ? userIDCapture[1] : undefined
for (let whitelisted of this.config.bridge.whitelist) { for (let whitelisted of this.config.bridge.whitelist) {
whitelisted = whitelisted.toLowerCase() whitelisted = whitelisted.toLowerCase()
@@ -280,25 +287,6 @@ class MautrixTelegram {
} }
return false return false
} }
/*encrypt(value) {
var cipher = crypto.createCipher("aes-256-gcm", this.config.bridge.auth_key_password);
var ret = cipher.update(Buffer.from(value), "hex", "base64");
ret += cipher.final("base64");
return [ret, cipher.getAuthTag().toString("base64")];
}
decrypt(value) {
if(!value) return value;
var decipher = crypto.createDecipher("aes-256-gcm", this.config.bridge.auth_key_password);
decipher.setAuthTag(new Buffer(value[1], "base64"));
var ret = decipher.update(value[0], "base64", "hex");
ret += decipher.final("hex");
return ret;
};*/
} }
module.exports = MautrixTelegram module.exports = MautrixTelegram
+13 -11
View File
@@ -24,13 +24,13 @@ function run(sender, command, args, reply, app) {
if (command === "cancel") { if (command === "cancel") {
reply(`${sender.commandStatus.action} cancelled.`) reply(`${sender.commandStatus.action} cancelled.`)
sender.commandStatus = undefined sender.commandStatus = undefined
return return undefined
} }
args.unshift(command) args.unshift(command)
return sender.commandStatus.next(sender, args, reply, app) return sender.commandStatus.next(sender, args, reply, app)
} }
reply("Unknown command. Try \"$cmdprefix help\" for help.") reply("Unknown command. Try \"$cmdprefix help\" for help.")
return return undefined
} }
return commandFunc(sender, args, reply, app) return commandFunc(sender, args, reply, app)
} }
@@ -49,8 +49,8 @@ api <method> <args> - Call a Telegram API method. Args is always a JSON object.
} }
///////////////////////////// /////////////////////////////
// Authentication handlers // // Authentication handlers //
///////////////////////////// /////////////////////////////
/** /**
@@ -88,7 +88,8 @@ commands.enterCode = async (sender, args, reply) => {
reply(`Logged in successfully as @${sender.telegramPuppet.getDisplayName()}.`) reply(`Logged in successfully as @${sender.telegramPuppet.getDisplayName()}.`)
sender.commandStatus = undefined sender.commandStatus = undefined
} else if (data.status === "need-password") { } else if (data.status === "need-password") {
reply(`You have two-factor authentication enabled. Password hint: ${data.hint}\nEnter your password using "$cmdprefix <password>"`) reply(`You have two-factor authentication enabled. Password hint: ${data.hint}
Enter your password using "$cmdprefix <password>"`)
sender.commandStatus = { sender.commandStatus = {
action: "Two-factor authentication", action: "Two-factor authentication",
next: commands.enterPassword, next: commands.enterPassword,
@@ -114,11 +115,12 @@ commands.login = async (sender, args, reply) => {
} }
try { try {
const data = await sender.sendTelegramCode(args[0]) /*const data = */
await sender.sendTelegramCode(args[0])
reply(`Login code sent to ${args[0]}.\nEnter the code using "$cmdprefix <code>"`) reply(`Login code sent to ${args[0]}.\nEnter the code using "$cmdprefix <code>"`)
sender.commandStatus = { sender.commandStatus = {
action: "Phone code authentication", action: "Phone code authentication",
next: commands.enterCode , next: commands.enterCode,
} }
} catch (err) { } catch (err) {
reply(`Failed to send code: ${err}`) reply(`Failed to send code: ${err}`)
@@ -139,13 +141,13 @@ commands.logout = async (sender, args, reply) => {
} }
} }
////////////////////////////// //////////////////////////////
// General command handlers // // General command handlers //
////////////////////////////// //////////////////////////////
//////////////////////////// ////////////////////////////
// Debug command handlers // // Debug command handlers //
//////////////////////////// ////////////////////////////
commands.api = async (sender, args, reply, app) => { commands.api = async (sender, args, reply, app) => {
+3 -3
View File
@@ -14,7 +14,7 @@
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
const {AppServiceRegistration} = require("matrix-appservice-bridge") const { AppServiceRegistration } = require("matrix-appservice-bridge")
const commander = require("commander") const commander = require("commander")
const YAML = require("yamljs") const YAML = require("yamljs")
const fs = require("fs") const fs = require("fs")
@@ -41,11 +41,11 @@ if (commander.generateRegistration) {
namespaces: { namespaces: {
users: [{ users: [{
exclusive: true, exclusive: true,
regex: `@${config.bridge.username_template.replace("${ID}", ".+")}:${config.homeserver.domain}` regex: `@${config.bridge.username_template.replace("${ID}", ".+")}:${config.homeserver.domain}`,
}], }],
aliases: [{ aliases: [{
exclusive: true, exclusive: true,
regex: `#${config.bridge.alias_template.replace("${NAME}", ".+")}:${config.homeserver.domain}` regex: `#${config.bridge.alias_template.replace("${NAME}", ".+")}:${config.homeserver.domain}`,
}], }],
rooms: [], rooms: [],
}, },
+11 -10
View File
@@ -97,7 +97,7 @@ class MatrixUser {
async syncContacts() { async syncContacts() {
const contacts = await this.telegramPuppet.client("contacts.getContacts", { const contacts = await this.telegramPuppet.client("contacts.getContacts", {
hash: md5(this.contactIDs.join(",")) hash: md5(this.contactIDs.join(",")),
}) })
if (contacts._ === "contacts.contactsNotModified") { if (contacts._ === "contacts.contactsNotModified") {
return false return false
@@ -112,7 +112,7 @@ class MatrixUser {
return true return true
} }
async syncDialogs({createRooms=true} = {}) { async syncDialogs({ createRooms = true } = {}) {
const dialogs = await this.telegramPuppet.client("messages.getDialogs", {}) const dialogs = await this.telegramPuppet.client("messages.getDialogs", {})
let changed = false let changed = false
for (const dialog of dialogs.chats.concat(dialogs.users)) { for (const dialog of dialogs.chats.concat(dialogs.users)) {
@@ -122,7 +122,7 @@ class MatrixUser {
const peer = new TelegramPeer(dialog._, dialog.id, { const peer = new TelegramPeer(dialog._, dialog.id, {
receiverID: dialog._ === "user" receiverID: dialog._ === "user"
? this.telegramPuppet.userID ? this.telegramPuppet.userID
: undefined : undefined,
}) })
const portal = await this.app.getPortalByPeer(peer) const portal = await this.app.getPortalByPeer(peer)
if (await portal.updateInfo(this.telegramPuppet, dialog)) { if (await portal.updateInfo(this.telegramPuppet, dialog)) {
@@ -130,7 +130,7 @@ class MatrixUser {
} }
if (createRooms) { if (createRooms) {
try { try {
const {roomID, created} = await portal.createMatrixRoom(this.telegramPuppet, { const { roomID, created } = await portal.createMatrixRoom(this.telegramPuppet, {
invite: [this.userID], invite: [this.userID],
}) })
if (!created) { if (!created) {
@@ -143,7 +143,8 @@ class MatrixUser {
//if (membership !== "join") { //if (membership !== "join") {
try { try {
await intent.invite(roomID, this.userID) await intent.invite(roomID, this.userID)
} catch (_) {} } catch (_) {
}
//} //}
} }
} catch (err) { } catch (err) {
@@ -159,11 +160,11 @@ class MatrixUser {
if (this._telegramPuppet && this._telegramPuppet.userID) { if (this._telegramPuppet && this._telegramPuppet.userID) {
throw new Error("You are already logged in. Please log out before logging in again.") throw new Error("You are already logged in. Please log out before logging in again.")
} }
switch(this.telegramPuppet.checkPhone(phoneNumber)) { switch (this.telegramPuppet.checkPhone(phoneNumber)) {
case "unregistered": case "unregistered":
throw new Error("That number has not been registered. Please register it first.") throw new Error("That number has not been registered. Please register it first.")
case "invalid": case "invalid":
throw new Error("Invalid phone number.") throw new Error("Invalid phone number.")
} }
try { try {
const result = await this.telegramPuppet.sendCode(phoneNumber) const result = await this.telegramPuppet.sendCode(phoneNumber)
+10 -10
View File
@@ -79,8 +79,8 @@ class Portal {
const uploaded = await this.app.botIntent.getClient() const uploaded = await this.app.botIntent.getClient()
.uploadContent({ .uploadContent({
stream: new Buffer(file.bytes), stream: Buffer.from(file.bytes),
name: name, name,
type: file.mimetype, type: file.mimetype,
}, { rawResponse: false }) }, { rawResponse: false })
@@ -106,13 +106,13 @@ class Portal {
async handleMatrixEvent(sender, evt) { async handleMatrixEvent(sender, evt) {
switch (evt.content.msgtype) { switch (evt.content.msgtype) {
case "m.notice": case "m.notice":
case "m.text": case "m.text":
await this.loadAccessHash(sender.telegramPuppet) await this.loadAccessHash(sender.telegramPuppet)
sender.telegramPuppet.sendMessage(this.peer, evt.content.body) sender.telegramPuppet.sendMessage(this.peer, evt.content.body)
break break
default: default:
console.log("Unhandled event:", evt) console.log("Unhandled event:", evt)
} }
} }
@@ -120,7 +120,7 @@ class Portal {
return !!this.roomID return !!this.roomID
} }
async createMatrixRoom(telegramPOV, {invite = []} = {}) { async createMatrixRoom(telegramPOV, { invite = [] } = {}) {
if (this.roomID) { if (this.roomID) {
return { return {
created: false, created: false,
+77 -76
View File
@@ -26,19 +26,19 @@ class TelegramPeer {
static fromTelegramData(peer, sender, receiverID) { static fromTelegramData(peer, sender, receiverID) {
switch (peer._) { switch (peer._) {
case "peerChat": case "peerChat":
return new TelegramPeer("chat", peer.chat_id) return new TelegramPeer("chat", peer.chat_id)
case "peerUser": case "peerUser":
return new TelegramPeer("user", sender, { return new TelegramPeer("user", sender, {
accessHash: peer.access_hash, accessHash: peer.access_hash,
receiverID, receiverID,
}) })
case "peerChannel": case "peerChannel":
return new TelegramPeer("channel", peer.channel_id, { return new TelegramPeer("channel", peer.channel_id, {
accessHash: peer.access_hash, accessHash: peer.access_hash,
}) })
default: default:
throw new Error(`Unrecognized peer type ${peer._}`) throw new Error(`Unrecognized peer type ${peer._}`)
} }
} }
@@ -71,6 +71,7 @@ class TelegramPeer {
} }
return false return false
} }
return false
} }
async updateInfo(dialog) { async updateInfo(dialog) {
@@ -92,82 +93,82 @@ class TelegramPeer {
let info, let info,
users users
switch (this.type) { switch (this.type) {
case "user": case "user":
info = await telegramPOV.client("users.getFullUser", { info = await telegramPOV.client("users.getFullUser", {
id: this.toInputObject(), id: this.toInputObject(),
}) })
users = [info.user] users = [info.user]
info = info.user info = info.user
break break
case "chat": case "chat":
info = await telegramPOV.client("messages.getFullChat", { info = await telegramPOV.client("messages.getFullChat", {
chat_id: this.id, chat_id: this.id,
}) })
users = info.users users = info.users
info = info.chats[0] info = info.chats[0]
break break
case "channel": case "channel":
info = await telegramPOV.client("channels.getFullChannel", { info = await telegramPOV.client("channels.getFullChannel", {
channel: this.toInputObject(), channel: this.toInputObject(),
}) })
info = info.chats[0] info = info.chats[0]
const participants = await telegramPOV.client("channels.getParticipants", { const participants = await telegramPOV.client("channels.getParticipants", {
channel: this.toInputObject(), channel: this.toInputObject(),
filter: { _: "channelParticipantsRecent" }, filter: { _: "channelParticipantsRecent" },
offset: 0, offset: 0,
limit: 1000, limit: 1000,
}) })
users = participants.users users = participants.users
break break
default: default:
throw new Error(`Unknown peer type ${this.type}`) throw new Error(`Unknown peer type ${this.type}`)
} }
return { return {
info: info, info,
users, users,
} }
} }
toInputPeer() { toInputPeer() {
switch (this.type) { switch (this.type) {
case "chat": case "chat":
return { return {
_: "inputPeerChat", _: "inputPeerChat",
chat_id: this.id, chat_id: this.id,
} }
case "user": case "user":
return { return {
_: "inputPeerUser", _: "inputPeerUser",
user_id: this.id, user_id: this.id,
access_hash: this.accessHash, access_hash: this.accessHash,
} }
case "channel": case "channel":
return { return {
_: "inputPeerChannel", _: "inputPeerChannel",
channel_id: this.id, channel_id: this.id,
access_hash: this.accessHash, access_hash: this.accessHash,
} }
default: default:
throw new Error(`Unrecognized peer type ${this.type}`) throw new Error(`Unrecognized peer type ${this.type}`)
} }
} }
toInputObject() { toInputObject() {
switch (this.type) { switch (this.type) {
case "user": case "user":
return { return {
_: "inputUser", _: "inputUser",
user_id: this.id, user_id: this.id,
access_hash: this.accessHash, access_hash: this.accessHash,
} }
case "channel": case "channel":
return { return {
_: "inputChannel", _: "inputChannel",
channel_id: this.id, channel_id: this.id,
access_hash: this.accessHash, access_hash: this.accessHash,
} }
default: default:
throw new Error(`Unrecognized type ${this.type}`) throw new Error(`Unrecognized type ${this.type}`)
} }
} }
+84 -82
View File
@@ -13,9 +13,8 @@
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
const pkg = require("../package.json")
const os = require("os")
const telegram = require("telegram-mtproto") const telegram = require("telegram-mtproto")
const pkg = require("../package.json")
const TelegramPeer = require("./telegram-peer") const TelegramPeer = require("./telegram-peer")
const META_FROM_FILETYPE = { const META_FROM_FILETYPE = {
@@ -37,7 +36,7 @@ const META_FROM_FILETYPE = {
* TelegramPuppet represents a Telegram account being controlled from Matrix. * TelegramPuppet represents a Telegram account being controlled from Matrix.
*/ */
class TelegramPuppet { class TelegramPuppet {
constructor(app, {userID, matrixUser, data, api_hash, api_id, server_config, api_config}) { constructor(app, { userID, matrixUser, data, api_hash, api_id, server_config, api_config }) {
this._client = undefined this._client = undefined
this.userID = userID this.userID = userID
this.matrixUser = matrixUser this.matrixUser = matrixUser
@@ -54,20 +53,20 @@ class TelegramPuppet {
get: async (key) => { get: async (key) => {
let value = this.data[key] let value = this.data[key]
// TODO test and (enable or remove) // TODO test and (enable or remove)
/*if (typeof(value) === "string" && value.startsWith("b64:")) { if (typeof value === "string" && value.startsWith("b64:")) {
value = Array.from(new Buffer(value.substr("b64:".length), "base64")) value = Array.from(Buffer.from(value.substr("b64:".length), "base64"))
}*/ }
return value return value
}, },
set: async (key, value) => { set: async (key, value) => {
// TODO test and (enable or remove) // TODO test and (enable or remove)
/*if (Array.isArray(value)) { if (Array.isArray(value)) {
console.log("Non-buffer array") console.log("Non-buffer array")
value = `b64:${new Buffer(value).toString("base64")}` value = `b64:${Buffer.from(value).toString("base64")}`
} else if (value instanceof Buffer) { } else if (value instanceof Buffer) {
console.log("Buffer array") console.log("Buffer array")
value = `b64:${value.toString("base64")}` value = `b64:${value.toString("base64")}`
}*/ }
console.warn("SET", key, "=", JSON.stringify(value)) console.warn("SET", key, "=", JSON.stringify(value))
if (this.data[key] === value) { if (this.data[key] === value) {
return return
@@ -77,7 +76,7 @@ class TelegramPuppet {
await this.matrixUser.save() await this.matrixUser.save()
}, },
remove: async (...keys) => { remove: async (...keys) => {
console.warn("DEL", JSON.stringify(value)) console.warn("DEL", JSON.stringify(keys))
keys.forEach((key) => delete this.data[key]) keys.forEach((key) => delete this.data[key])
await this.matrixUser.save() await this.matrixUser.save()
}, },
@@ -91,8 +90,8 @@ class TelegramPuppet {
this.apiConfig = Object.assign({}, { this.apiConfig = Object.assign({}, {
app_version: pkg.version, app_version: pkg.version,
lang_code: "en", lang_code: "en",
api_id: api_id, api_id,
initConnection : 0x69796de9, initConnection: 0x69796de9,
layer: 57, layer: 57,
invokeWithLayer: 0xda9b0d0d, invokeWithLayer: 0xda9b0d0d,
}, api_config) }, api_config)
@@ -120,7 +119,6 @@ class TelegramPuppet {
get client() { get client() {
if (!this._client) { if (!this._client) {
const self = this
this._client = telegram.MTProto({ this._client = telegram.MTProto({
api: this.apiConfig, api: this.apiConfig,
server: this.serverConfig, server: this.serverConfig,
@@ -212,7 +210,7 @@ class TelegramPuppet {
const result = await this.client("messages.sendMessage", { const result = await this.client("messages.sendMessage", {
peer: peer.toInputPeer(), peer: peer.toInputPeer(),
message, message,
random_id: ~~(Math.random() * (1<<30)), random_id: ~~(Math.random() * (1 << 30)),
}) })
return result return result
} }
@@ -220,8 +218,8 @@ class TelegramPuppet {
async sendMedia(peer, media) { async sendMedia(peer, media) {
const result = await this.client("messages.sendMedia", { const result = await this.client("messages.sendMedia", {
peer: peer.toInputPeer(), peer: peer.toInputPeer(),
media: media, media,
random_id: ~~(Math.random() * (1<<30)), random_id: ~~(Math.random() * (1 << 30)),
}) })
// TODO use result? (maybe the ID) // TODO use result? (maybe the ID)
return result return result
@@ -241,80 +239,83 @@ class TelegramPuppet {
return return
} }
let peer, portal let peer, portal
switch(update._) { switch (update._) {
case "updateUserStatus": case "updateUserStatus":
const user = await this.app.getTelegramUser(update.user_id) const user = await this.app.getTelegramUser(update.user_id)
let status let status
switch(update.status._) { switch (update.status._) {
case "userStatusOnline": case "userStatusOnline":
status = "online" status = "online"
break
case "userStatusOffline":
default:
status = "offline"
}
await user.intent.getClient().setPresence({presence: status})
break
case "updateUserTyping":
peer = new TelegramPeer("user", update.user_id, { receiverID: this.userID })
case "updateChatUserTyping":
peer = peer || new TelegramPeer("chat", update.chat_id)
portal = await this.app.getPortalByPeer(peer)
if (portal.isMatrixRoomCreated()) {
const sender = await this.app.getTelegramUser(update.user_id)
// The Intent API currently doesn't allow you to set the
// typing timeout. Once it does, we should set it to ~5.5s
// as Telegram resends typing notifications every 5 seconds.
await sender.intent.sendTyping(portal.roomID, true/*, 5500*/)
}
break
case "updateShortMessage":
peer = new TelegramPeer("user", update.user_id, { receiverID: this.userID })
case "updateShortChatMessage":
peer = peer || new TelegramPeer("chat", update.chat_id)
await this.handleMessage({
from: update.user_id,
to: peer,
text: update.message,
})
break
case "updateNewChannelMessage":
case "updateNewMessage":
// TODO handle other content types
update = update.message // Message defined at message#90dddc11 in layer 71
await this.handleMessage({
from: update.from_id,
to: TelegramPeer.fromTelegramData(update.to_id, update.from_id, this.userID),
text: update.message,
})
break break
case "userStatusOffline":
default: default:
console.log(`Update of type ${update._} received:\n${JSON.stringify(update, "", " ")}`) status = "offline"
}
await user.intent.getClient()
.setPresence({ presence: status })
break
case "updateUserTyping":
peer = new TelegramPeer("user", update.user_id, { receiverID: this.userID })
/* falls through */
case "updateChatUserTyping":
peer = peer || new TelegramPeer("chat", update.chat_id)
portal = await this.app.getPortalByPeer(peer)
if (portal.isMatrixRoomCreated()) {
const sender = await this.app.getTelegramUser(update.user_id)
// The Intent API currently doesn't allow you to set the
// typing timeout. Once it does, we should set it to ~5.5s
// as Telegram resends typing notifications every 5 seconds.
await sender.intent.sendTyping(portal.roomID, true/*, 5500*/)
}
break
case "updateShortMessage":
peer = new TelegramPeer("user", update.user_id, { receiverID: this.userID })
/* falls through */
case "updateShortChatMessage":
peer = peer || new TelegramPeer("chat", update.chat_id)
await this.handleMessage({
from: update.user_id,
to: peer,
text: update.message,
})
break
case "updateNewChannelMessage":
case "updateNewMessage":
// TODO handle other content types
update = update.message // Message defined at message#90dddc11 in layer 71
await this.handleMessage({
from: update.from_id,
to: TelegramPeer.fromTelegramData(update.to_id, update.from_id, this.userID),
text: update.message,
})
break
default:
console.log(`Update of type ${update._} received:\n${JSON.stringify(update, "", " ")}`)
} }
} }
handleUpdate(data) { handleUpdate(data) {
try { try {
switch (data._) { switch (data._) {
case "updateShort": case "updateShort":
this.onUpdate(data.update) this.onUpdate(data.update)
break break
case "updates": case "updates":
for (const update of data.updates) { for (const update of data.updates) {
this.onUpdate(update) this.onUpdate(update)
} }
break break
case "updateShortMessage": case "updateShortMessage":
case "updateShortChatMessage": case "updateShortChatMessage":
this.onUpdate(data) this.onUpdate(data)
break break
default: default:
console.log("Unrecognized update type:", data._) console.log("Unrecognized update type:", data._)
} }
} catch (err) { } catch (err) {
console.error("Error handling update:", err) console.error("Error handling update:", err)
console.log(e.stack) console.log(err.stack)
} }
} }
@@ -355,8 +356,9 @@ class TelegramPuppet {
} }
setInterval(async () => { setInterval(async () => {
try { try {
const state = this.client("updates.getState", {})
// TODO use state? // TODO use state?
/*const state = */
this.client("updates.getState", {})
} catch (err) { } catch (err) {
console.error("Error updating state:", err) console.error("Error updating state:", err)
} }
@@ -364,12 +366,12 @@ class TelegramPuppet {
} }
async getFile(location) { async getFile(location) {
location = Object.assign({}, location, {_: "inputFileLocation"}) location = Object.assign({}, location, { _: "inputFileLocation" })
delete location.dc_id delete location.dc_id
const file = await this.client("upload.getFile", { const file = await this.client("upload.getFile", {
location, location,
offset: 0, offset: 0,
limit: 100*1024*1024, limit: 100 * 1024 * 1024,
}) })
const meta = META_FROM_FILETYPE[file.type._] const meta = META_FROM_FILETYPE[file.type._]
if (meta) { if (meta) {
+4 -4
View File
@@ -91,8 +91,8 @@ class TelegramUser {
const userInfo = await this.intent.getProfileInfo(this.mxid, "displayname") const userInfo = await this.intent.getProfileInfo(this.mxid, "displayname")
if (userInfo.displayname !== this.getDisplayName()) { if (userInfo.displayname !== this.getDisplayName()) {
this.intent.setDisplayName( this.intent.setDisplayName(this.app.config.bridge.displayname_template
this.app.config.bridge.displayname_template.replace("${DISPLAYNAME}", this.getDisplayName())) .replace("${DISPLAYNAME}", this.getDisplayName()))
} }
if (updateAvatar && this.updateAvatar(telegramPOV, user)) { if (updateAvatar && this.updateAvatar(telegramPOV, user)) {
changed = true changed = true
@@ -172,8 +172,8 @@ class TelegramUser {
const name = `${photo.volume_id}_${photo.local_id}.${file.extension}` const name = `${photo.volume_id}_${photo.local_id}.${file.extension}`
const uploaded = await this.uploadContent({ const uploaded = await this.uploadContent({
stream: new Buffer(file.bytes), stream: Buffer.from(file.bytes),
name: name, name,
type: file.mimetype, type: file.mimetype,
}) })