package tdesktop import ( "github.com/go-faster/errors" "github.com/gotd/td/bin" "github.com/gotd/td/internal/crypto" ) // MTPConfigEnvironment is enum of config environment. type MTPConfigEnvironment int32 func (e MTPConfigEnvironment) valid() bool { return e == 0 || e == 1 } // String implements fmt.Stringer. func (e MTPConfigEnvironment) String() string { switch e { case 0: return "production" case 1: return "test" default: return "unknown" } } // Test denotes that environment is test. func (e MTPConfigEnvironment) Test() bool { return e == 1 } // MTPConfig is a Telegram Desktop storage structure which stores MTProto config info. // // See https://github.com/telegramdesktop/tdesktop/blob/v2.9.8/Telegram/SourceFiles/mtproto/mtproto_config.h. type MTPConfig struct { Environment MTPConfigEnvironment DCOptions MTPDCOptions ChatSizeMax int32 // default: 200 MegagroupSizeMax int32 // default: 10000 ForwardedCountMax int32 // default: 100 OnlineUpdatePeriod int32 // default: 120000 OfflineBlurTimeout int32 // default: 5000 OfflineIdleTimeout int32 // default: 30000 OnlineFocusTimeout int32 // default: 1000 OnlineCloudTimeout int32 // default: 300000 NotifyCloudDelay int32 // default: 30000 NotifyDefaultDelay int32 // default: 1500 SavedGifsLimit int32 // default: 200 EditTimeLimit int32 // default: 172800 RevokeTimeLimit int32 // default: 172800 RevokePrivateTimeLimit int32 // default: 172800 RevokePrivateInbox bool // default: false StickersRecentLimit int32 // default: 30 StickersFavedLimit int32 // default: 5 PinnedDialogsCountMax int32 // default: 5 PinnedDialogsInFolderMax int32 // default: 100 InternalLinksDomain string // default: "https://t.me/" ChannelsReadMediaPeriod int32 // default: 86400 * 7 CallReceiveTimeoutMs int32 // default: 20000 CallRingTimeoutMs int32 // default: 90000 CallConnectTimeoutMs int32 // default: 30000 CallPacketTimeoutMs int32 // default: 10000 WebFileDCID int32 // default: 4 TxtDomainString string // default: "" PhoneCallsEnabled bool // default: true BlockedMode bool // default: false CaptionLengthMax int32 // default: 1024 } // See https://github.com/telegramdesktop/tdesktop/blob/v2.9.8/Telegram/SourceFiles/storage/storage_account.cpp#L938. func readMTPConfig(tgf *tdesktopFile, localKey crypto.Key) (MTPConfig, error) { encrypted, err := tgf.readArray() if err != nil { return MTPConfig{}, errors.Wrap(err, "read encrypted data") } decrypted, err := decryptLocal(encrypted, localKey) if err != nil { return MTPConfig{}, errors.Wrap(err, "decrypt data") } // Skip decrypted data length (uint32). decrypted = decrypted[4:] root := qtReader{buf: bin.Buffer{Buf: decrypted}} cfgReader, err := root.subArray() if err != nil { return MTPConfig{}, errors.Wrap(err, "read config array") } var m MTPConfig if err := m.deserialize(&cfgReader); err != nil { return MTPConfig{}, errors.Wrap(err, "deserialize MTPConfig") } return m, err } func (m *MTPConfig) deserialize(r *qtReader) error { version, err := r.readInt32() if err != nil { return errors.Wrap(err, "read version") } if version != kVersion { return errors.Errorf("wrong version (expected %d, got %d)", kVersion, version) } environment, err := r.readInt32() if err != nil { return errors.Wrap(err, "read environment") } m.Environment = MTPConfigEnvironment(environment) if !m.Environment.valid() { return errors.Errorf("invalid environment %d", environment) } { sub, err := r.subArray() if err != nil { return err } if err := m.DCOptions.deserialize(&sub); err != nil { return errors.Wrap(err, "read DC options") } } chatSizeMax, err := r.readInt32() if err != nil { return errors.Wrap(err, "read chatSizeMax") } m.ChatSizeMax = chatSizeMax megagroupSizeMax, err := r.readInt32() if err != nil { return errors.Wrap(err, "read megagroupSizeMax") } m.MegagroupSizeMax = megagroupSizeMax forwardedCountMax, err := r.readInt32() if err != nil { return errors.Wrap(err, "read forwardedCountMax") } m.ForwardedCountMax = forwardedCountMax onlineUpdatePeriod, err := r.readInt32() if err != nil { return errors.Wrap(err, "read onlineUpdatePeriod") } m.OnlineUpdatePeriod = onlineUpdatePeriod offlineBlurTimeout, err := r.readInt32() if err != nil { return errors.Wrap(err, "read offlineBlurTimeout") } m.OfflineBlurTimeout = offlineBlurTimeout offlineIdleTimeout, err := r.readInt32() if err != nil { return errors.Wrap(err, "read offlineIdleTimeout") } m.OfflineIdleTimeout = offlineIdleTimeout onlineFocusTimeout, err := r.readInt32() if err != nil { return errors.Wrap(err, "read onlineFocusTimeout") } m.OnlineFocusTimeout = onlineFocusTimeout onlineCloudTimeout, err := r.readInt32() if err != nil { return errors.Wrap(err, "read onlineCloudTimeout") } m.OnlineCloudTimeout = onlineCloudTimeout notifyCloudDelay, err := r.readInt32() if err != nil { return errors.Wrap(err, "read notifyCloudDelay") } m.NotifyCloudDelay = notifyCloudDelay notifyDefaultDelay, err := r.readInt32() if err != nil { return errors.Wrap(err, "read notifyDefaultDelay") } m.NotifyDefaultDelay = notifyDefaultDelay savedGifsLimit, err := r.readInt32() if err != nil { return errors.Wrap(err, "read savedGifsLimit") } m.SavedGifsLimit = savedGifsLimit editTimeLimit, err := r.readInt32() if err != nil { return errors.Wrap(err, "read editTimeLimit") } m.EditTimeLimit = editTimeLimit revokeTimeLimit, err := r.readInt32() if err != nil { return errors.Wrap(err, "read revokeTimeLimit") } m.RevokeTimeLimit = revokeTimeLimit revokePrivateTimeLimit, err := r.readInt32() if err != nil { return errors.Wrap(err, "read revokePrivateTimeLimit") } m.RevokePrivateTimeLimit = revokePrivateTimeLimit revokePrivateInbox, err := r.readUint32() if err != nil { return errors.Wrap(err, "read revokePrivateInbox") } m.RevokePrivateInbox = revokePrivateInbox == 1 stickersRecentLimit, err := r.readInt32() if err != nil { return errors.Wrap(err, "read stickersRecentLimit") } m.StickersRecentLimit = stickersRecentLimit stickersFavedLimit, err := r.readInt32() if err != nil { return errors.Wrap(err, "read stickersFavedLimit") } m.StickersFavedLimit = stickersFavedLimit pinnedDialogsCountMax, err := r.readInt32() if err != nil { return errors.Wrap(err, "read pinnedDialogsCountMax") } m.PinnedDialogsCountMax = pinnedDialogsCountMax pinnedDialogsInFolderMax, err := r.readInt32() if err != nil { return errors.Wrap(err, "read pinnedDialogsInFolderMax") } m.PinnedDialogsInFolderMax = pinnedDialogsInFolderMax internalLinksDomain, err := r.readString() if err != nil { return errors.Wrap(err, "read internalLinksDomain") } m.InternalLinksDomain = internalLinksDomain channelsReadMediaPeriod, err := r.readInt32() if err != nil { return errors.Wrap(err, "read channelsReadMediaPeriod") } m.ChannelsReadMediaPeriod = channelsReadMediaPeriod callReceiveTimeoutMs, err := r.readInt32() if err != nil { return errors.Wrap(err, "read callReceiveTimeoutMs") } m.CallReceiveTimeoutMs = callReceiveTimeoutMs callRingTimeoutMs, err := r.readInt32() if err != nil { return errors.Wrap(err, "read callRingTimeoutMs") } m.CallRingTimeoutMs = callRingTimeoutMs callConnectTimeoutMs, err := r.readInt32() if err != nil { return errors.Wrap(err, "read callConnectTimeoutMs") } m.CallConnectTimeoutMs = callConnectTimeoutMs callPacketTimeoutMs, err := r.readInt32() if err != nil { return errors.Wrap(err, "read callPacketTimeoutMs") } m.CallPacketTimeoutMs = callPacketTimeoutMs webFileDCID, err := r.readInt32() if err != nil { return errors.Wrap(err, "read webFileDCID") } m.WebFileDCID = webFileDCID txtDomainString, err := r.readString() if err != nil { return errors.Wrap(err, "read txtDomainString") } m.TxtDomainString = txtDomainString phoneCallsEnabled, err := r.readUint32() if err != nil { return errors.Wrap(err, "read phoneCallsEnabled") } m.PhoneCallsEnabled = phoneCallsEnabled == 1 blockedMode, err := r.readUint32() if err != nil { return errors.Wrap(err, "read blockedMode") } m.BlockedMode = blockedMode == 1 captionLengthMax, err := r.readInt32() if err != nil { return errors.Wrap(err, "read captionLengthMax") } m.CaptionLengthMax = captionLengthMax return nil }