mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +02:00
Allow several accounts in Core::App.
This commit is contained in:
parent
815e26eea5
commit
6fc5e22882
36 changed files with 834 additions and 267 deletions
|
@ -668,6 +668,8 @@ PRIVATE
|
|||
lang/lang_values.h
|
||||
main/main_account.cpp
|
||||
main/main_account.h
|
||||
main/main_accounts.cpp
|
||||
main/main_accounts.h
|
||||
main/main_app_config.cpp
|
||||
main/main_app_config.h
|
||||
main/main_session.cpp
|
||||
|
@ -912,6 +914,8 @@ PRIVATE
|
|||
storage/serialize_document.h
|
||||
storage/storage_account.cpp
|
||||
storage/storage_account.h
|
||||
storage/storage_accounts.cpp
|
||||
storage/storage_accounts.h
|
||||
storage/storage_cloud_blob.cpp
|
||||
storage/storage_cloud_blob.h
|
||||
storage/storage_facade.cpp
|
||||
|
|
|
@ -14,8 +14,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "mainwindow.h"
|
||||
#include "apiwrap.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_accounts.h"
|
||||
#include "core/application.h"
|
||||
#include "storage/storage_account.h"
|
||||
#include "storage/storage_accounts.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
|
@ -451,7 +452,7 @@ void PasscodeBox::save(bool force) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (_session->local().checkPasscode(old.toUtf8())) {
|
||||
if (Core::App().accounts().local().checkPasscode(old.toUtf8())) {
|
||||
cSetPasscodeBadTries(0);
|
||||
if (_turningOff) pwd = conf = QString();
|
||||
} else {
|
||||
|
@ -519,7 +520,7 @@ void PasscodeBox::save(bool force) {
|
|||
closeReplacedBy();
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
cSetPasscodeBadTries(0);
|
||||
_session->local().setPasscode(pwd.toUtf8());
|
||||
Core::App().accounts().local().setPasscode(pwd.toUtf8());
|
||||
Core::App().localPasscodeChanged();
|
||||
if (weak) {
|
||||
closeBox();
|
||||
|
|
|
@ -315,7 +315,7 @@ Panel::Panel(not_null<Call*> call)
|
|||
_cancel->setDuration(st::callPanelDuration);
|
||||
|
||||
setMouseTracking(true);
|
||||
setWindowIcon(Window::CreateIcon(&_user->account()));
|
||||
setWindowIcon(Window::CreateIcon(&_user->session()));
|
||||
initControls();
|
||||
initLayout();
|
||||
showAndActivate();
|
||||
|
|
|
@ -13,7 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "core/application.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_accounts.h"
|
||||
#include "main/main_session.h"
|
||||
#include "apiwrap.h"
|
||||
|
||||
|
@ -516,7 +516,7 @@ void EmojiKeywords::langPackRefreshed() {
|
|||
}
|
||||
|
||||
void EmojiKeywords::handleSessionChanges() {
|
||||
Core::App().activeAccount().sessionValue( // #TODO multi someSessionValue
|
||||
Core::App().accounts().activeSessionValue( // #TODO multi someSessionValue
|
||||
) | rpl::map([](Main::Session *session) {
|
||||
return session ? &session->api() : nullptr;
|
||||
}) | rpl::start_with_next([=](ApiWrap *api) {
|
||||
|
|
|
@ -21,13 +21,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "core/launcher.h"
|
||||
#include "core/ui_integration.h"
|
||||
#include "chat_helpers/emoji_keywords.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "platform/platform_specific.h"
|
||||
#include "mainwindow.h"
|
||||
#include "dialogs/dialogs_entry.h"
|
||||
#include "history/history.h"
|
||||
#include "main/main_session.h"
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_updates.h"
|
||||
#include "calls/calls_instance.h"
|
||||
|
@ -35,10 +33,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "lang/lang_translator.h"
|
||||
#include "lang/lang_cloud_manager.h"
|
||||
#include "lang/lang_hardcoded.h"
|
||||
#include "storage/storage_databases.h"
|
||||
#include "mainwidget.h"
|
||||
#include "core/file_utilities.h"
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_accounts.h"
|
||||
#include "main/main_session.h"
|
||||
#include "media/view/media_view_overlay_widget.h"
|
||||
#include "mtproto/dc_options.h"
|
||||
#include "mtproto/mtp_instance.h"
|
||||
|
@ -56,7 +55,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/emoji_config.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "storage/serialize_common.h"
|
||||
#include "storage/storage_account.h"
|
||||
#include "storage/storage_accounts.h"
|
||||
#include "storage/storage_databases.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "base/qthelp_regex.h"
|
||||
|
@ -95,7 +96,7 @@ Application::Application(not_null<Launcher*> launcher)
|
|||
, _databases(std::make_unique<Storage::Databases>())
|
||||
, _animationsManager(std::make_unique<Ui::Animations::Manager>())
|
||||
, _dcOptions(std::make_unique<MTP::DcOptions>())
|
||||
, _account(std::make_unique<Main::Account>(cDataFile()))
|
||||
, _accounts(std::make_unique<Main::Accounts>(cDataFile()))
|
||||
, _langpack(std::make_unique<Lang::Instance>())
|
||||
, _langCloudManager(std::make_unique<Lang::CloudManager>(langpack()))
|
||||
, _emojiKeywords(std::make_unique<ChatHelpers::EmojiKeywords>())
|
||||
|
@ -113,22 +114,22 @@ Application::Application(not_null<Launcher*> launcher)
|
|||
_shouldLockAt = 0;
|
||||
}, _lifetime);
|
||||
|
||||
activeAccount().sessionChanges( // #TODO multi activeSessionValue
|
||||
accounts().activeSessionChanges(
|
||||
) | rpl::start_with_next([=](Main::Session *session) {
|
||||
if (_mediaView) {
|
||||
hideMediaView();
|
||||
_mediaView->clearData();
|
||||
}
|
||||
if (session && !UpdaterDisabled()) { // #TODO multi someSessionValue
|
||||
UpdateChecker().setMtproto(session);
|
||||
}
|
||||
}, _lifetime);
|
||||
|
||||
activeAccount().mtpChanges(
|
||||
accounts().activeValue(
|
||||
) | rpl::map([=](Main::Account *account) {
|
||||
return account ? account->mtpValue() : rpl::never<MTP::Instance*>();
|
||||
}) | rpl::flatten_latest(
|
||||
) | rpl::filter([=](MTP::Instance *instance) {
|
||||
return instance != nullptr;
|
||||
}) | rpl::start_with_next([=] {
|
||||
if (_window) {
|
||||
// Global::DesktopNotify is used in updateTrayMenu.
|
||||
// This should be called when user settings are read.
|
||||
// Right now after they are read the startMtp() is called.
|
||||
_window->widget()->updateTrayMenu();
|
||||
|
@ -137,7 +138,11 @@ Application::Application(not_null<Launcher*> launcher)
|
|||
}
|
||||
|
||||
Application::~Application() {
|
||||
// Depend on activeWindow() for now :(
|
||||
Shortcuts::Finish();
|
||||
|
||||
_window.reset();
|
||||
|
||||
if (_mediaView) {
|
||||
_mediaView->clearData();
|
||||
_mediaView = nullptr;
|
||||
|
@ -224,7 +229,7 @@ void Application::run() {
|
|||
// Create mime database, so it won't be slow later.
|
||||
QMimeDatabase().mimeTypeForName(qsl("text/plain"));
|
||||
|
||||
_window = std::make_unique<Window::Controller>(&activeAccount());
|
||||
_window = std::make_unique<Window::Controller>();
|
||||
|
||||
QCoreApplication::instance()->installEventFilter(this);
|
||||
connect(
|
||||
|
@ -235,24 +240,19 @@ void Application::run() {
|
|||
|
||||
DEBUG_LOG(("Application Info: window created..."));
|
||||
|
||||
// Depend on activeWindow() for now :(
|
||||
startShortcuts();
|
||||
|
||||
App::initMedia();
|
||||
|
||||
const auto state = activeAccount().local().start(QByteArray());
|
||||
const auto state = accounts().start(QByteArray());
|
||||
if (state == Storage::StartResult::IncorrectPasscode) {
|
||||
Global::SetLocalPasscode(true);
|
||||
Global::RefLocalPasscodeChanged().notify();
|
||||
lockByPasscode();
|
||||
DEBUG_LOG(("Application Info: passcode needed..."));
|
||||
} else {
|
||||
DEBUG_LOG(("Application Info: local map read..."));
|
||||
activeAccount().startMtp();
|
||||
DEBUG_LOG(("Application Info: MTP started..."));
|
||||
if (activeAccount().sessionExists()) {
|
||||
_window->setupMain();
|
||||
} else {
|
||||
_window->setupIntro();
|
||||
}
|
||||
_window->showAccount(&activeAccount());
|
||||
}
|
||||
|
||||
_window->widget()->show();
|
||||
|
@ -552,6 +552,10 @@ void Application::writeInstallBetaVersionsSetting() {
|
|||
_launcher->writeInstallBetaVersionsSetting();
|
||||
}
|
||||
|
||||
Main::Account &Application::activeAccount() const {
|
||||
return _accounts->active();
|
||||
}
|
||||
|
||||
bool Application::exportPreventsQuit() {
|
||||
if (!activeAccount().sessionExists()
|
||||
|| !activeAccount().session().data().exportInProgress()) {
|
||||
|
@ -564,25 +568,28 @@ bool Application::exportPreventsQuit() {
|
|||
}
|
||||
|
||||
int Application::unreadBadge() const {
|
||||
return activeAccount().sessionExists()
|
||||
return (accounts().started() && activeAccount().sessionExists())
|
||||
? activeAccount().session().data().unreadBadge()
|
||||
: 0;
|
||||
}
|
||||
|
||||
bool Application::unreadBadgeMuted() const {
|
||||
return activeAccount().sessionExists()
|
||||
return (accounts().started() && activeAccount().sessionExists())
|
||||
? activeAccount().session().data().unreadBadgeMuted()
|
||||
: false;
|
||||
}
|
||||
|
||||
bool Application::offerLegacyLangPackSwitch() const {
|
||||
// #TODO multi we offer only if we were upgraded from an old authed app.
|
||||
return activeAccount().sessionExists();
|
||||
return (accounts().list().size() == 1) && activeAccount().sessionExists();
|
||||
}
|
||||
|
||||
bool Application::canApplyLangPackWithoutRestart() const {
|
||||
// #TODO multi we can't if at least one account is authorized.
|
||||
return !activeAccount().sessionExists();
|
||||
for (const auto &[index, account] : accounts().list()) {
|
||||
if (account->sessionExists()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Application::setInternalLinkDomain(const QString &domain) const {
|
||||
|
@ -674,10 +681,6 @@ void Application::lockByPasscode() {
|
|||
|
||||
void Application::unlockPasscode() {
|
||||
clearPasscodeLock();
|
||||
if (!activeAccount().mtp()) {
|
||||
// We unlocked initial passcode, so we just start mtproto.
|
||||
activeAccount().startMtp();
|
||||
}
|
||||
if (_window) {
|
||||
_window->clearPasscodeLock();
|
||||
}
|
||||
|
@ -720,10 +723,20 @@ void Application::lockByTerms(const Window::TermsLock &data) {
|
|||
}
|
||||
}
|
||||
|
||||
bool Application::someSessionExists() const {
|
||||
const auto &list = _accounts->list();
|
||||
for (const auto &[index, account] : list) {
|
||||
if (account->sessionExists()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Application::checkAutoLock() {
|
||||
if (!Global::LocalPasscode()
|
||||
|| passcodeLocked()
|
||||
|| !_account->sessionExists()) {
|
||||
|| !someSessionExists()) {
|
||||
_shouldLockAt = 0;
|
||||
_autoLockTimer.cancel();
|
||||
return;
|
||||
|
@ -949,6 +962,13 @@ void Application::quitDelayed() {
|
|||
void Application::startShortcuts() {
|
||||
Shortcuts::Start();
|
||||
|
||||
_accounts->activeSessionChanges(
|
||||
) | rpl::start_with_next([=](Main::Session *session) {
|
||||
const auto support = session && session->supportMode();
|
||||
Shortcuts::ToggleSupportShortcuts(support);
|
||||
Platform::SetApplicationIcon(Window::CreateIcon(session));
|
||||
}, _lifetime);
|
||||
|
||||
Shortcuts::Requests(
|
||||
) | rpl::start_with_next([=](not_null<Shortcuts::Request*> request) {
|
||||
using Command = Shortcuts::Command;
|
||||
|
|
|
@ -36,6 +36,7 @@ void quit();
|
|||
} // namespace App
|
||||
|
||||
namespace Main {
|
||||
class Accounts;
|
||||
class Account;
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
@ -150,10 +151,12 @@ public:
|
|||
return *_databases;
|
||||
}
|
||||
|
||||
// Account component.
|
||||
[[nodiscard]] Main::Account &activeAccount() const {
|
||||
return *_account;
|
||||
// Accounts component.
|
||||
[[nodiscard]] Main::Accounts &accounts() const {
|
||||
return *_accounts;
|
||||
}
|
||||
[[nodiscard]] Main::Account &activeAccount() const;
|
||||
[[nodiscard]] bool someSessionExists() const;
|
||||
[[nodiscard]] bool exportPreventsQuit();
|
||||
|
||||
// Main::Session component.
|
||||
|
@ -278,7 +281,7 @@ private:
|
|||
const std::unique_ptr<Storage::Databases> _databases;
|
||||
const std::unique_ptr<Ui::Animations::Manager> _animationsManager;
|
||||
const std::unique_ptr<MTP::DcOptions> _dcOptions;
|
||||
const std::unique_ptr<Main::Account> _account;
|
||||
const std::unique_ptr<Main::Accounts> _accounts;
|
||||
std::unique_ptr<Window::Controller> _window;
|
||||
std::unique_ptr<Media::View::OverlayWidget> _mediaView;
|
||||
const std::unique_ptr<Lang::Instance> _langpack;
|
||||
|
|
|
@ -7,9 +7,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "core/changelogs.h"
|
||||
|
||||
#include "storage/storage_account.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "core/application.h"
|
||||
#include "main/main_accounts.h"
|
||||
#include "main/main_session.h"
|
||||
#include "storage/storage_accounts.h"
|
||||
#include "data/data_session.h"
|
||||
#include "mainwindow.h"
|
||||
#include "apiwrap.h"
|
||||
|
@ -80,7 +82,9 @@ Changelogs::Changelogs(not_null<Main::Session*> session, int oldVersion)
|
|||
|
||||
std::unique_ptr<Changelogs> Changelogs::Create(
|
||||
not_null<Main::Session*> session) {
|
||||
const auto oldVersion = session->local().oldMapVersion();
|
||||
auto &local = Core::App().accounts().local();
|
||||
const auto oldVersion = local.oldVersion();
|
||||
local.clearOldVersion();
|
||||
return (oldVersion > 0 && oldVersion < AppVersion)
|
||||
? std::make_unique<Changelogs>(session, oldVersion)
|
||||
: nullptr;
|
||||
|
|
|
@ -248,7 +248,6 @@ void CodeWidget::codeSubmitDone(const MTPauth_Authorization &result) {
|
|||
showError(rpl::single(Lang::Hard::ServerError()));
|
||||
return;
|
||||
}
|
||||
cSetLoggedPhoneNumber(getData()->phone);
|
||||
finish(data.vuser());
|
||||
}, [&](const MTPDauth_authorizationSignUpRequired &data) {
|
||||
if (const auto terms = data.vterms_of_service()) {
|
||||
|
|
|
@ -373,8 +373,6 @@ void QrWidget::done(const MTPauth_Authorization &authorization) {
|
|||
showError(rpl::single(Lang::Hard::ServerError()));
|
||||
return;
|
||||
}
|
||||
const auto phone = data.vuser().c_user().vphone().value_or_empty();
|
||||
cSetLoggedPhoneNumber(phone);
|
||||
finish(data.vuser());
|
||||
}, [&](const MTPDauth_authorizationSignUpRequired &data) {
|
||||
_requestId = 0;
|
||||
|
|
|
@ -13,8 +13,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "mtproto/mtp_instance.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "core/application.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_accounts.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/wrap/padding_wrap.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
|
@ -158,7 +158,10 @@ Language ParseLanguage(const MTPLangPackLanguage &data) {
|
|||
|
||||
CloudManager::CloudManager(Instance &langpack)
|
||||
: _langpack(langpack) {
|
||||
Core::App().activeAccount().mtpValue( // #TODO multi activeAccountValue
|
||||
Core::App().accounts().activeValue(
|
||||
) | rpl::map([=](Main::Account *account) {
|
||||
return account ? account->mtpValue() : rpl::never<MTP::Instance*>();
|
||||
}) | rpl::flatten_latest(
|
||||
) | rpl::start_with_next([=](MTP::Instance *instance) {
|
||||
if (instance) {
|
||||
_api.emplace(instance);
|
||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "core/launcher.h"
|
||||
#include "core/shortcuts.h"
|
||||
#include "storage/storage_account.h"
|
||||
#include "storage/storage_accounts.h" // Storage::StartResult.
|
||||
#include "storage/serialize_common.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "data/data_session.h"
|
||||
|
@ -26,16 +27,49 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "facades.h"
|
||||
|
||||
namespace Main {
|
||||
namespace {
|
||||
|
||||
Account::Account(const QString &dataName)
|
||||
: _local(std::make_unique<Storage::Account>(this, dataName))
|
||||
, _appConfig(std::make_unique<AppConfig>(this)) {
|
||||
watchProxyChanges();
|
||||
watchSessionChanges();
|
||||
[[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(const QString &dataName, int index)
|
||||
: _local(std::make_unique<Storage::Account>(
|
||||
this,
|
||||
ComposeDataString(dataName, index))) {
|
||||
}
|
||||
|
||||
Account::~Account() = default;
|
||||
|
||||
[[nodiscard]] Storage::StartResult Account::legacyStart(
|
||||
const QByteArray &passcode) {
|
||||
Expects(!_appConfig);
|
||||
|
||||
const auto result = _local->legacyStart(passcode);
|
||||
if (result == Storage::StartResult::Success) {
|
||||
finishStarting();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Account::start(std::shared_ptr<MTP::AuthKey> localKey) {
|
||||
_local->start(std::move(localKey));
|
||||
finishStarting();
|
||||
}
|
||||
|
||||
void Account::finishStarting() {
|
||||
_appConfig = std::make_unique<AppConfig>(this);
|
||||
watchProxyChanges();
|
||||
watchSessionChanges();
|
||||
}
|
||||
|
||||
void Account::watchProxyChanges() {
|
||||
using ProxyChange = Core::Application::ProxyChange;
|
||||
|
||||
|
@ -60,28 +94,17 @@ void Account::watchProxyChanges() {
|
|||
|
||||
void Account::watchSessionChanges() {
|
||||
sessionChanges(
|
||||
) | rpl::start_with_next([=] {
|
||||
crl::on_main(this, [=] {
|
||||
const auto phone = sessionExists()
|
||||
? session().user()->phone()
|
||||
: QString();
|
||||
const auto support = sessionExists() && session().supportMode();
|
||||
if (cLoggedPhoneNumber() != phone) {
|
||||
cSetLoggedPhoneNumber(phone);
|
||||
if (_mtp) {
|
||||
_mtp->setUserPhone(phone);
|
||||
}
|
||||
Local::writeSettings();
|
||||
}
|
||||
if (_mtp) {
|
||||
_mtp->requestConfig();
|
||||
}
|
||||
Shortcuts::ToggleSupportShortcuts(support);
|
||||
Platform::SetApplicationIcon(Window::CreateIcon(this));
|
||||
});
|
||||
) | rpl::start_with_next([=](Session *session) {
|
||||
if (!session && _mtp) {
|
||||
_mtp->setUserPhone(QString());
|
||||
}
|
||||
}, _lifetime);
|
||||
}
|
||||
|
||||
UserId Account::willHaveUserId() const {
|
||||
return _sessionUserId;
|
||||
}
|
||||
|
||||
void Account::createSession(const MTPUser &user) {
|
||||
createSession(user, QByteArray(), 0, Settings());
|
||||
}
|
||||
|
@ -330,7 +353,6 @@ void Account::startMtp() {
|
|||
Core::App().dcOptions(),
|
||||
MTP::Instance::Mode::Normal,
|
||||
std::move(config));
|
||||
_mtp->setUserPhone(cLoggedPhoneNumber());
|
||||
_mtp->writeKeysRequests(
|
||||
) | rpl::start_with_next([=] {
|
||||
local().writeMtpData();
|
||||
|
|
|
@ -13,8 +13,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
namespace Storage {
|
||||
class Account;
|
||||
enum class StartResult : uchar;
|
||||
} // namespace Storage
|
||||
|
||||
namespace MTP {
|
||||
class AuthKey;
|
||||
} // namespace MTP
|
||||
|
||||
namespace Main {
|
||||
|
||||
class Session;
|
||||
|
@ -23,12 +28,17 @@ class AppConfig;
|
|||
|
||||
class Account final : public base::has_weak_ptr {
|
||||
public:
|
||||
explicit Account(const QString &dataName);
|
||||
Account(const QString &dataName, int index);
|
||||
~Account();
|
||||
|
||||
Account(const Account &other) = delete;
|
||||
Account &operator=(const Account &other) = delete;
|
||||
|
||||
[[nodiscard]] Storage::StartResult legacyStart(
|
||||
const QByteArray &passcode);
|
||||
void start(std::shared_ptr<MTP::AuthKey> localKey);
|
||||
|
||||
[[nodiscard]] UserId willHaveUserId() const;
|
||||
void createSession(const MTPUser &user);
|
||||
void createSession(
|
||||
UserId id,
|
||||
|
@ -41,8 +51,11 @@ public:
|
|||
void forcedLogOut();
|
||||
|
||||
[[nodiscard]] AppConfig &appConfig() const {
|
||||
Expects(_appConfig != nullptr);
|
||||
|
||||
return *_appConfig;
|
||||
}
|
||||
|
||||
[[nodiscard]] Storage::Account &local() const {
|
||||
return *_local;
|
||||
}
|
||||
|
@ -87,6 +100,7 @@ private:
|
|||
QByteArray serialized,
|
||||
int streamVersion,
|
||||
Settings &&settings);
|
||||
void finishStarting();
|
||||
void watchProxyChanges();
|
||||
void watchSessionChanges();
|
||||
bool checkForUpdates(const mtpPrime *from, const mtpPrime *end);
|
||||
|
|
112
Telegram/SourceFiles/main/main_accounts.cpp
Normal file
112
Telegram/SourceFiles/main/main_accounts.cpp
Normal file
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
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_accounts.h"
|
||||
|
||||
#include "core/application.h"
|
||||
#include "core/shortcuts.h"
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_session.h"
|
||||
#include "storage/storage_accounts.h"
|
||||
#include "storage/localstorage.h"
|
||||
|
||||
namespace Main {
|
||||
|
||||
Accounts::Accounts(const QString &dataName)
|
||||
: _dataName(dataName)
|
||||
, _local(std::make_unique<Storage::Accounts>(this, dataName)) {
|
||||
}
|
||||
|
||||
Accounts::~Accounts() = default;
|
||||
|
||||
bool Accounts::started() const {
|
||||
return !_accounts.empty();
|
||||
}
|
||||
|
||||
Storage::StartResult Accounts::start(const QByteArray &passcode) {
|
||||
Expects(!started());
|
||||
|
||||
auto active = -1;
|
||||
const auto callback = [&](int index, std::unique_ptr<Account> account) {
|
||||
Expects(account != nullptr);
|
||||
Expects(!_accounts.contains(index));
|
||||
|
||||
if (_accounts.empty()) {
|
||||
active = index;
|
||||
}
|
||||
_accounts.emplace(index, std::move(account));
|
||||
};
|
||||
const auto result = _local->start(passcode, callback);
|
||||
if (result == Storage::StartResult::Success) {
|
||||
Assert(started());
|
||||
|
||||
activate(active);
|
||||
|
||||
for (const auto &[index, account] : _accounts) {
|
||||
account->startMtp();
|
||||
}
|
||||
if (Local::oldSettingsVersion() < AppVersion) {
|
||||
Local::writeSettings();
|
||||
}
|
||||
} else {
|
||||
Assert(!started());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const base::flat_map<int, std::unique_ptr<Account>> &Accounts::list() const {
|
||||
return _accounts;
|
||||
}
|
||||
|
||||
rpl::producer<Account*> Accounts::activeValue() const {
|
||||
return _active.value();
|
||||
}
|
||||
|
||||
Account &Accounts::active() const {
|
||||
Expects(!_accounts.empty());
|
||||
|
||||
Ensures(_active.current() != nullptr);
|
||||
return *_active.current();
|
||||
}
|
||||
|
||||
rpl::producer<not_null<Account*>> Accounts::activeChanges() const {
|
||||
return _active.changes() | rpl::map([](Account *value) {
|
||||
return not_null{ value };
|
||||
});
|
||||
}
|
||||
|
||||
rpl::producer<Session*> Accounts::activeSessionChanges() const {
|
||||
return _activeSessions.events();
|
||||
}
|
||||
|
||||
rpl::producer<Session*> Accounts::activeSessionValue() const {
|
||||
const auto current = (_accounts.empty() || !active().sessionExists())
|
||||
? nullptr
|
||||
: &active().session();
|
||||
return rpl::single(current) | rpl::then(_activeSessions.events());
|
||||
}
|
||||
|
||||
int Accounts::add() {
|
||||
auto index = 0;
|
||||
while (_accounts.contains(index)) {
|
||||
++index;
|
||||
}
|
||||
_accounts.emplace(index, std::make_unique<Account>(_dataName, index));
|
||||
return index;
|
||||
}
|
||||
|
||||
void Accounts::activate(int index) {
|
||||
Expects(_accounts.contains(index));
|
||||
|
||||
_activeLifetime.destroy();
|
||||
_activeIndex = index;
|
||||
_active = _accounts.find(index)->second.get();
|
||||
_active.current()->sessionValue(
|
||||
) | rpl::start_to_stream(_activeSessions, _activeLifetime);
|
||||
}
|
||||
|
||||
} // namespace Main
|
61
Telegram/SourceFiles/main/main_accounts.h
Normal file
61
Telegram/SourceFiles/main/main_accounts.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
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
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace Storage {
|
||||
class Accounts;
|
||||
enum class StartResult : uchar;
|
||||
} // namespace Storage
|
||||
|
||||
namespace Main {
|
||||
|
||||
class Account;
|
||||
class Session;
|
||||
|
||||
class Accounts final {
|
||||
public:
|
||||
explicit Accounts(const QString &dataName);
|
||||
~Accounts();
|
||||
|
||||
[[nodiscard]] bool started() const;
|
||||
Storage::StartResult start(const QByteArray &passcode);
|
||||
|
||||
[[nodiscard]] Storage::Accounts &local() const {
|
||||
return *_local;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto list() const
|
||||
-> const base::flat_map<int, std::unique_ptr<Account>> &;
|
||||
[[nodiscard]] rpl::producer<Account*> activeValue() const;
|
||||
|
||||
// Expects(started());
|
||||
[[nodiscard]] Account &active() const;
|
||||
[[nodiscard]] rpl::producer<not_null<Account*>> activeChanges() const;
|
||||
|
||||
[[nodiscard]] rpl::producer<Session*> activeSessionValue() const;
|
||||
[[nodiscard]] rpl::producer<Session*> activeSessionChanges() const;
|
||||
|
||||
[[nodiscard]] int add();
|
||||
void activate(int index);
|
||||
|
||||
private:
|
||||
const QString _dataName;
|
||||
const std::unique_ptr<Storage::Accounts> _local;
|
||||
|
||||
base::flat_map<int, std::unique_ptr<Account>> _accounts;
|
||||
rpl::variable<Account*> _active = nullptr;
|
||||
int _activeIndex = 0;
|
||||
|
||||
rpl::event_stream<Session*> _activeSessions;
|
||||
|
||||
rpl::lifetime _activeLifetime;
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Main
|
|
@ -29,7 +29,6 @@ AppConfig::AppConfig(not_null<Account*> account) : _account(account) {
|
|||
_requestId = 0;
|
||||
}
|
||||
}, _lifetime);
|
||||
refresh();
|
||||
}
|
||||
|
||||
void AppConfig::refresh() {
|
||||
|
|
|
@ -67,6 +67,7 @@ Session::Session(
|
|||
) | rpl::start_with_next([=] {
|
||||
notifications().updateAll();
|
||||
}, _lifetime);
|
||||
|
||||
subscribe(Global::RefConnectionTypeChanged(), [=] {
|
||||
_api->refreshTopPromotion();
|
||||
});
|
||||
|
@ -74,6 +75,8 @@ Session::Session(
|
|||
_api->requestTermsUpdate();
|
||||
_api->requestFullPeer(_user);
|
||||
|
||||
_api->instance()->setUserPhone(_user->phone());
|
||||
|
||||
crl::on_main(this, [=] {
|
||||
using Flag = Data::PeerUpdate::Flag;
|
||||
changes().peerUpdates(
|
||||
|
@ -83,8 +86,16 @@ Session::Session(
|
|||
| Flag::Photo
|
||||
| Flag::About
|
||||
| Flag::PhoneNumber
|
||||
) | rpl::start_with_next([=] {
|
||||
) | rpl::start_with_next([=](const Data::PeerUpdate &update) {
|
||||
local().writeSelf();
|
||||
|
||||
if (update.flags & Flag::PhoneNumber) {
|
||||
const auto phone = _user->phone();
|
||||
_api->instance()->setUserPhone(phone);
|
||||
if (!phone.isEmpty()) {
|
||||
_api->instance()->requestConfig();
|
||||
}
|
||||
}
|
||||
}, _lifetime);
|
||||
|
||||
if (_settings.hadLegacyCallsPeerToPeerNobody()) {
|
||||
|
|
|
@ -94,13 +94,6 @@ MainWindow::MainWindow(not_null<Window::Controller*> controller)
|
|||
|
||||
setLocale(QLocale(QLocale::English, QLocale::UnitedStates));
|
||||
|
||||
account().sessionValue(
|
||||
) | rpl::start_with_next([=](Main::Session *session) {
|
||||
updateGlobalMenu();
|
||||
if (!session) {
|
||||
_mediaPreview.destroy();
|
||||
}
|
||||
}, lifetime());
|
||||
subscribe(Window::Theme::Background(), [this](const Window::Theme::BackgroundUpdate &data) {
|
||||
themeUpdated(data);
|
||||
});
|
||||
|
@ -202,6 +195,7 @@ void MainWindow::finishFirstShow() {
|
|||
|
||||
void MainWindow::clearWidgetsHook() {
|
||||
destroyLayer();
|
||||
_mediaPreview.destroy();
|
||||
_main.destroy();
|
||||
_passcodeLock.destroy();
|
||||
_intro.destroy();
|
||||
|
@ -241,20 +235,19 @@ void MainWindow::setupPasscodeLock() {
|
|||
}
|
||||
|
||||
void MainWindow::clearPasscodeLock() {
|
||||
if (!_passcodeLock) return;
|
||||
if (!_passcodeLock) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto bg = grabInner();
|
||||
|
||||
_passcodeLock.destroy();
|
||||
if (_intro) {
|
||||
auto bg = grabInner();
|
||||
_passcodeLock.destroy();
|
||||
_intro->showAnimated(bg, true);
|
||||
} else if (_main) {
|
||||
auto bg = grabInner();
|
||||
_passcodeLock.destroy();
|
||||
_main->showAnimated(bg, true);
|
||||
Core::App().checkStartUrl();
|
||||
} else if (account().sessionExists()) {
|
||||
setupMain();
|
||||
} else {
|
||||
setupIntro();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -984,8 +977,10 @@ QImage MainWindow::iconWithCounter(int size, int count, style::color bg, style::
|
|||
}
|
||||
|
||||
QImage img(smallIcon ? ((size == 16) ? iconbig16 : (size == 32 ? iconbig32 : iconbig64)) : ((size == 16) ? icon16 : (size == 32 ? icon32 : icon64)));
|
||||
if (account().sessionExists() && account().session().supportMode()) {
|
||||
Window::ConvertIconToBlack(img);
|
||||
if (const auto controller = sessionController()) {
|
||||
if (controller->session().supportMode()) {
|
||||
Window::ConvertIconToBlack(img);
|
||||
}
|
||||
}
|
||||
if (!count) return img;
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "window/window_session_controller.h"
|
||||
#include "core/shortcuts.h"
|
||||
#include "core/application.h"
|
||||
#include "main/main_account.h" // Account::sessionValue.
|
||||
#include "main/main_accounts.h" // Accounts::activeSessionValue.
|
||||
#include "mainwindow.h"
|
||||
#include "main/main_session.h"
|
||||
#include "facades.h"
|
||||
|
@ -114,7 +114,7 @@ Instance::Instance()
|
|||
});
|
||||
|
||||
// While we have one Media::Player::Instance for all sessions we have to do this.
|
||||
Core::App().activeAccount().sessionValue( // #TODO multi activeSessionValue
|
||||
Core::App().accounts().activeSessionValue(
|
||||
) | rpl::start_with_next([=](Main::Session *session) {
|
||||
if (session) {
|
||||
subscribe(session->calls().currentCallChanged(), [=](Calls::Call *call) {
|
||||
|
|
|
@ -46,9 +46,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "window/window_peer_menu.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "main/main_account.h" // Account::sessionValue.
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_accounts.h" // Accounts::activeSessionValue.
|
||||
#include "main/main_session.h"
|
||||
#include "layout.h"
|
||||
#include "storage/file_download.h"
|
||||
|
@ -303,8 +304,6 @@ OverlayWidget::OverlayWidget()
|
|||
? Global::VideoVolume()
|
||||
: Global::kDefaultVolume;
|
||||
|
||||
// #TODO multi activeSessionValue change icon on show?
|
||||
setWindowIcon(Window::CreateIcon(&Core::App().activeAccount()));
|
||||
setWindowTitle(qsl("Media viewer"));
|
||||
|
||||
const auto text = tr::lng_mediaview_saved_to(
|
||||
|
@ -320,9 +319,15 @@ OverlayWidget::OverlayWidget()
|
|||
connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(onScreenResized(int)));
|
||||
|
||||
// While we have one mediaview for all sessions we have to do this.
|
||||
Core::App().activeAccount().sessionValue( // #TODO multi activeSessionValue
|
||||
Core::App().accounts().activeSessionValue(
|
||||
) | rpl::start_with_next([=](Main::Session *session) {
|
||||
if (!isHidden()) {
|
||||
close();
|
||||
}
|
||||
clearData();
|
||||
setWindowIcon(Window::CreateIcon(session));
|
||||
if (session) {
|
||||
// #TODO multi
|
||||
subscribe(session->downloaderTaskFinished(), [=] {
|
||||
if (!isHidden()) {
|
||||
updateControls();
|
||||
|
|
|
@ -51,7 +51,6 @@ bool gNoStartUpdate = false;
|
|||
bool gStartToSettings = false;
|
||||
|
||||
uint32 gConnectionsInSession = 1;
|
||||
QString gLoggedPhoneNumber;
|
||||
|
||||
QByteArray gLocalSalt;
|
||||
int gScreenScale = style::kScaleAuto;
|
||||
|
|
|
@ -36,7 +36,6 @@ DeclareSetting(uint64, RealAlphaVersion);
|
|||
DeclareSetting(QByteArray, AlphaPrivateKey);
|
||||
|
||||
DeclareSetting(bool, TestMode);
|
||||
DeclareSetting(QString, LoggedPhoneNumber);
|
||||
DeclareSetting(bool, AutoStart);
|
||||
DeclareSetting(bool, StartMinimized);
|
||||
DeclareSetting(bool, StartInTray);
|
||||
|
|
|
@ -21,6 +21,8 @@ namespace {
|
|||
constexpr char TdfMagic[] = { 'T', 'D', 'F', '$' };
|
||||
constexpr auto TdfMagicLen = int(sizeof(TdfMagic));
|
||||
|
||||
constexpr auto kStrongIterationsCount = 100'000;
|
||||
|
||||
} // namespace
|
||||
|
||||
QString ToFilePart(FileKey val) {
|
||||
|
@ -86,6 +88,28 @@ bool CheckStreamStatus(QDataStream &stream) {
|
|||
MTP::AuthKeyPtr CreateLocalKey(
|
||||
const QByteArray &passcode,
|
||||
const QByteArray &salt) {
|
||||
const auto s = bytes::make_span(salt);
|
||||
const auto hash = openssl::Sha512(s, bytes::make_span(passcode), s);
|
||||
const auto iterationsCount = passcode.isEmpty()
|
||||
? 1 // Don't slow down for no password.
|
||||
: kStrongIterationsCount;
|
||||
|
||||
auto key = MTP::AuthKey::Data{ { gsl::byte{} } };
|
||||
PKCS5_PBKDF2_HMAC(
|
||||
reinterpret_cast<const char*>(hash.data()),
|
||||
hash.size(),
|
||||
reinterpret_cast<const unsigned char*>(s.data()),
|
||||
s.size(),
|
||||
iterationsCount,
|
||||
EVP_sha512(),
|
||||
key.size(),
|
||||
reinterpret_cast<unsigned char*>(key.data()));
|
||||
return std::make_shared<MTP::AuthKey>(key);
|
||||
}
|
||||
|
||||
MTP::AuthKeyPtr CreateLegacyLocalKey(
|
||||
const QByteArray &passcode,
|
||||
const QByteArray &salt) {
|
||||
auto key = MTP::AuthKey::Data{ { gsl::byte{} } };
|
||||
const auto iterationsCount = passcode.isEmpty()
|
||||
? LocalEncryptNoPwdIterCount // Don't slow down for no password.
|
||||
|
|
|
@ -23,6 +23,9 @@ void ClearKey(const FileKey &key, const QString &basePath);
|
|||
[[nodiscard]] MTP::AuthKeyPtr CreateLocalKey(
|
||||
const QByteArray &passcode,
|
||||
const QByteArray &salt);
|
||||
[[nodiscard]] MTP::AuthKeyPtr CreateLegacyLocalKey(
|
||||
const QByteArray &passcode,
|
||||
const QByteArray &salt);
|
||||
|
||||
struct FileReadDescriptor final {
|
||||
~FileReadDescriptor();
|
||||
|
|
|
@ -681,12 +681,10 @@ bool ReadSetting(
|
|||
cSetWindowPos(position);
|
||||
} break;
|
||||
|
||||
case dbiLoggedPhoneNumber: {
|
||||
case dbiLoggedPhoneNumber: { // deprecated
|
||||
QString v;
|
||||
stream >> v;
|
||||
if (!CheckStreamStatus(stream)) return false;
|
||||
|
||||
cSetLoggedPhoneNumber(v);
|
||||
} break;
|
||||
|
||||
case dbiMutePeer: { // deprecated
|
||||
|
@ -737,9 +735,9 @@ bool ReadSetting(
|
|||
? false
|
||||
: (v == 1);
|
||||
if (Window::Theme::IsNightMode()) {
|
||||
Window::Theme::Background()->setTileNightValue(tile);
|
||||
context.tileNight = tile;
|
||||
} else {
|
||||
Window::Theme::Background()->setTileDayValue(tile);
|
||||
context.tileDay = tile;
|
||||
}
|
||||
} break;
|
||||
|
||||
|
@ -748,8 +746,8 @@ bool ReadSetting(
|
|||
stream >> tileDay >> tileNight;
|
||||
if (!CheckStreamStatus(stream)) return false;
|
||||
|
||||
Window::Theme::Background()->setTileDayValue(tileDay == 1);
|
||||
Window::Theme::Background()->setTileNightValue(tileNight == 1);
|
||||
context.tileDay = (tileDay == 1);
|
||||
context.tileNight = (tileNight == 1);
|
||||
} break;
|
||||
|
||||
case dbiAdaptiveForWide: {
|
||||
|
|
|
@ -51,6 +51,9 @@ struct ReadSettingsContext {
|
|||
std::vector<std::shared_ptr<MTP::AuthKey>> mtpLegacyKeys;
|
||||
qint32 mtpLegacyMainDcId = 0;
|
||||
qint32 mtpLegacyUserId = 0;
|
||||
|
||||
bool tileDay = false;
|
||||
bool tileNight = true;
|
||||
};
|
||||
|
||||
[[nodiscard]] bool ReadSetting(
|
||||
|
|
|
@ -88,14 +88,6 @@ enum class WriteMapWhen {
|
|||
Soon,
|
||||
};
|
||||
|
||||
std::unique_ptr<Main::Settings> StoredSessionSettings;
|
||||
Main::Settings &GetStoredSessionSettings() {
|
||||
if (!StoredSessionSettings) {
|
||||
StoredSessionSettings = std::make_unique<Main::Settings>();
|
||||
}
|
||||
return *StoredSessionSettings;
|
||||
}
|
||||
|
||||
void applyReadContext(ReadSettingsContext &&context) {
|
||||
Core::App().dcOptions()->addFromOther(std::move(context.dcOptions));
|
||||
|
||||
|
@ -169,7 +161,7 @@ void _readOldUserSettingsFields(
|
|||
continue;
|
||||
}
|
||||
|
||||
OldKey = CreateLocalKey(QByteArray(), salt);
|
||||
OldKey = CreateLegacyLocalKey(QByteArray(), salt);
|
||||
|
||||
if (data.size() <= 16 || (data.size() & 0x0F)) {
|
||||
LOG(("App Error: bad encrypted part size in old user config: %1").arg(data.size()));
|
||||
|
@ -344,7 +336,7 @@ void start() {
|
|||
LOG(("App Error: bad salt in settings file, size: %1").arg(salt.size()));
|
||||
return writeSettings();
|
||||
}
|
||||
SettingsKey = CreateLocalKey(QByteArray(), salt);
|
||||
SettingsKey = CreateLegacyLocalKey(QByteArray(), salt);
|
||||
|
||||
EncryptedDescriptor settings;
|
||||
if (!DecryptLocal(settings, settingsEncrypted, SettingsKey)) {
|
||||
|
@ -388,7 +380,7 @@ void writeSettings() {
|
|||
if (_settingsSalt.isEmpty() || !SettingsKey) {
|
||||
_settingsSalt.resize(LocalEncryptSaltSize);
|
||||
memset_rand(_settingsSalt.data(), _settingsSalt.size());
|
||||
SettingsKey = CreateLocalKey(QByteArray(), _settingsSalt);
|
||||
SettingsKey = CreateLegacyLocalKey(QByteArray(), _settingsSalt);
|
||||
}
|
||||
settings.writeData(_settingsSalt);
|
||||
|
||||
|
@ -398,7 +390,6 @@ void writeSettings() {
|
|||
quint32 size = 12 * (sizeof(quint32) + sizeof(qint32));
|
||||
size += sizeof(quint32) + Serialize::bytearraySize(dcOptionsSerialized);
|
||||
size += sizeof(quint32) + Serialize::bytearraySize(applicationSettings);
|
||||
size += sizeof(quint32) + Serialize::stringSize(cLoggedPhoneNumber());
|
||||
size += sizeof(quint32) + Serialize::stringSize(Global::TxtDomainString());
|
||||
size += sizeof(quint32) + Serialize::stringSize(cDialogLastPath());
|
||||
|
||||
|
@ -438,7 +429,6 @@ void writeSettings() {
|
|||
data.stream << quint32(dbiScalePercent) << qint32(cConfigScale());
|
||||
data.stream << quint32(dbiDcOptions) << dcOptionsSerialized;
|
||||
data.stream << quint32(dbiApplicationSettings) << applicationSettings;
|
||||
data.stream << quint32(dbiLoggedPhoneNumber) << cLoggedPhoneNumber();
|
||||
data.stream << quint32(dbiTxtDomainString) << Global::TxtDomainString();
|
||||
data.stream << quint32(dbiDialogLastPath) << cDialogLastPath();
|
||||
data.stream << quint32(dbiAnimationsDisabled) << qint32(anim::Disabled() ? 1 : 0);
|
||||
|
@ -542,7 +532,6 @@ void reset() {
|
|||
|
||||
Window::Theme::Background()->reset();
|
||||
_oldSettingsVersion = 0;
|
||||
StoredSessionSettings.reset();
|
||||
}
|
||||
|
||||
int32 oldSettingsVersion() {
|
||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "storage/storage_account.h"
|
||||
|
||||
#include "storage/localstorage.h"
|
||||
#include "storage/storage_accounts.h"
|
||||
#include "storage/storage_encryption.h"
|
||||
#include "storage/storage_clear_legacy.h"
|
||||
#include "storage/cache/storage_cache_types.h"
|
||||
|
@ -35,7 +36,6 @@ namespace {
|
|||
using namespace details;
|
||||
using Database = Cache::Database;
|
||||
|
||||
constexpr auto kLocalKeySize = MTP::AuthKey::kSize;
|
||||
constexpr auto kDelayedWriteTimeout = crl::time(1000);
|
||||
constexpr auto kSavedBackgroundFormat = QImage::Format_ARGB32_Premultiplied;
|
||||
|
||||
|
@ -120,14 +120,28 @@ Account::~Account() {
|
|||
}
|
||||
}
|
||||
|
||||
StartResult Account::start(const QByteArray &passcode) {
|
||||
const auto result = readMap(passcode);
|
||||
StartResult Account::legacyStart(const QByteArray &passcode) {
|
||||
const auto result = readMapWith(MTP::AuthKeyPtr(), passcode);
|
||||
if (result == ReadMapResult::Failed) {
|
||||
_mapChanged = true;
|
||||
writeMap();
|
||||
Assert(_localKey == nullptr);
|
||||
//_mapChanged = true;
|
||||
//writeMap();
|
||||
} else if (result == ReadMapResult::IncorrectPasscode) {
|
||||
return StartResult::IncorrectPasscode;
|
||||
}
|
||||
clearLegacyFiles();
|
||||
return StartResult::Success;
|
||||
}
|
||||
|
||||
void Account::start(MTP::AuthKeyPtr localKey) {
|
||||
Expects(localKey != nullptr);
|
||||
|
||||
_localKey = std::move(localKey);
|
||||
readMapWith(_localKey);
|
||||
clearLegacyFiles();
|
||||
}
|
||||
|
||||
void Account::clearLegacyFiles() {
|
||||
const auto weak = base::make_weak(_owner.get());
|
||||
ClearLegacyFiles(_basePath, [weak, this](
|
||||
FnMut<void(base::flat_set<QString>&&)> then) {
|
||||
|
@ -135,12 +149,6 @@ StartResult Account::start(const QByteArray &passcode) {
|
|||
then(collectGoodNames());
|
||||
});
|
||||
});
|
||||
|
||||
if (Local::oldSettingsVersion() < AppVersion) {
|
||||
Local::writeSettings();
|
||||
}
|
||||
|
||||
return StartResult::Success;
|
||||
}
|
||||
|
||||
base::flat_set<QString> Account::collectGoodNames() const {
|
||||
|
@ -184,7 +192,9 @@ base::flat_set<QString> Account::collectGoodNames() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
Account::ReadMapResult Account::readMap(const QByteArray &passcode) {
|
||||
Account::ReadMapResult Account::readMapWith(
|
||||
MTP::AuthKeyPtr localKey,
|
||||
const QByteArray &legacyPasscode) {
|
||||
auto ms = crl::now();
|
||||
|
||||
FileReadDescriptor mapData;
|
||||
|
@ -193,34 +203,33 @@ Account::ReadMapResult Account::readMap(const QByteArray &passcode) {
|
|||
}
|
||||
LOG(("App Info: reading map..."));
|
||||
|
||||
QByteArray salt, keyEncrypted, mapEncrypted;
|
||||
mapData.stream >> salt >> keyEncrypted >> mapEncrypted;
|
||||
QByteArray legacySalt, legacyKeyEncrypted, mapEncrypted;
|
||||
mapData.stream >> legacySalt >> legacyKeyEncrypted >> mapEncrypted;
|
||||
if (!CheckStreamStatus(mapData.stream)) {
|
||||
return ReadMapResult::Failed;
|
||||
}
|
||||
if (!localKey) {
|
||||
if (legacySalt.size() != LocalEncryptSaltSize) {
|
||||
LOG(("App Error: bad salt in map file, size: %1").arg(legacySalt.size()));
|
||||
return ReadMapResult::Failed;
|
||||
}
|
||||
auto legacyPasscodeKey = CreateLegacyLocalKey(legacyPasscode, legacySalt);
|
||||
|
||||
if (salt.size() != LocalEncryptSaltSize) {
|
||||
LOG(("App Error: bad salt in map file, size: %1").arg(salt.size()));
|
||||
return ReadMapResult::Failed;
|
||||
EncryptedDescriptor keyData;
|
||||
if (!DecryptLocal(keyData, legacyKeyEncrypted, legacyPasscodeKey)) {
|
||||
LOG(("App Info: could not decrypt pass-protected key from map file, maybe bad password..."));
|
||||
return ReadMapResult::IncorrectPasscode;
|
||||
}
|
||||
auto key = Serialize::read<MTP::AuthKey::Data>(keyData.stream);
|
||||
if (keyData.stream.status() != QDataStream::Ok || !keyData.stream.atEnd()) {
|
||||
LOG(("App Error: could not read pass-protected key from map file"));
|
||||
return ReadMapResult::Failed;
|
||||
}
|
||||
localKey = std::make_shared<MTP::AuthKey>(key);
|
||||
}
|
||||
_passcodeKey = CreateLocalKey(passcode, salt);
|
||||
|
||||
EncryptedDescriptor keyData, map;
|
||||
if (!DecryptLocal(keyData, keyEncrypted, _passcodeKey)) {
|
||||
LOG(("App Info: could not decrypt pass-protected key from map file, maybe bad password..."));
|
||||
return ReadMapResult::IncorrectPasscode;
|
||||
}
|
||||
auto key = Serialize::read<MTP::AuthKey::Data>(keyData.stream);
|
||||
if (keyData.stream.status() != QDataStream::Ok || !keyData.stream.atEnd()) {
|
||||
LOG(("App Error: could not read pass-protected key from map file"));
|
||||
return ReadMapResult::Failed;
|
||||
}
|
||||
_localKey = std::make_shared<MTP::AuthKey>(key);
|
||||
|
||||
_passcodeKeyEncrypted = keyEncrypted;
|
||||
_passcodeKeySalt = salt;
|
||||
|
||||
if (!DecryptLocal(map, mapEncrypted, _localKey)) {
|
||||
EncryptedDescriptor map;
|
||||
if (!DecryptLocal(map, mapEncrypted, localKey)) {
|
||||
LOG(("App Error: could not decrypt map."));
|
||||
return ReadMapResult::Failed;
|
||||
}
|
||||
|
@ -336,6 +345,8 @@ Account::ReadMapResult Account::readMap(const QByteArray &passcode) {
|
|||
}
|
||||
}
|
||||
|
||||
_localKey = std::move(localKey);
|
||||
|
||||
_draftsMap = draftsMap;
|
||||
_draftCursorsMap = draftCursorsMap;
|
||||
_draftsNotReadMap = draftsNotReadMap;
|
||||
|
@ -355,6 +366,7 @@ Account::ReadMapResult Account::readMap(const QByteArray &passcode) {
|
|||
_recentHashtagsAndBotsKey = recentHashtagsAndBotsKey;
|
||||
_exportSettingsKey = exportSettingsKey;
|
||||
_oldMapVersion = mapData.version;
|
||||
|
||||
if (_oldMapVersion < AppVersion) {
|
||||
writeMapDelayed();
|
||||
} else {
|
||||
|
@ -391,6 +403,8 @@ void Account::writeMapQueued() {
|
|||
}
|
||||
|
||||
void Account::writeMap() {
|
||||
Expects(_localKey != nullptr);
|
||||
|
||||
_writeMapTimer.cancel();
|
||||
if (!_mapChanged) {
|
||||
return;
|
||||
|
@ -402,23 +416,8 @@ void Account::writeMap() {
|
|||
}
|
||||
|
||||
FileWriteDescriptor map(u"map"_q, _basePath);
|
||||
if (_passcodeKeySalt.isEmpty() || _passcodeKeyEncrypted.isEmpty()) {
|
||||
auto pass = QByteArray(kLocalKeySize, Qt::Uninitialized);
|
||||
auto salt = QByteArray(LocalEncryptSaltSize, Qt::Uninitialized);
|
||||
memset_rand(pass.data(), pass.size());
|
||||
memset_rand(salt.data(), salt.size());
|
||||
_localKey = CreateLocalKey(pass, salt);
|
||||
|
||||
_passcodeKeySalt.resize(LocalEncryptSaltSize);
|
||||
memset_rand(_passcodeKeySalt.data(), _passcodeKeySalt.size());
|
||||
_passcodeKey = CreateLocalKey(QByteArray(), _passcodeKeySalt);
|
||||
|
||||
EncryptedDescriptor passKeyData(kLocalKeySize);
|
||||
_localKey->write(passKeyData.stream);
|
||||
_passcodeKeyEncrypted = PrepareEncrypted(passKeyData, _passcodeKey);
|
||||
}
|
||||
map.writeData(_passcodeKeySalt);
|
||||
map.writeData(_passcodeKeyEncrypted);
|
||||
map.writeData(QByteArray());
|
||||
map.writeData(QByteArray());
|
||||
|
||||
uint32 mapSize = 0;
|
||||
const auto self = [&] {
|
||||
|
@ -514,34 +513,8 @@ void Account::writeMap() {
|
|||
_mapChanged = false;
|
||||
}
|
||||
|
||||
bool Account::checkPasscode(const QByteArray &passcode) const {
|
||||
Expects(!_passcodeKeySalt.isEmpty());
|
||||
Expects(_passcodeKey != nullptr);
|
||||
|
||||
const auto checkKey = CreateLocalKey(passcode, _passcodeKeySalt);
|
||||
return checkKey->equals(_passcodeKey);
|
||||
}
|
||||
|
||||
void Account::setPasscode(const QByteArray &passcode) {
|
||||
Expects(!_passcodeKeySalt.isEmpty());
|
||||
Expects(_localKey != nullptr);
|
||||
|
||||
_passcodeKey = CreateLocalKey(passcode, _passcodeKeySalt);
|
||||
|
||||
EncryptedDescriptor passKeyData(kLocalKeySize);
|
||||
_localKey->write(passKeyData.stream);
|
||||
_passcodeKeyEncrypted = PrepareEncrypted(passKeyData, _passcodeKey);
|
||||
|
||||
_mapChanged = true;
|
||||
writeMap();
|
||||
|
||||
Global::SetLocalPasscode(!passcode.isEmpty());
|
||||
Global::RefLocalPasscodeChanged().notify();
|
||||
}
|
||||
|
||||
void Account::reset() {
|
||||
auto names = collectGoodNames();
|
||||
_passcodeKeySalt.clear();
|
||||
_draftsMap.clear();
|
||||
_draftCursorsMap.clear();
|
||||
_draftsNotReadMap.clear();
|
||||
|
@ -921,6 +894,10 @@ std::unique_ptr<Main::Settings> Account::applyReadContext(
|
|||
}
|
||||
}
|
||||
|
||||
// #TODO multi
|
||||
//Window::Theme::Background()->setTileDayValue(context.tileDay);
|
||||
//Window::Theme::Background()->setTileNightValue(context.tileNight);
|
||||
|
||||
return std::move(context.sessionSettingsStorage);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,10 +41,7 @@ class EncryptionKey;
|
|||
|
||||
using FileKey = quint64;
|
||||
|
||||
enum class StartResult : uchar {
|
||||
Success,
|
||||
IncorrectPasscode,
|
||||
};
|
||||
enum class StartResult : uchar;
|
||||
|
||||
struct MessageDraft {
|
||||
MsgId msgId = 0;
|
||||
|
@ -57,13 +54,15 @@ public:
|
|||
Account(not_null<Main::Account*> owner, const QString &dataName);
|
||||
~Account();
|
||||
|
||||
[[nodiscard]] StartResult start(const QByteArray &passcode);
|
||||
[[nodiscard]] void start(MTP::AuthKeyPtr localKey);
|
||||
[[nodiscard]] StartResult legacyStart(const QByteArray &passcode);
|
||||
[[nodiscard]] int oldMapVersion() const {
|
||||
return _oldMapVersion;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool checkPasscode(const QByteArray &passcode) const;
|
||||
void setPasscode(const QByteArray &passcode);
|
||||
MTP::AuthKeyPtr peekLegacyLocalKey() const {
|
||||
return _localKey;
|
||||
}
|
||||
|
||||
void writeSettings();
|
||||
void writeMtpData();
|
||||
|
@ -156,7 +155,10 @@ private:
|
|||
[[nodiscard]] auto prepareReadSettingsContext() const
|
||||
-> details::ReadSettingsContext;
|
||||
|
||||
[[nodiscard]] ReadMapResult readMap(const QByteArray &passcode);
|
||||
ReadMapResult readMapWith(
|
||||
MTP::AuthKeyPtr localKey,
|
||||
const QByteArray &legacyPasscode = QByteArray());
|
||||
void clearLegacyFiles();
|
||||
void writeMapDelayed();
|
||||
void writeMapQueued();
|
||||
void writeMap();
|
||||
|
@ -168,18 +170,6 @@ private:
|
|||
|
||||
std::unique_ptr<Main::Settings> readSettings();
|
||||
void writeSettings(Main::Settings *stored);
|
||||
bool readOldUserSettings(
|
||||
bool remove,
|
||||
details::ReadSettingsContext &context);
|
||||
void readOldUserSettingsFields(
|
||||
QIODevice *device,
|
||||
qint32 &version,
|
||||
details::ReadSettingsContext &context);
|
||||
void readOldMtpDataFields(
|
||||
QIODevice *device,
|
||||
qint32 &version,
|
||||
details::ReadSettingsContext &context);
|
||||
bool readOldMtpData(bool remove, details::ReadSettingsContext &context);
|
||||
|
||||
void readMtpData();
|
||||
std::unique_ptr<Main::Settings> applyReadContext(
|
||||
|
@ -222,9 +212,6 @@ private:
|
|||
const QString _databasePath;
|
||||
|
||||
MTP::AuthKeyPtr _localKey;
|
||||
MTP::AuthKeyPtr _passcodeKey;
|
||||
QByteArray _passcodeKeySalt;
|
||||
QByteArray _passcodeKeyEncrypted;
|
||||
|
||||
base::flat_map<PeerId, FileKey> _draftsMap;
|
||||
base::flat_map<PeerId, FileKey> _draftCursorsMap;
|
||||
|
|
243
Telegram/SourceFiles/storage/storage_accounts.cpp
Normal file
243
Telegram/SourceFiles/storage/storage_accounts.cpp
Normal file
|
@ -0,0 +1,243 @@
|
|||
/*
|
||||
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 "storage/storage_accounts.h"
|
||||
|
||||
#include "storage/details/storage_file_utilities.h"
|
||||
#include "storage/serialize_common.h"
|
||||
#include "main/main_accounts.h"
|
||||
#include "main/main_account.h"
|
||||
#include "facades.h"
|
||||
|
||||
namespace Storage {
|
||||
namespace {
|
||||
|
||||
using namespace details;
|
||||
|
||||
constexpr auto kMaxAccounts = 3;
|
||||
|
||||
[[nodiscard]] QString BaseGlobalPath() {
|
||||
return cWorkingDir() + qsl("tdata/");
|
||||
}
|
||||
|
||||
[[nodiscard]] QString ComputeKeyName(const QString &dataName) {
|
||||
return "key_" + dataName + (cTestMode() ? "[test]" : "");
|
||||
}
|
||||
|
||||
[[nodiscard]] QString ComputeInfoName(const QString &dataName) {
|
||||
return "info_" + dataName + (cTestMode() ? "[test]" : "");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Accounts::Accounts(not_null<Main::Accounts*> owner, const QString &dataName)
|
||||
: _owner(owner)
|
||||
, _dataName(dataName) {
|
||||
}
|
||||
|
||||
Accounts::~Accounts() = default;
|
||||
|
||||
StartResult Accounts::start(
|
||||
const QByteArray &passcode,
|
||||
Fn<void(int, std::unique_ptr<Main::Account>)> callback) {
|
||||
const auto modern = startModern(passcode, callback);
|
||||
if (modern == StartModernResult::Success) {
|
||||
if (_oldVersion < AppVersion) {
|
||||
writeAccounts();
|
||||
}
|
||||
return StartResult::Success;
|
||||
} else if (modern == StartModernResult::IncorrectPasscode) {
|
||||
return StartResult::IncorrectPasscode;
|
||||
} else if (modern == StartModernResult::Failed) {
|
||||
startWithSingleAccount(
|
||||
passcode,
|
||||
std::move(callback),
|
||||
std::make_unique<Main::Account>(_dataName, 0));
|
||||
return StartResult::Success;
|
||||
}
|
||||
auto legacy = std::make_unique<Main::Account>(_dataName, 0);
|
||||
const auto result = legacy->legacyStart(passcode);
|
||||
if (result == StartResult::Success) {
|
||||
_oldVersion = legacy->local().oldMapVersion();
|
||||
startWithSingleAccount(
|
||||
passcode,
|
||||
std::move(callback),
|
||||
std::move(legacy));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Accounts::startWithSingleAccount(
|
||||
const QByteArray &passcode,
|
||||
Fn<void(int, std::unique_ptr<Main::Account>)> callback,
|
||||
std::unique_ptr<Main::Account> account) {
|
||||
Expects(account != nullptr);
|
||||
|
||||
if (auto localKey = account->local().peekLegacyLocalKey()) {
|
||||
_localKey = std::move(localKey);
|
||||
encryptLocalKey(passcode);
|
||||
} else {
|
||||
generateLocalKey();
|
||||
account->start(_localKey);
|
||||
}
|
||||
callback(0, std::move(account));
|
||||
writeAccounts();
|
||||
}
|
||||
|
||||
void Accounts::generateLocalKey() {
|
||||
Expects(_localKey == nullptr);
|
||||
Expects(_passcodeKeySalt.isEmpty());
|
||||
Expects(_passcodeKeyEncrypted.isEmpty());
|
||||
|
||||
auto pass = QByteArray(MTP::AuthKey::kSize, Qt::Uninitialized);
|
||||
auto salt = QByteArray(LocalEncryptSaltSize, Qt::Uninitialized);
|
||||
memset_rand(pass.data(), pass.size());
|
||||
memset_rand(salt.data(), salt.size());
|
||||
_localKey = CreateLocalKey(pass, salt);
|
||||
|
||||
encryptLocalKey(QByteArray());
|
||||
}
|
||||
|
||||
void Accounts::encryptLocalKey(const QByteArray &passcode) {
|
||||
_passcodeKeySalt.resize(LocalEncryptSaltSize);
|
||||
memset_rand(_passcodeKeySalt.data(), _passcodeKeySalt.size());
|
||||
_passcodeKey = CreateLocalKey(passcode, _passcodeKeySalt);
|
||||
|
||||
EncryptedDescriptor passKeyData(MTP::AuthKey::kSize);
|
||||
_localKey->write(passKeyData.stream);
|
||||
_passcodeKeyEncrypted = PrepareEncrypted(passKeyData, _passcodeKey);
|
||||
}
|
||||
|
||||
Accounts::StartModernResult Accounts::startModern(
|
||||
const QByteArray &passcode,
|
||||
Fn<void(int, std::unique_ptr<Main::Account>)> callback) {
|
||||
const auto name = ComputeKeyName(_dataName);
|
||||
|
||||
FileReadDescriptor keyData;
|
||||
if (!ReadFile(keyData, name, BaseGlobalPath())) {
|
||||
return StartModernResult::Empty;
|
||||
}
|
||||
LOG(("App Info: reading accounts info..."));
|
||||
|
||||
QByteArray salt, keyEncrypted, infoEncrypted;
|
||||
keyData.stream >> salt >> keyEncrypted >> infoEncrypted;
|
||||
if (!CheckStreamStatus(keyData.stream)) {
|
||||
return StartModernResult::Failed;
|
||||
}
|
||||
|
||||
if (salt.size() != LocalEncryptSaltSize) {
|
||||
LOG(("App Error: bad salt in info file, size: %1").arg(salt.size()));
|
||||
return StartModernResult::Failed;
|
||||
}
|
||||
_passcodeKey = CreateLocalKey(passcode, salt);
|
||||
|
||||
EncryptedDescriptor keyInnerData, info;
|
||||
if (!DecryptLocal(keyInnerData, keyEncrypted, _passcodeKey)) {
|
||||
LOG(("App Info: could not decrypt pass-protected key from info file, "
|
||||
"maybe bad password..."));
|
||||
return StartModernResult::IncorrectPasscode;
|
||||
}
|
||||
auto key = Serialize::read<MTP::AuthKey::Data>(keyInnerData.stream);
|
||||
if (keyInnerData.stream.status() != QDataStream::Ok
|
||||
|| !keyInnerData.stream.atEnd()) {
|
||||
LOG(("App Error: could not read pass-protected key from info file"));
|
||||
return StartModernResult::Failed;
|
||||
}
|
||||
_localKey = std::make_shared<MTP::AuthKey>(key);
|
||||
|
||||
_passcodeKeyEncrypted = keyEncrypted;
|
||||
_passcodeKeySalt = salt;
|
||||
|
||||
if (!DecryptLocal(info, infoEncrypted, _localKey)) {
|
||||
LOG(("App Error: could not decrypt info."));
|
||||
return StartModernResult::Failed;
|
||||
}
|
||||
LOG(("App Info: reading encrypted info..."));
|
||||
auto count = qint32();
|
||||
info.stream >> count;
|
||||
if (count <= 0 || count > kMaxAccounts) {
|
||||
LOG(("App Error: bad accounts count: %1").arg(count));
|
||||
return StartModernResult::Failed;
|
||||
}
|
||||
|
||||
_oldVersion = keyData.version;
|
||||
|
||||
auto tried = base::flat_set<int>();
|
||||
auto users = base::flat_set<UserId>();
|
||||
for (auto i = 0; i != count; ++i) {
|
||||
auto index = qint32();
|
||||
info.stream >> index;
|
||||
if (index >= 0
|
||||
&& index < kMaxAccounts
|
||||
&& tried.emplace(index).second) {
|
||||
auto account = std::make_unique<Main::Account>(_dataName, index);
|
||||
account->start(_localKey);
|
||||
const auto userId = account->willHaveUserId();
|
||||
if (!users.contains(userId)
|
||||
&& (userId != 0 || (users.empty() && i + 1 == count))) {
|
||||
callback(index, std::move(account));
|
||||
users.emplace(userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ensures(!users.empty());
|
||||
return StartModernResult::Success;
|
||||
}
|
||||
|
||||
void Accounts::writeAccounts() {
|
||||
Expects(!_owner->list().empty());
|
||||
|
||||
const auto path = BaseGlobalPath();
|
||||
if (!QDir().exists(path)) {
|
||||
QDir().mkpath(path);
|
||||
}
|
||||
|
||||
FileWriteDescriptor key(ComputeKeyName(_dataName), path);
|
||||
key.writeData(_passcodeKeySalt);
|
||||
key.writeData(_passcodeKeyEncrypted);
|
||||
|
||||
const auto &list = _owner->list();
|
||||
|
||||
auto keySize = sizeof(qint32) + sizeof(qint32) * list.size();
|
||||
|
||||
EncryptedDescriptor keyData(keySize);
|
||||
keyData.stream << qint32(list.size());
|
||||
for (const auto &[index, account] : list) {
|
||||
keyData.stream << qint32(index);
|
||||
}
|
||||
key.writeEncrypted(keyData, _localKey);
|
||||
}
|
||||
|
||||
bool Accounts::checkPasscode(const QByteArray &passcode) const {
|
||||
Expects(!_passcodeKeySalt.isEmpty());
|
||||
Expects(_passcodeKey != nullptr);
|
||||
|
||||
const auto checkKey = CreateLocalKey(passcode, _passcodeKeySalt);
|
||||
return checkKey->equals(_passcodeKey);
|
||||
}
|
||||
|
||||
void Accounts::setPasscode(const QByteArray &passcode) {
|
||||
Expects(!_passcodeKeySalt.isEmpty());
|
||||
Expects(_localKey != nullptr);
|
||||
|
||||
encryptLocalKey(passcode);
|
||||
writeAccounts();
|
||||
|
||||
Global::SetLocalPasscode(!passcode.isEmpty());
|
||||
Global::RefLocalPasscodeChanged().notify();
|
||||
}
|
||||
|
||||
int Accounts::oldVersion() const {
|
||||
return _oldVersion;
|
||||
}
|
||||
|
||||
void Accounts::clearOldVersion() {
|
||||
_oldVersion = 0;
|
||||
}
|
||||
|
||||
} // namespace Storage
|
73
Telegram/SourceFiles/storage/storage_accounts.h
Normal file
73
Telegram/SourceFiles/storage/storage_accounts.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
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
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace MTP {
|
||||
class AuthKey;
|
||||
using AuthKeyPtr = std::shared_ptr<AuthKey>;
|
||||
} // namespace MTP
|
||||
|
||||
namespace Main {
|
||||
class Account;
|
||||
class Accounts;
|
||||
} // namespace Main
|
||||
|
||||
namespace Storage {
|
||||
|
||||
enum class StartResult : uchar {
|
||||
Success,
|
||||
IncorrectPasscode,
|
||||
};
|
||||
|
||||
class Accounts final {
|
||||
public:
|
||||
Accounts(not_null<Main::Accounts*> owner, const QString &dataName);
|
||||
~Accounts();
|
||||
|
||||
[[nodiscard]] StartResult start(
|
||||
const QByteArray &passcode,
|
||||
Fn<void(int, std::unique_ptr<Main::Account>)> callback);
|
||||
void writeAccounts();
|
||||
|
||||
[[nodiscard]] bool checkPasscode(const QByteArray &passcode) const;
|
||||
void setPasscode(const QByteArray &passcode);
|
||||
|
||||
[[nodiscard]] int oldVersion() const;
|
||||
void clearOldVersion();
|
||||
|
||||
private:
|
||||
enum class StartModernResult {
|
||||
Success,
|
||||
IncorrectPasscode,
|
||||
Failed,
|
||||
Empty,
|
||||
};
|
||||
|
||||
[[nodiscard]] StartModernResult startModern(
|
||||
const QByteArray &passcode,
|
||||
Fn<void(int, std::unique_ptr<Main::Account>)> callback);
|
||||
void startWithSingleAccount(
|
||||
const QByteArray &passcode,
|
||||
Fn<void(int, std::unique_ptr<Main::Account>)> callback,
|
||||
std::unique_ptr<Main::Account> account);
|
||||
void generateLocalKey();
|
||||
void encryptLocalKey(const QByteArray &passcode);
|
||||
void writeInfo();
|
||||
|
||||
const not_null<Main::Accounts*> _owner;
|
||||
const QString _dataName;
|
||||
|
||||
MTP::AuthKeyPtr _localKey;
|
||||
MTP::AuthKeyPtr _passcodeKey;
|
||||
QByteArray _passcodeKeySalt;
|
||||
QByteArray _passcodeKeyEncrypted;
|
||||
int _oldVersion = 0;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Storage
|
|
@ -105,18 +105,16 @@ void ConvertIconToBlack(QImage &image) {
|
|||
}
|
||||
}
|
||||
|
||||
QIcon CreateOfficialIcon(Main::Account *account) {
|
||||
QIcon CreateOfficialIcon(Main::Session *session) {
|
||||
auto image = Core::IsAppLaunched() ? Core::App().logo() : LoadLogo();
|
||||
if (account
|
||||
&& account->sessionExists()
|
||||
&& account->session().supportMode()) {
|
||||
if (session && session->supportMode()) {
|
||||
ConvertIconToBlack(image);
|
||||
}
|
||||
return QIcon(App::pixmapFromImageInPlace(std::move(image)));
|
||||
}
|
||||
|
||||
QIcon CreateIcon(Main::Account *account) {
|
||||
auto result = CreateOfficialIcon(account);
|
||||
QIcon CreateIcon(Main::Session *session) {
|
||||
auto result = CreateOfficialIcon(session);
|
||||
#if defined Q_OS_UNIX && !defined Q_OS_MAC
|
||||
return QIcon::fromTheme(Platform::GetIconName(), result);
|
||||
#endif
|
||||
|
@ -295,10 +293,12 @@ bool MainWindow::computeIsActive() const {
|
|||
}
|
||||
|
||||
void MainWindow::updateWindowIcon() {
|
||||
const auto supportIcon = account().sessionExists()
|
||||
&& account().session().supportMode();
|
||||
const auto session = sessionController()
|
||||
? &sessionController()->session()
|
||||
: nullptr;
|
||||
const auto supportIcon = session && session->supportMode();
|
||||
if (supportIcon != _usingSupportIcon || _icon.isNull()) {
|
||||
_icon = CreateIcon(&account());
|
||||
_icon = CreateIcon(session);
|
||||
_usingSupportIcon = supportIcon;
|
||||
}
|
||||
setWindowIcon(_icon);
|
||||
|
@ -528,9 +528,7 @@ void MainWindow::updateControlsGeometry() {
|
|||
void MainWindow::updateUnreadCounter() {
|
||||
if (!Global::started() || App::quitting()) return;
|
||||
|
||||
const auto counter = account().sessionExists()
|
||||
? account().session().data().unreadBadge()
|
||||
: 0;
|
||||
const auto counter = Core::App().unreadBadge();
|
||||
_titleText = (counter > 0) ? qsl("Telegram (%1)").arg(counter) : qsl("Telegram");
|
||||
|
||||
unreadCounterChangedHook();
|
||||
|
|
|
@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include <QtWidgets/QSystemTrayIcon>
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
class Account;
|
||||
} // namespace Main
|
||||
|
||||
|
@ -31,7 +32,7 @@ struct TermsLock;
|
|||
|
||||
QImage LoadLogo();
|
||||
QImage LoadLogoNoMargin();
|
||||
QIcon CreateIcon(Main::Account *account = nullptr);
|
||||
QIcon CreateIcon(Main::Session *session = nullptr);
|
||||
void ConvertIconToBlack(QImage &image);
|
||||
|
||||
class MainWindow : public Ui::RpWidget, protected base::Subscriber {
|
||||
|
@ -40,11 +41,11 @@ class MainWindow : public Ui::RpWidget, protected base::Subscriber {
|
|||
public:
|
||||
explicit MainWindow(not_null<Controller*> controller);
|
||||
|
||||
Window::Controller &controller() const {
|
||||
[[nodiscard]] Window::Controller &controller() const {
|
||||
return *_controller;
|
||||
}
|
||||
Main::Account &account() const;
|
||||
Window::SessionController *sessionController() const;
|
||||
[[nodiscard]] Main::Account &account() const;
|
||||
[[nodiscard]] Window::SessionController *sessionController() const;
|
||||
|
||||
bool hideNoQuit();
|
||||
|
||||
|
|
|
@ -22,7 +22,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/unixtime.h"
|
||||
#include "base/crc32hash.h"
|
||||
#include "data/data_session.h"
|
||||
#include "main/main_account.h" // Account::sessionValue.
|
||||
#include "main/main_account.h" // Account::local.
|
||||
#include "main/main_accounts.h" // Accounts::activeSessionValue.
|
||||
#include "ui/image/image.h"
|
||||
#include "boxes/background_box.h"
|
||||
#include "core/application.h"
|
||||
|
@ -547,7 +548,7 @@ void ChatBackground::start() {
|
|||
set(Data::ThemeWallPaper());
|
||||
}
|
||||
|
||||
Core::App().activeAccount().sessionValue( // #TODO multi activeSessionValue
|
||||
Core::App().accounts().activeSessionValue(
|
||||
) | rpl::filter([=](Main::Session *session) {
|
||||
return session != _session;
|
||||
}) | rpl::start_with_next([=](Main::Session *session) {
|
||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "core/application.h"
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_accounts.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/layers/box_content.h"
|
||||
#include "ui/layers/layer_widget.h"
|
||||
|
@ -27,11 +28,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
namespace Window {
|
||||
|
||||
Controller::Controller(not_null<Main::Account*> account)
|
||||
: _account(account)
|
||||
, _widget(this) {
|
||||
Controller::Controller()
|
||||
: _widget(this) {
|
||||
_widget.init();
|
||||
}
|
||||
|
||||
Controller::~Controller() {
|
||||
// We want to delete all widgets before the _sessionController.
|
||||
_widget.clearWidgets();
|
||||
}
|
||||
|
||||
void Controller::showAccount(not_null<Main::Account*> account) {
|
||||
_accountLifetime.destroy();
|
||||
_account = account;
|
||||
|
||||
_account->sessionValue(
|
||||
) | rpl::start_with_next([=](Main::Session *session) {
|
||||
) | rpl::start_with_next([=](Main::Session *session) {
|
||||
_sessionController = session
|
||||
? std::make_unique<SessionController>(session, this)
|
||||
: nullptr;
|
||||
|
@ -47,14 +59,13 @@ Controller::Controller(not_null<Main::Account*> account)
|
|||
sideBarChanged();
|
||||
}
|
||||
_widget.updateWindowIcon();
|
||||
_widget.updateGlobalMenu();
|
||||
if (session) {
|
||||
setupMain();
|
||||
} else {
|
||||
setupIntro();
|
||||
}
|
||||
}, _lifetime);
|
||||
|
||||
_widget.init();
|
||||
}
|
||||
|
||||
Controller::~Controller() {
|
||||
// We want to delete all widgets before the _sessionController.
|
||||
_widget.clearWidgets();
|
||||
}
|
||||
|
||||
void Controller::finishFirstShow() {
|
||||
|
@ -75,7 +86,11 @@ void Controller::setupPasscodeLock() {
|
|||
}
|
||||
|
||||
void Controller::clearPasscodeLock() {
|
||||
_widget.clearPasscodeLock();
|
||||
if (!_account) {
|
||||
showAccount(&Core::App().activeAccount());
|
||||
} else {
|
||||
_widget.clearPasscodeLock();
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::setupIntro() {
|
||||
|
@ -83,12 +98,12 @@ void Controller::setupIntro() {
|
|||
}
|
||||
|
||||
void Controller::setupMain() {
|
||||
Expects(_account->sessionExists());
|
||||
Expects(_sessionController != nullptr);
|
||||
|
||||
_widget.setupMain();
|
||||
|
||||
if (const auto id = Ui::Emoji::NeedToSwitchBackToId()) {
|
||||
Ui::Emoji::LoadAndSwitchTo(&_account->session(), id);
|
||||
Ui::Emoji::LoadAndSwitchTo(&_sessionController->session(), id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,18 +18,22 @@ namespace Window {
|
|||
|
||||
class Controller final {
|
||||
public:
|
||||
explicit Controller(not_null<Main::Account*> account);
|
||||
Controller();
|
||||
~Controller();
|
||||
|
||||
Controller(const Controller &other) = delete;
|
||||
Controller &operator=(const Controller &other) = delete;
|
||||
|
||||
Main::Account &account() const {
|
||||
return *_account;
|
||||
}
|
||||
void showAccount(not_null<Main::Account*> account);
|
||||
|
||||
not_null<::MainWindow*> widget() {
|
||||
return &_widget;
|
||||
}
|
||||
Main::Account &account() const {
|
||||
Expects(_account != nullptr);
|
||||
|
||||
return *_account;
|
||||
}
|
||||
SessionController *sessionController() const {
|
||||
return _sessionController.get();
|
||||
}
|
||||
|
@ -74,10 +78,11 @@ private:
|
|||
anim::type animated);
|
||||
void checkThemeEditor();
|
||||
|
||||
not_null<Main::Account*> _account;
|
||||
Main::Account *_account = nullptr;
|
||||
::MainWindow _widget;
|
||||
std::unique_ptr<SessionController> _sessionController;
|
||||
|
||||
rpl::lifetime _accountLifetime;
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "window/window_lock_widgets.h"
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "storage/storage_account.h"
|
||||
#include "storage/storage_accounts.h"
|
||||
#include "mainwindow.h"
|
||||
#include "core/application.h"
|
||||
#include "api/api_text_entities.h"
|
||||
|
@ -22,7 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "window/window_controller.h"
|
||||
#include "window/window_slide_animation.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_accounts.h"
|
||||
#include "facades.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
@ -147,11 +147,12 @@ void PasscodeLockWidget::submit() {
|
|||
}
|
||||
|
||||
const auto passcode = _passcode->text().toUtf8();
|
||||
auto &account = window()->account();
|
||||
auto &local = window()->account().local();
|
||||
const auto correct = account.sessionExists()
|
||||
? local.checkPasscode(passcode)
|
||||
: (local.start(passcode) != Storage::StartResult::IncorrectPasscode);
|
||||
const auto controller = window()->sessionController();
|
||||
auto &accounts = Core::App().accounts();
|
||||
const auto correct = controller
|
||||
? accounts.local().checkPasscode(passcode)
|
||||
: (accounts.start(passcode)
|
||||
!= Storage::StartResult::IncorrectPasscode);
|
||||
if (!correct) {
|
||||
cSetPasscodeBadTries(cPasscodeBadTries() + 1);
|
||||
cSetPasscodeLastTry(crl::now());
|
||||
|
|
Loading…
Add table
Reference in a new issue