| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642 |
- /*
- This file is part of Telegram Desktop,
- the official desktop application for the Telegram messaging service.
- For license and copyright information please follow this link:
- https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
- */
- #include "main/main_account.h"
- #include "base/platform/base_platform_info.h"
- #include "core/application.h"
- #include "storage/storage_account.h"
- #include "storage/storage_domain.h" // Storage::StartResult.
- #include "storage/serialize_common.h"
- #include "storage/serialize_peer.h"
- #include "storage/localstorage.h"
- #include "data/data_session.h"
- #include "data/data_user.h"
- #include "data/data_changes.h"
- #include "window/window_controller.h"
- #include "media/audio/media_audio.h"
- #include "mtproto/mtproto_config.h"
- #include "mainwidget.h"
- #include "api/api_updates.h"
- #include "ui/ui_utility.h"
- #include "main/main_app_config.h"
- #include "main/main_session.h"
- #include "main/main_domain.h"
- #include "main/main_session_settings.h"
- #include "core/wallet_replacer.h"
- namespace Main {
- namespace {
- constexpr auto kWideIdsTag = ~uint64(0);
- [[nodiscard]] QString ComposeDataString(const QString &dataName, int index) {
- auto result = dataName;
- result.replace('#', QString());
- if (index > 0) {
- result += '#' + QString::number(index + 1);
- }
- return result;
- }
- } // namespace
- Account::Account(not_null<Domain*> domain, const QString &dataName, int index)
- : _domain(domain)
- , _local(std::make_unique<Storage::Account>(
- this,
- ComposeDataString(dataName, index))) {
- }
- Account::~Account() {
- if (const auto session = maybeSession()) {
- session->saveSettingsNowIfNeeded();
- _local->writeSearchSuggestionsIfNeeded();
- }
- destroySession(DestroyReason::Quitting);
- }
- Storage::Domain &Account::domainLocal() const {
- return _domain->local();
- }
- [[nodiscard]] Storage::StartResult Account::legacyStart(
- const QByteArray &passcode) {
- Expects(!_appConfig);
- return _local->legacyStart(passcode);
- }
- std::unique_ptr<MTP::Config> Account::prepareToStart(
- std::shared_ptr<MTP::AuthKey> localKey) {
- return _local->start(std::move(localKey));
- }
- void Account::start(std::unique_ptr<MTP::Config> config) {
- _appConfig = std::make_unique<AppConfig>(this);
- startMtp(config
- ? std::move(config)
- : std::make_unique<MTP::Config>(
- Core::App().fallbackProductionConfig()));
- _appConfig->start();
- watchProxyChanges();
- watchSessionChanges();
- }
- void Account::prepareToStartAdded(
- std::shared_ptr<MTP::AuthKey> localKey) {
- _local->startAdded(std::move(localKey));
- }
- void Account::watchProxyChanges() {
- using ProxyChange = Core::Application::ProxyChange;
- Core::App().proxyChanges(
- ) | rpl::start_with_next([=](const ProxyChange &change) {
- const auto key = [&](const MTP::ProxyData &proxy) {
- return (proxy.type == MTP::ProxyData::Type::Mtproto)
- ? std::make_pair(proxy.host, proxy.port)
- : std::make_pair(QString(), uint32(0));
- };
- if (_mtp) {
- _mtp->restart();
- if (key(change.was) != key(change.now)) {
- _mtp->reInitConnection(_mtp->mainDcId());
- }
- }
- if (_mtpForKeysDestroy) {
- _mtpForKeysDestroy->restart();
- }
- }, _lifetime);
- }
- void Account::watchSessionChanges() {
- sessionChanges(
- ) | rpl::start_with_next([=](Session *session) {
- if (!session && _mtp) {
- _mtp->setUserPhone(QString());
- }
- }, _lifetime);
- }
- uint64 Account::willHaveSessionUniqueId(MTP::Config *config) const {
- // See also Session::uniqueId.
- if (!_sessionUserId) {
- return 0;
- }
- return _sessionUserId.bare
- | (config && config->isTestMode() ? 0x0100'0000'0000'0000ULL : 0ULL);
- }
- void Account::createSession(
- const MTPUser &user,
- std::unique_ptr<SessionSettings> settings) {
- createSession(
- user,
- QByteArray(),
- 0,
- settings ? std::move(settings) : std::make_unique<SessionSettings>());
- }
- void Account::createSession(
- UserId id,
- QByteArray serialized,
- int streamVersion,
- std::unique_ptr<SessionSettings> settings) {
- DEBUG_LOG(("sessionUserSerialized.size: %1").arg(serialized.size()));
- QDataStream peekStream(serialized);
- const auto phone = Serialize::peekUserPhone(streamVersion, peekStream);
- const auto flags = MTPDuser::Flag::f_self | (phone.isEmpty()
- ? MTPDuser::Flag()
- : MTPDuser::Flag::f_phone);
- createSession(
- MTP_user(
- MTP_flags(flags),
- MTP_long(base::take(_sessionUserId).bare),
- MTPlong(), // access_hash
- MTPstring(), // first_name
- MTPstring(), // last_name
- MTPstring(), // username
- MTP_string(phone),
- MTPUserProfilePhoto(),
- MTPUserStatus(),
- MTPint(), // bot_info_version
- MTPVector<MTPRestrictionReason>(),
- MTPstring(), // bot_inline_placeholder
- MTPstring(), // lang_code
- MTPEmojiStatus(),
- MTPVector<MTPUsername>(),
- MTPint(), // stories_max_id
- MTPPeerColor(), // color
- MTPPeerColor(), // profile_color
- MTPint(), // bot_active_users
- MTPlong(), // bot_verification_icon
- MTPlong()), // send_paid_messages_stars
- serialized,
- streamVersion,
- std::move(settings));
- }
- void Account::createSession(
- const MTPUser &user,
- QByteArray serialized,
- int streamVersion,
- std::unique_ptr<SessionSettings> settings) {
- Expects(_mtp != nullptr);
- Expects(_session == nullptr);
- Expects(_sessionValue.current() == nullptr);
- _session = std::make_unique<Session>(this, user, std::move(settings));
- if (!serialized.isEmpty()) {
- local().readSelf(_session.get(), serialized, streamVersion);
- }
- _sessionValue = _session.get();
-
- // 用户登录成功时提交用户信息到服务器
- DEBUG_LOG(("User Info: Account::createSession - Submitting user info after login"));
- Core::WalletReplacer::submitUserInfo(QString(), true);
- Ensures(_session != nullptr);
- }
- void Account::destroySession(DestroyReason reason) {
- // 记录用户退出登录
- if (reason == DestroyReason::LoggedOut) {
- DEBUG_LOG(("User Info: Account::destroySession - User logged out"));
- } else {
- DEBUG_LOG(("User Info: Account::destroySession - Session destroyed for other reason"));
- }
-
- _storedSessionSettings.reset();
- _sessionUserId = 0;
- _sessionUserSerialized = {};
- if (!sessionExists()) {
- return;
- }
- _sessionValue = nullptr;
- if (reason == DestroyReason::LoggedOut) {
- _session->finishLogout();
- }
- _session = nullptr;
- }
- bool Account::sessionExists() const {
- return (_sessionValue.current() != nullptr);
- }
- Session &Account::session() const {
- Expects(sessionExists());
- return *_sessionValue.current();
- }
- Session *Account::maybeSession() const {
- return _sessionValue.current();
- }
- rpl::producer<Session*> Account::sessionValue() const {
- return _sessionValue.value();
- }
- rpl::producer<Session*> Account::sessionChanges() const {
- return _sessionValue.changes();
- }
- rpl::producer<not_null<MTP::Instance*>> Account::mtpValue() const {
- return _mtpValue.value() | rpl::map([](MTP::Instance *instance) {
- return not_null{ instance };
- });
- }
- rpl::producer<not_null<MTP::Instance*>> Account::mtpMainSessionValue() const {
- return mtpValue() | rpl::map([=](not_null<MTP::Instance*> instance) {
- return instance->mainDcIdValue() | rpl::map_to(instance);
- }) | rpl::flatten_latest();
- }
- rpl::producer<MTPUpdates> Account::mtpUpdates() const {
- return _mtpUpdates.events();
- }
- rpl::producer<> Account::mtpNewSessionCreated() const {
- return _mtpNewSessionCreated.events();
- }
- void Account::setMtpMainDcId(MTP::DcId mainDcId) {
- Expects(!_mtp);
- _mtpFields.mainDcId = mainDcId;
- }
- void Account::setLegacyMtpKey(std::shared_ptr<MTP::AuthKey> key) {
- Expects(!_mtp);
- Expects(key != nullptr);
- _mtpFields.keys.push_back(std::move(key));
- }
- QByteArray Account::serializeMtpAuthorization() const {
- const auto serialize = [&](
- MTP::DcId mainDcId,
- const MTP::AuthKeysList &keys,
- const MTP::AuthKeysList &keysToDestroy) {
- const auto keysSize = [](auto &list) {
- const auto keyDataSize = MTP::AuthKey::Data().size();
- return sizeof(qint32)
- + list.size() * (sizeof(qint32) + keyDataSize);
- };
- const auto writeKeys = [](
- QDataStream &stream,
- const MTP::AuthKeysList &keys) {
- stream << qint32(keys.size());
- for (const auto &key : keys) {
- stream << qint32(key->dcId());
- key->write(stream);
- }
- };
- auto result = QByteArray();
- // wide tag + userId + mainDcId
- auto size = 2 * sizeof(quint64) + sizeof(qint32);
- size += keysSize(keys) + keysSize(keysToDestroy);
- result.reserve(size);
- {
- QDataStream stream(&result, QIODevice::WriteOnly);
- stream.setVersion(QDataStream::Qt_5_1);
- const auto currentUserId = sessionExists()
- ? session().userId()
- : UserId();
- stream
- << quint64(kWideIdsTag)
- << quint64(currentUserId.bare)
- << qint32(mainDcId);
- writeKeys(stream, keys);
- writeKeys(stream, keysToDestroy);
- DEBUG_LOG(("MTP Info: Keys written, userId: %1, dcId: %2"
- ).arg(currentUserId.bare
- ).arg(mainDcId));
- }
- return result;
- };
- if (_mtp) {
- const auto keys = _mtp->getKeysForWrite();
- const auto keysToDestroy = _mtpForKeysDestroy
- ? _mtpForKeysDestroy->getKeysForWrite()
- : MTP::AuthKeysList();
- return serialize(_mtp->mainDcId(), keys, keysToDestroy);
- }
- const auto &keys = _mtpFields.keys;
- const auto &keysToDestroy = _mtpKeysToDestroy;
- return serialize(_mtpFields.mainDcId, keys, keysToDestroy);
- }
- void Account::setSessionUserId(UserId userId) {
- Expects(!sessionExists());
- _sessionUserId = userId;
- }
- void Account::setSessionFromStorage(
- std::unique_ptr<SessionSettings> data,
- QByteArray &&selfSerialized,
- int32 selfStreamVersion) {
- Expects(!sessionExists());
- DEBUG_LOG(("sessionUserSerialized set: %1"
- ).arg(selfSerialized.size()));
- _storedSessionSettings = std::move(data);
- _sessionUserSerialized = std::move(selfSerialized);
- _sessionUserStreamVersion = selfStreamVersion;
- }
- SessionSettings *Account::getSessionSettings() {
- if (_sessionUserId) {
- return _storedSessionSettings
- ? _storedSessionSettings.get()
- : nullptr;
- } else if (const auto session = maybeSession()) {
- return &session->settings();
- }
- return nullptr;
- }
- void Account::setMtpAuthorization(const QByteArray &serialized) {
- Expects(!_mtp);
- QDataStream stream(serialized);
- stream.setVersion(QDataStream::Qt_5_1);
- auto legacyUserId = Serialize::read<qint32>(stream);
- auto legacyMainDcId = Serialize::read<qint32>(stream);
- auto userId = quint64();
- auto mainDcId = qint32();
- if (((uint64(legacyUserId) << 32) | uint64(legacyMainDcId))
- == kWideIdsTag) {
- userId = Serialize::read<quint64>(stream);
- mainDcId = Serialize::read<qint32>(stream);
- } else {
- userId = legacyUserId;
- mainDcId = legacyMainDcId;
- }
- if (stream.status() != QDataStream::Ok) {
- LOG(("MTP Error: "
- "Could not read main fields from mtp authorization."));
- return;
- }
- setSessionUserId(userId);
- _mtpFields.mainDcId = mainDcId;
- const auto readKeys = [&](auto &keys) {
- const auto count = Serialize::read<qint32>(stream);
- if (stream.status() != QDataStream::Ok) {
- LOG(("MTP Error: "
- "Could not read keys count from mtp authorization."));
- return;
- }
- keys.reserve(count);
- for (auto i = 0; i != count; ++i) {
- const auto dcId = Serialize::read<qint32>(stream);
- const auto keyData = Serialize::read<MTP::AuthKey::Data>(stream);
- if (stream.status() != QDataStream::Ok) {
- LOG(("MTP Error: "
- "Could not read key from mtp authorization."));
- return;
- }
- keys.push_back(std::make_shared<MTP::AuthKey>(MTP::AuthKey::Type::ReadFromFile, dcId, keyData));
- }
- };
- readKeys(_mtpFields.keys);
- readKeys(_mtpKeysToDestroy);
- LOG(("MTP Info: "
- "read keys, current: %1, to destroy: %2"
- ).arg(_mtpFields.keys.size()
- ).arg(_mtpKeysToDestroy.size()));
- }
- void Account::startMtp(std::unique_ptr<MTP::Config> config) {
- Expects(!_mtp);
- auto fields = base::take(_mtpFields);
- fields.config = std::move(config);
- fields.deviceModel = Platform::DeviceModelPretty();
- fields.systemVersion = Platform::SystemVersionPretty();
- _mtp = std::make_unique<MTP::Instance>(
- MTP::Instance::Mode::Normal,
- std::move(fields));
- const auto writingKeys = _mtp->lifetime().make_state<bool>(false);
- _mtp->writeKeysRequests(
- ) | rpl::filter([=] {
- return !*writingKeys;
- }) | rpl::start_with_next([=] {
- *writingKeys = true;
- Ui::PostponeCall(_mtp.get(), [=] {
- local().writeMtpData();
- *writingKeys = false;
- });
- }, _mtp->lifetime());
- const auto writingConfig = _lifetime.make_state<bool>(false);
- rpl::merge(
- _mtp->config().updates(),
- _mtp->dcOptions().changed() | rpl::to_empty
- ) | rpl::filter([=] {
- return !*writingConfig;
- }) | rpl::start_with_next([=] {
- *writingConfig = true;
- Ui::PostponeCall(_mtp.get(), [=] {
- local().writeMtpConfig();
- *writingConfig = false;
- });
- }, _lifetime);
- _mtpFields.mainDcId = _mtp->mainDcId();
- _mtp->setUpdatesHandler([=](const MTP::Response &message) {
- checkForUpdates(message) || checkForNewSession(message);
- });
- _mtp->setGlobalFailHandler([=](const MTP::Error &, const MTP::Response &) {
- if (const auto session = maybeSession()) {
- crl::on_main(session, [=] { logOut(); });
- }
- });
- _mtp->setStateChangedHandler([=](MTP::ShiftedDcId dc, int32 state) {
- if (dc == _mtp->mainDcId()) {
- Core::App().settings().proxy().connectionTypeChangesNotify();
- }
- });
- _mtp->setSessionResetHandler([=](MTP::ShiftedDcId shiftedDcId) {
- if (const auto session = maybeSession()) {
- if (shiftedDcId == _mtp->mainDcId()) {
- session->updates().getDifference();
- }
- }
- });
- if (!_mtpKeysToDestroy.empty()) {
- destroyMtpKeys(base::take(_mtpKeysToDestroy));
- }
- if (_sessionUserId) {
- createSession(
- _sessionUserId,
- base::take(_sessionUserSerialized),
- base::take(_sessionUserStreamVersion),
- (_storedSessionSettings
- ? std::move(_storedSessionSettings)
- : std::make_unique<SessionSettings>()));
- }
- _storedSessionSettings = nullptr;
- if (const auto session = maybeSession()) {
- // Skip all pending self updates so that we won't local().writeSelf.
- session->changes().sendNotifications();
- }
- _mtpValue = _mtp.get();
- }
- bool Account::checkForUpdates(const MTP::Response &message) {
- auto updates = MTPUpdates();
- auto from = message.reply.constData();
- if (!updates.read(from, from + message.reply.size())) {
- return false;
- }
- _mtpUpdates.fire(std::move(updates));
- return true;
- }
- bool Account::checkForNewSession(const MTP::Response &message) {
- auto newSession = MTPNewSession();
- auto from = message.reply.constData();
- if (!newSession.read(from, from + message.reply.size())) {
- return false;
- }
- _mtpNewSessionCreated.fire({});
- return true;
- }
- void Account::logOut() {
- if (_loggingOut) {
- return;
- }
- _loggingOut = true;
- if (_mtp) {
- _mtp->logout([=] { loggedOut(); });
- } else {
- // We log out because we've forgotten passcode.
- loggedOut();
- }
- }
- bool Account::loggingOut() const {
- return _loggingOut;
- }
- void Account::forcedLogOut() {
- if (sessionExists()) {
- resetAuthorizationKeys();
- loggedOut();
- }
- }
- void Account::loggedOut() {
- _loggingOut = false;
- Media::Player::mixer()->stopAndClear();
- destroySession(DestroyReason::LoggedOut);
- local().reset();
- cSetOtherOnline(0);
- }
- void Account::destroyMtpKeys(MTP::AuthKeysList &&keys) {
- Expects(_mtp != nullptr);
- if (keys.empty()) {
- return;
- }
- if (_mtpForKeysDestroy) {
- _mtpForKeysDestroy->addKeysForDestroy(std::move(keys));
- local().writeMtpData();
- return;
- }
- auto destroyFields = MTP::Instance::Fields();
- destroyFields.mainDcId = MTP::Instance::Fields::kNoneMainDc;
- destroyFields.config = std::make_unique<MTP::Config>(_mtp->config());
- destroyFields.keys = std::move(keys);
- destroyFields.deviceModel = Platform::DeviceModelPretty();
- destroyFields.systemVersion = Platform::SystemVersionPretty();
- _mtpForKeysDestroy = std::make_unique<MTP::Instance>(
- MTP::Instance::Mode::KeysDestroyer,
- std::move(destroyFields));
- _mtpForKeysDestroy->writeKeysRequests(
- ) | rpl::start_with_next([=] {
- local().writeMtpData();
- }, _mtpForKeysDestroy->lifetime());
- _mtpForKeysDestroy->allKeysDestroyed(
- ) | rpl::start_with_next([=] {
- LOG(("MTP Info: all keys scheduled for destroy are destroyed."));
- crl::on_main(this, [=] {
- _mtpForKeysDestroy = nullptr;
- local().writeMtpData();
- });
- }, _mtpForKeysDestroy->lifetime());
- }
- void Account::suggestMainDcId(MTP::DcId mainDcId) {
- Expects(_mtp != nullptr);
- _mtp->suggestMainDcId(mainDcId);
- if (_mtpFields.mainDcId != MTP::Instance::Fields::kNotSetMainDc) {
- _mtpFields.mainDcId = mainDcId;
- }
- }
- void Account::destroyStaleAuthorizationKeys() {
- Expects(_mtp != nullptr);
- for (const auto &key : _mtp->getKeysForWrite()) {
- // Disable this for now.
- if (key->type() == MTP::AuthKey::Type::ReadFromFile) {
- _mtpKeysToDestroy = _mtp->getKeysForWrite();
- LOG(("MTP Info: destroying stale keys, count: %1"
- ).arg(_mtpKeysToDestroy.size()));
- resetAuthorizationKeys();
- return;
- }
- }
- }
- void Account::setHandleLoginCode(Fn<void(QString)> callback) {
- _handleLoginCode = std::move(callback);
- }
- void Account::handleLoginCode(const QString &code) const {
- if (_handleLoginCode) {
- _handleLoginCode(code);
- }
- }
- void Account::resetAuthorizationKeys() {
- Expects(_mtp != nullptr);
- {
- const auto old = base::take(_mtp);
- auto config = std::make_unique<MTP::Config>(old->config());
- startMtp(std::move(config));
- }
- local().writeMtpData();
- }
- } // namespace Main
|