From 68e835c6588cf3d56c4def10b5b43369e876b3fa Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 27 Aug 2024 15:13:11 +0300 Subject: [PATCH] legacymigrate: add support for migrating legacy database and config (#23) --- cmd/mautrix-telegram/legacymigrate.go | 52 +++++ cmd/mautrix-telegram/legacymigrate.sql | 256 +++++++++++++++++++++++++ cmd/mautrix-telegram/main.go | 54 +++++- go.mod | 4 +- go.sum | 8 +- pkg/connector/client.go | 9 +- pkg/connector/config.go | 35 +++- pkg/connector/example-config.yaml | 11 +- pkg/connector/login.go | 2 +- 9 files changed, 405 insertions(+), 26 deletions(-) create mode 100644 cmd/mautrix-telegram/legacymigrate.go create mode 100644 cmd/mautrix-telegram/legacymigrate.sql diff --git a/cmd/mautrix-telegram/legacymigrate.go b/cmd/mautrix-telegram/legacymigrate.go new file mode 100644 index 00000000..8005fd7f --- /dev/null +++ b/cmd/mautrix-telegram/legacymigrate.go @@ -0,0 +1,52 @@ +package main + +import ( + _ "embed" + + up "go.mau.fi/util/configupgrade" + "maunium.net/go/mautrix/bridgev2/bridgeconfig" +) + +const legacyMigrateRenameTables = ` +ALTER TABLE backfill_queue RENAME TO backfill_queue_old; +ALTER TABLE bot_chat RENAME TO bot_chat_old; +ALTER TABLE contact RENAME TO contact_old; +ALTER TABLE disappearing_message RENAME TO disappearing_message_old; +ALTER TABLE message RENAME TO message_old; +ALTER TABLE portal RENAME TO portal_old; +ALTER TABLE puppet RENAME TO puppet_old; +ALTER TABLE reaction RENAME TO reaction_old; +ALTER TABLE telegram_file RENAME TO telegram_file_old; +ALTER TABLE telethon_entities RENAME TO telethon_entities_old; +ALTER TABLE telethon_sent_files RENAME TO telethon_sent_files_old; +ALTER TABLE telethon_sessions RENAME TO telethon_sessions_old; +ALTER TABLE telethon_update_state RENAME TO telethon_update_state_old; +ALTER TABLE "user" RENAME TO user_old; +ALTER TABLE user_portal RENAME TO user_portal_old; +` + +//go:embed legacymigrate.sql +var legacyMigrateCopyData string + +func migrateLegacyConfig(helper up.Helper) { + helper.Set(up.Str, "mautrix.bridge.e2ee", "encryption", "pickle_key") + bridgeconfig.CopyToOtherLocation(helper, up.Int, []string{"telegram", "api_id"}, []string{"network", "api_id"}) + bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"telegram", "api_hash"}, []string{"network", "api_hash"}) + bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"telegram", "device_info", "device_model"}, []string{"network", "device_info", "device_model"}) + bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"telegram", "device_info", "system_version"}, []string{"network", "device_info", "system_version"}) + bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"telegram", "device_info", "app_version"}, []string{"network", "device_info", "app_version"}) + bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"telegram", "device_info", "lang_code"}, []string{"network", "device_info", "lang_code"}) + bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"telegram", "device_info", "system_lang_code"}, []string{"network", "device_info", "system_lang_code"}) + bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"bridge", "animated_sticker", "target"}, []string{"network", "animated_sticker", "target"}) + bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "animated_sticker", "convert_from_webm"}, []string{"network", "animated_sticker", "convert_from_webm"}) + bridgeconfig.CopyToOtherLocation(helper, up.Int, []string{"bridge", "animated_sticker", "width"}, []string{"network", "animated_sticker", "width"}) + bridgeconfig.CopyToOtherLocation(helper, up.Int, []string{"bridge", "animated_sticker", "height"}, []string{"network", "animated_sticker", "height"}) + bridgeconfig.CopyToOtherLocation(helper, up.Int, []string{"bridge", "animated_sticker", "fps"}, []string{"network", "animated_sticker", "fps"}) + bridgeconfig.CopyToOtherLocation(helper, up.Int, []string{"bridge", "max_initial_member_sync"}, []string{"network", "member_list", "max_initial_sync"}) + bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "sync_channel_members"}, []string{"network", "member_list", "sync_broadcast_channels"}) + bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "skip_deleted_members"}, []string{"network", "member_list", "skip_deleted"}) + bridgeconfig.CopyToOtherLocation(helper, up.Int, []string{"bridge", "max_member_count"}, []string{"network", "max_member_count"}) + bridgeconfig.CopyToOtherLocation(helper, up.Int, []string{"bridge", "sync_update_limit"}, []string{"network", "sync", "update_limit"}) + bridgeconfig.CopyToOtherLocation(helper, up.Int, []string{"bridge", "sync_create_limit"}, []string{"network", "sync", "create_limit"}) + bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "sync_direct_chats"}, []string{"network", "sync", "direct_chats"}) +} diff --git a/cmd/mautrix-telegram/legacymigrate.sql b/cmd/mautrix-telegram/legacymigrate.sql new file mode 100644 index 00000000..d1415e5c --- /dev/null +++ b/cmd/mautrix-telegram/legacymigrate.sql @@ -0,0 +1,256 @@ +INSERT INTO "user" (bridge_id, mxid) +SELECT '', mxid FROM user_old; + +ALTER TABLE telethon_sessions_old ADD COLUMN json_data jsonb; +UPDATE telethon_sessions_old SET json_data= + -- only: postgres + jsonb_build_object + -- only: sqlite (line commented) +-- json_object + ( + 'auth_key', encode(auth_key, 'base64'), + 'dc_id', dc_id, + 'server_address', server_address, + 'port', port + ); + +INSERT INTO user_login (bridge_id, user_mxid, id, remote_name, remote_profile, space_room, metadata) +SELECT + '', -- bridge_id + mxid, -- user_mxid + CAST(tgid AS TEXT), -- id + COALESCE(tg_username, tg_phone, ''), -- remote_name + '{}', -- remote_profile + '', -- space_room + -- only: postgres + jsonb_build_object + -- only: sqlite (line commented) +-- json_object + ( + 'phone', COALESCE(tg_phone, ''), + 'session', json((SELECT json_data FROM telethon_sessions_old WHERE session_id=mxid)) + ) -- metadata +FROM user_old +WHERE tgid IS NOT NULL; + +INSERT INTO ghost ( + bridge_id, id, name, avatar_id, avatar_hash, avatar_mxc, + name_set, avatar_set, contact_info_set, is_bot, identifiers, metadata +) +SELECT + '', -- bridge_id + CAST(id AS TEXT), -- id + COALESCE(displayname, ''), -- name + COALESCE(photo_id, ''), -- avatar_id + '', -- avatar_hash + COALESCE(avatar_url, ''), -- avatar_mxc + name_set, + avatar_set, + contact_info_set, + COALESCE(is_bot, false), + '[]', -- identifiers + -- only: postgres + jsonb_build_object + -- only: sqlite (line commented) +-- json_object + ( + 'is_premium', is_premium, + 'is_channel', is_channel, + 'phone', phone, + 'name_source', displayname_source, + 'name_quality', displayname_quality, + 'name_not_contact', CASE WHEN displayname_contact THEN json('false') ELSE json('true') END + ) -- metadata +FROM puppet_old; + +DELETE FROM user_portal_old WHERE portal IN (SELECT tgid FROM portal_old WHERE peer_type<>'channel'); +-- TODO migrate backfill queue instead of deleting +DELETE FROM backfill_queue_old WHERE portal_tgid IN (SELECT tgid FROM portal_old WHERE peer_type<>'channel'); + +UPDATE portal_old +SET tg_receiver=COALESCE((SELECT "user" FROM user_portal_old WHERE portal=portal_old.tgid LIMIT 1), tg_receiver) +WHERE peer_type='chat' AND tgid=tg_receiver; + +UPDATE portal_old +SET tg_receiver=COALESCE((SELECT tgid FROM user_old WHERE tgid IS NOT NULL LIMIT 1), tg_receiver) +WHERE peer_type='chat' AND tgid=tg_receiver; + +DELETE FROM portal_old WHERE peer_type='chat' AND tgid=tg_receiver; + +INSERT INTO portal ( + bridge_id, id, receiver, mxid, other_user_id, name, topic, avatar_id, avatar_hash, avatar_mxc, + name_set, avatar_set, topic_set, name_is_custom, in_space, room_type, metadata +) +SELECT + '', -- bridge_id + CAST(tgid AS TEXT), -- id + CAST(tg_receiver AS TEXT), -- receiver + mxid, -- mxid + CASE WHEN peer_type='user' THEN CAST(tgid AS TEXT) END, -- other_user_id + COALESCE(title, ''), -- name + COALESCE(about, ''), -- topic + COALESCE(photo_id, ''), -- avatar_id + '', -- avatar_hash + COALESCE(avatar_url, ''), -- avatar_mxc + name_set, -- name_set + avatar_set, -- avatar_set + false, -- topic_set + peer_type<>'user', -- name_is_custom + false, -- in_space + CASE WHEN peer_type='user' THEN 'dm' ELSE '' END, -- room_type + -- only: postgres + jsonb_build_object + -- only: sqlite (line commented) +-- json_object + ( + -- TODO + ) -- metadata +FROM portal_old; + +INSERT INTO user_portal (bridge_id, user_mxid, login_id, portal_id, portal_receiver, in_space, preferred) +SELECT + '', -- bridge_id + user_old.mxid, -- user_mxid + CAST(user_portal_old.user AS TEXT), -- login_id + CAST(user_portal_old.portal AS TEXT), -- portal_id + CAST(user_portal_old.portal_receiver AS TEXT), -- portal_receiver + false, -- in_space + false -- preferred +FROM user_portal_old +INNER JOIN user_old ON user_portal_old."user" = user_old.tgid; + +INSERT INTO user_portal (bridge_id, user_mxid, login_id, portal_id, portal_receiver, in_space, preferred) +SELECT + '', -- bridge_id + user_old.mxid, -- user_mxid + CAST(portal_old.tg_receiver AS TEXT), -- login_id + CAST(portal_old.tgid AS TEXT), -- portal_id + CAST(portal_old.tg_receiver AS TEXT), -- portal_receiver + false, -- in_space + false -- preferred +FROM portal_old +INNER JOIN user_old ON portal_old.tg_receiver = user_old.tgid +WHERE portal_old.tg_receiver<>portal_old.tgid +ON CONFLICT (bridge_id, user_mxid, login_id, portal_id, portal_receiver) DO NOTHING; + +INSERT INTO ghost (bridge_id, id, name, avatar_id, avatar_hash, avatar_mxc, name_set, avatar_set, contact_info_set, is_bot, identifiers, metadata) +VALUES ('', '', '', '', '', '', false, false, false, false, '[]', '{}'); + +INSERT INTO message ( + bridge_id, id, part_id, mxid, room_id, room_receiver, sender_id, sender_mxid, timestamp, edit_count, metadata +) +SELECT + '', -- bridge_id + CASE WHEN tg_space=portal_old.tgid THEN (CAST(tg_space AS TEXT) || '.') ELSE '' END || CAST(message_old.tgid AS TEXT), -- id + '', -- part_id + message_old.mxid, -- mxid + CAST(portal_old.tgid AS TEXT), -- room_id + CAST(portal_old.tg_receiver AS TEXT), -- room_receiver + COALESCE(CAST(sender AS TEXT), ''), -- sender_id + COALESCE(sender_mxid, ''), + 0, -- timestamp + 0, -- edit_count + '{}' -- metadata +FROM message_old +INNER JOIN portal_old ON mx_room=portal_old.mxid +WHERE (tg_space=portal_old.tgid OR tg_space=portal_old.tg_receiver) AND edit_index=0; +-- TODO migrate edit_index? + +INSERT INTO reaction ( + bridge_id, message_id, message_part_id, sender_id, emoji_id, room_id, room_receiver, mxid, timestamp, emoji, metadata +) +SELECT + '', -- bridge_id + message.id, -- message_id + message.part_id, -- message_part_id + CAST(tg_sender AS TEXT), -- sender_id + reaction, -- emoji_id + message.room_id, -- room_id + message.room_receiver, -- room_receiver + reaction_old.mxid, -- mxid + 0, -- timestamp + reaction, -- emoji + '{}' -- metadata +FROM reaction_old +INNER JOIN message ON reaction_old.msg_mxid=message.mxid; + +INSERT INTO telegram_access_hash (user_id, entity_id, access_hash) +SELECT user_old.tgid, id, hash +FROM telethon_entities_old +LEFT JOIN user_old ON user_old.mxid=session_id +WHERE user_old.tgid IS NOT NULL AND hash<>0; + +INSERT INTO telegram_user_state (user_id, pts, qts, date, seq) +SELECT user_old.tgid, pts, qts, date, seq +FROM telethon_update_state_old +LEFT JOIN user_old ON user_old.mxid=session_id +WHERE entity_id=0 AND user_old.tgid IS NOT NULL; + +INSERT INTO telegram_channel_state (user_id, channel_id, pts) +SELECT user_old.tgid, entity_id, pts +FROM telethon_update_state_old +LEFT JOIN user_old ON user_old.mxid=session_id +WHERE entity_id<>0 AND user_old.tgid IS NOT NULL; + +INSERT INTO telegram_username (username, entity_id) +SELECT username, id +FROM telethon_entities_old +WHERE username<>'' +ON CONFLICT DO NOTHING; + +INSERT INTO telegram_file (id, mxc, mime_type, size) +SELECT id, mxc, mime_type, size +FROM telegram_file_old; + +INSERT INTO disappearing_message (bridge_id, mx_room, mxid, type, timer, disappear_at) +SELECT + '', -- bridge_id + room_id, + event_id, + 'after_send', + expiration_seconds * 1000000000, + expiration_ts * 1000000 +FROM disappearing_message_old +WHERE expiration_ts<9999999999999 AND expiration_seconds<999999; + +-- TODO do something with the bot_chat table? + +-- Python -> Go mx_ table migration +ALTER TABLE mx_room_state DROP COLUMN is_encrypted; +ALTER TABLE mx_room_state RENAME COLUMN has_full_member_list TO members_fetched; + +-- only: postgres until "end only" +ALTER TABLE mx_room_state ALTER COLUMN power_levels TYPE jsonb USING power_levels::jsonb; +ALTER TABLE mx_room_state ALTER COLUMN encryption TYPE jsonb USING encryption::jsonb; +ALTER TABLE mx_room_state ALTER COLUMN members_fetched SET DEFAULT false; +ALTER TABLE mx_room_state ALTER COLUMN members_fetched SET NOT NULL; +-- end only postgres + +ALTER TABLE mx_user_profile ADD COLUMN name_skeleton bytea; +CREATE INDEX mx_user_profile_membership_idx ON mx_user_profile (room_id, membership); +CREATE INDEX mx_user_profile_name_skeleton_idx ON mx_user_profile (room_id, name_skeleton); + +UPDATE mx_user_profile SET displayname='' WHERE displayname IS NULL; +UPDATE mx_user_profile SET avatar_url='' WHERE avatar_url IS NULL; + +CREATE TABLE mx_registrations ( + user_id TEXT PRIMARY KEY +); + +UPDATE mx_version SET version=7; + +DROP TABLE user_portal_old; +DROP TABLE backfill_queue_old; +DROP TABLE bot_chat_old; +DROP TABLE contact_old; +DROP TABLE disappearing_message_old; +DROP TABLE message_old; +DROP TABLE reaction_old; +DROP TABLE portal_old; +DROP TABLE puppet_old; +DROP TABLE user_old; +DROP TABLE telegram_file_old; +DROP TABLE telethon_entities_old; +DROP TABLE telethon_sent_files_old; +DROP TABLE telethon_sessions_old; +DROP TABLE telethon_update_state_old; diff --git a/cmd/mautrix-telegram/main.go b/cmd/mautrix-telegram/main.go index b190b58a..fa269e24 100644 --- a/cmd/mautrix-telegram/main.go +++ b/cmd/mautrix-telegram/main.go @@ -17,9 +17,15 @@ package main import ( + "encoding/base64" + "fmt" + + "go.mau.fi/util/dbutil/litestream" + "maunium.net/go/mautrix/bridgev2/bridgeconfig" "maunium.net/go/mautrix/bridgev2/matrix/mxmain" "go.mau.fi/mautrix-telegram/pkg/connector" + "go.mau.fi/mautrix-telegram/pkg/connector/store/upgrades" ) // Information to find out exactly which commit the bridge was built from. @@ -30,14 +36,48 @@ var ( BuildTime = "unknown" ) -func main() { - m := mxmain.BridgeMain{ - Name: "mautrix-telegram", - URL: "https://github.com/mautrix/telegram", - Description: "A Matrix-Telegram puppeting bridge.", - Version: "0.16.0", +var c = connector.NewConnector() +var m = mxmain.BridgeMain{ + Name: "mautrix-telegram", + URL: "https://github.com/mautrix/telegram", + Description: "A Matrix-Telegram puppeting bridge.", + Version: "0.16.0", - Connector: connector.NewConnector(), + Connector: c, +} + +func init() { + litestream.Functions["encode"] = func(data []byte, encoding string) string { + if encoding == "base64" { + return base64.StdEncoding.EncodeToString(data) + } + panic(fmt.Errorf("unknown encoding %q", encoding)) + } +} + +func main() { + bridgeconfig.HackyMigrateLegacyNetworkConfig = migrateLegacyConfig + versionWithoutCommit := m.Version + m.PostInit = func() { + if c.Config.DeviceInfo.AppVersion == "auto" { + c.Config.DeviceInfo.AppVersion = versionWithoutCommit + } + if c.Config.DeviceInfo.SystemVersion == "auto" { + c.Config.DeviceInfo.SystemVersion = "" + } + if c.Config.DeviceInfo.DeviceModel == "auto" || c.Config.DeviceInfo.DeviceModel == "" { + c.Config.DeviceInfo.DeviceModel = "mautrix-telegram" + } + m.CheckLegacyDB( + 18, + "v0.14.0", + "v0.16.0", + m.LegacyMigrateWithAnotherUpgrader( + legacyMigrateRenameTables, legacyMigrateCopyData, 16, + upgrades.Table, "telegram_version", 1, + ), + true, + ) } m.InitVersion(Tag, Commit, BuildTime) m.Run() diff --git a/go.mod b/go.mod index 00cc215b..8ae499d4 100644 --- a/go.mod +++ b/go.mod @@ -6,12 +6,12 @@ require ( github.com/gotd/td v0.105.0 github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.9.0 - go.mau.fi/util v0.7.0 + go.mau.fi/util v0.7.1-0.20240827120252-821b350d3b0b go.mau.fi/zerozap v0.1.1 go.uber.org/zap v1.27.0 golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa golang.org/x/net v0.28.0 - maunium.net/go/mautrix v0.20.1-0.20240826145415-7e7cb57ee770 + maunium.net/go/mautrix v0.20.1-0.20240827115426-7276f10fcf1e ) require ( diff --git a/go.sum b/go.sum index bd0508df..c51cfcbd 100644 --- a/go.sum +++ b/go.sum @@ -73,8 +73,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.7.0 h1:l31z+ivrSQw+cv/9eFebEqtQW2zhxivGypn+JT0h/ws= -go.mau.fi/util v0.7.0/go.mod h1:bWYreIoTULL/UiRbZdfddPh7uWDFW5yX4YCv5FB0eE0= +go.mau.fi/util v0.7.1-0.20240827120252-821b350d3b0b h1:P2ss5SCNFTQ0X471E/nxEJTbSpXjwvjoSEws3zrOgU0= +go.mau.fi/util v0.7.1-0.20240827120252-821b350d3b0b/go.mod h1:WuAOOV0O/otkxGkFUvfv/XE2ztegaoyM15ovS6SYbf4= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= go.mau.fi/zerozap v0.1.1 h1:mxE/dW4wtkqBYOXOEEzXldk5qKB+ahsZXjoTGnvEhZQ= @@ -116,8 +116,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M= maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA= -maunium.net/go/mautrix v0.20.1-0.20240826145415-7e7cb57ee770 h1:u8T0cxthFOTyQDqGwDU15/f7zIZdW/268CP4ITWDF1A= -maunium.net/go/mautrix v0.20.1-0.20240826145415-7e7cb57ee770/go.mod h1:gjaQwhKXiw0MDWmGpYvbBbIkmI5bUC7PVgrvn1DgYjI= +maunium.net/go/mautrix v0.20.1-0.20240827115426-7276f10fcf1e h1:sCZhAaEKqc7GJ0zmBb4Jg7u7imQdMC71kaGkIR+5B00= +maunium.net/go/mautrix v0.20.1-0.20240827115426-7276f10fcf1e/go.mod h1:7hh/Hx5W9lUcqL0hkSw52kMyY+6nMUPTtdDN0qVEXwI= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY= diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 7db170fc..fc0da011 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -182,7 +182,7 @@ func NewTelegramClient(ctx context.Context, tc *TelegramConnector, login *bridge AccessHasher: client.ScopedStore, }) - client.client = telegram.NewClient(tc.Config.AppID, tc.Config.AppHash, telegram.Options{ + client.client = telegram.NewClient(tc.Config.APIID, tc.Config.APIHash, telegram.Options{ CustomSessionStorage: &login.Metadata.(*UserLoginMetadata).Session, Logger: zaplog, UpdateHandler: client.updatesManager, @@ -191,6 +191,13 @@ func NewTelegramClient(ctx context.Context, tc *TelegramConnector, login *bridge OnAuthError: client.onAuthError, PingTimeout: time.Duration(tc.Config.Ping.TimeoutSeconds) * time.Second, PingInterval: time.Duration(tc.Config.Ping.IntervalSeconds) * time.Second, + Device: telegram.DeviceConfig{ + DeviceModel: tc.Config.DeviceInfo.DeviceModel, + SystemVersion: tc.Config.DeviceInfo.SystemVersion, + AppVersion: tc.Config.DeviceInfo.AppVersion, + SystemLangCode: tc.Config.DeviceInfo.SystemLangCode, + LangCode: tc.Config.DeviceInfo.LangCode, + }, }) client.telegramFmtParams = &telegramfmt.FormatParams{ diff --git a/pkg/connector/config.go b/pkg/connector/config.go index 75dc6322..6938f187 100644 --- a/pkg/connector/config.go +++ b/pkg/connector/config.go @@ -10,6 +10,7 @@ import ( "github.com/gotd/td/session" up "go.mau.fi/util/configupgrade" "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/bridgeconfig" "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/id" @@ -31,10 +32,19 @@ func (c MemberListConfig) NormalizedMaxInitialSync() int { return c.MaxInitialSync } +type DeviceInfo struct { + DeviceModel string `yaml:"device_model"` + SystemVersion string `yaml:"system_version"` + AppVersion string `yaml:"app_version"` + SystemLangCode string `yaml:"system_lang_code"` + LangCode string `yaml:"lang_code"` +} + type TelegramConfig struct { - // FIXME these should be called api_id and api_hash - AppID int `yaml:"app_id"` - AppHash string `yaml:"app_hash"` + APIID int `yaml:"api_id"` + APIHash string `yaml:"api_hash"` + + DeviceInfo DeviceInfo `yaml:"device_info"` AnimatedSticker media.AnimatedStickerConfig `yaml:"animated_sticker"` @@ -62,8 +72,15 @@ func (c TelegramConfig) ShouldBridge(participantCount int) bool { var ExampleConfig string func upgradeConfig(helper up.Helper) { - helper.Copy(up.Int, "app_id") - helper.Copy(up.Str, "app_hash") + bridgeconfig.CopyToOtherLocation(helper, up.Int, []string{"app_id"}, []string{"api_id"}) + bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"app_hash"}, []string{"api_hash"}) + helper.Copy(up.Int, "api_id") + helper.Copy(up.Str, "api_hash") + helper.Copy(up.Str|up.Null, "device_info", "device_model") + helper.Copy(up.Str|up.Null, "device_info", "system_version") + helper.Copy(up.Str|up.Null, "device_info", "app_version") + helper.Copy(up.Str|up.Null, "device_info", "system_lang_code") + helper.Copy(up.Str|up.Null, "device_info", "lang_code") helper.Copy(up.Str, "animated_sticker", "target") helper.Copy(up.Bool, "animated_sticker", "convert_from_webm") helper.Copy(up.Int, "animated_sticker", "args", "width") @@ -85,11 +102,11 @@ func (tg *TelegramConnector) GetConfig() (example string, data any, upgrader up. } func (tg *TelegramConnector) ValidateConfig() error { - if tg.Config.AppID == 0 { - return fmt.Errorf("app_id is required") + if tg.Config.APIID == 0 { + return fmt.Errorf("api_id is required") } - if tg.Config.AppHash == "" { - return fmt.Errorf("app_hash is required") + if tg.Config.APIHash == "" || tg.Config.APIHash == "tjyd5yge35lbodk1xwzw2jstp90k55qz" { + return fmt.Errorf("api_hash is required") } if !slices.Contains([]string{"disable", "gif", "png", "webp", "webm"}, tg.Config.AnimatedSticker.Target) { return fmt.Errorf("unsupported animated sticker target: %s", tg.Config.AnimatedSticker.Target) diff --git a/pkg/connector/example-config.yaml b/pkg/connector/example-config.yaml index 22798b51..b51d9466 100644 --- a/pkg/connector/example-config.yaml +++ b/pkg/connector/example-config.yaml @@ -1,6 +1,13 @@ # Get your own API keys at https://my.telegram.org/apps -app_id: 12345 -app_hash: tjyd5yge35lbodk1xwzw2jstp90k55qz +api_id: 12345 +api_hash: tjyd5yge35lbodk1xwzw2jstp90k55qz + +device_info: + device_model: mautrix-telegram + system_version: + app_version: auto + lang_code: en + system_lang_code: en # Settings for converting animated stickers. animated_sticker: diff --git a/pkg/connector/login.go b/pkg/connector/login.go index 4b451e99..38a7990d 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -98,7 +98,7 @@ func (p *PhoneLogin) Start(ctx context.Context) (*bridgev2.LoginStep, error) { func (p *PhoneLogin) SubmitUserInput(ctx context.Context, input map[string]string) (*bridgev2.LoginStep, error) { if phone, ok := input[phoneNumberStep]; ok { p.phone = phone - p.client = telegram.NewClient(p.main.Config.AppID, p.main.Config.AppHash, telegram.Options{ + p.client = telegram.NewClient(p.main.Config.APIID, p.main.Config.APIHash, telegram.Options{ CustomSessionStorage: &p.authData, Logger: zap.New(zerozap.New(zerolog.Ctx(ctx).With().Str("component", "telegram_login_client").Logger())), })