From c3595f2e3164a4d12a02243eab750f1fb765af1b Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 30 Jul 2021 17:33:26 +0300 Subject: [PATCH] Ask for a new password when recovering by email. --- Telegram/SourceFiles/boxes/passcode_box.cpp | 210 ++++++++++++------ Telegram/SourceFiles/boxes/passcode_box.h | 38 +++- Telegram/SourceFiles/intro/intro_code.cpp | 12 +- .../intro/intro_password_check.cpp | 73 +++--- .../SourceFiles/intro/intro_password_check.h | 7 +- Telegram/SourceFiles/intro/intro_qr.cpp | 8 +- Telegram/SourceFiles/intro/intro_widget.h | 5 +- .../passport/passport_form_controller.cpp | 20 +- .../passport/passport_panel_controller.cpp | 26 +-- 9 files changed, 256 insertions(+), 143 deletions(-) diff --git a/Telegram/SourceFiles/boxes/passcode_box.cpp b/Telegram/SourceFiles/boxes/passcode_box.cpp index d8b093b79..6527f1a03 100644 --- a/Telegram/SourceFiles/boxes/passcode_box.cpp +++ b/Telegram/SourceFiles/boxes/passcode_box.cpp @@ -189,21 +189,33 @@ PasscodeBox::PasscodeBox( PasscodeBox::PasscodeBox( QWidget*, - not_null session, + not_null mtp, + Main::Session *session, const CloudFields &fields) : _session(session) -, _api(&_session->mtp()) +, _api(mtp) , _turningOff(fields.turningOff) , _cloudPwd(true) , _cloudFields(fields) , _about(st::boxWidth - st::boxPadding.left() * 1.5) , _oldPasscode(this, st::defaultInputField, tr::lng_cloud_password_enter_old()) -, _newPasscode(this, st::defaultInputField, fields.curRequest ? tr::lng_cloud_password_enter_new() : tr::lng_cloud_password_enter_first()) +, _newPasscode( + this, + st::defaultInputField, + (fields.curRequest + ? tr::lng_cloud_password_enter_new() + : tr::lng_cloud_password_enter_first())) , _reenterPasscode(this, st::defaultInputField, tr::lng_cloud_password_confirm_new()) -, _passwordHint(this, st::defaultInputField, fields.curRequest ? tr::lng_cloud_password_change_hint() : tr::lng_cloud_password_hint()) +, _passwordHint( + this, + st::defaultInputField, + (fields.curRequest + ? tr::lng_cloud_password_change_hint() + : tr::lng_cloud_password_hint())) , _recoverEmail(this, st::defaultInputField, tr::lng_cloud_password_email()) , _recover(this, tr::lng_signin_recover(tr::now)) , _showRecoverLink(_cloudFields.hasRecovery || !_cloudFields.pendingResetDate) { + Expects(session != nullptr || !fields.fromRecoveryCode.isEmpty()); Expects(!_turningOff || _cloudFields.curRequest); if (!_cloudFields.hint.isEmpty()) { @@ -213,6 +225,13 @@ PasscodeBox::PasscodeBox( } } +PasscodeBox::PasscodeBox( + QWidget*, + not_null session, + const CloudFields &fields) +: PasscodeBox(nullptr, &session->mtp(), session, fields) { +} + rpl::producer PasscodeBox::newPasswordSet() const { return _newPasswordSet.events(); } @@ -225,6 +244,10 @@ rpl::producer<> PasscodeBox::clearUnconfirmedPassword() const { return _clearUnconfirmedPassword.events(); } +rpl::producer PasscodeBox::newAuthorization() const { + return _newAuthorization.events(); +} + bool PasscodeBox::currentlyHave() const { return _cloudPwd ? (!!_cloudFields.curRequest) @@ -272,9 +295,11 @@ void PasscodeBox::prepare() { } else { _oldPasscode->hide(); setTitle(_cloudPwd - ? tr::lng_cloud_password_create() + ? (_cloudFields.fromRecoveryCode.isEmpty() + ? tr::lng_cloud_password_create() + : tr::lng_cloud_password_change()) : tr::lng_passcode_create()); - setDimensions(st::boxWidth, st::passcodePadding.top() + _newPasscode->height() + st::passcodeLittleSkip + _reenterPasscode->height() + st::passcodeSkip + (_cloudPwd ? _passwordHint->height() + st::passcodeLittleSkip : 0) + st::passcodeAboutSkip + _aboutHeight + (_cloudPwd ? (st::passcodeLittleSkip + _recoverEmail->height() + st::passcodeSkip) : st::passcodePadding.bottom())); + setDimensions(st::boxWidth, st::passcodePadding.top() + _newPasscode->height() + st::passcodeLittleSkip + _reenterPasscode->height() + st::passcodeSkip + (_cloudPwd ? _passwordHint->height() + st::passcodeLittleSkip : 0) + st::passcodeAboutSkip + _aboutHeight + ((_cloudPwd && _cloudFields.fromRecoveryCode.isEmpty()) ? (st::passcodeLittleSkip + _recoverEmail->height() + st::passcodeSkip) : st::passcodePadding.bottom())); } } @@ -301,7 +326,10 @@ void PasscodeBox::prepare() { _newPasscode->setVisible(!onlyCheck); _reenterPasscode->setVisible(!onlyCheck); _passwordHint->setVisible(!onlyCheck && _cloudPwd); - _recoverEmail->setVisible(!onlyCheck && _cloudPwd && !has); + _recoverEmail->setVisible(!onlyCheck + && _cloudPwd + && !has + && _cloudFields.fromRecoveryCode.isEmpty()); } void PasscodeBox::submit() { @@ -400,21 +428,42 @@ void PasscodeBox::setInnerFocus() { } } +void PasscodeBox::recoverPasswordDone( + const QByteArray &newPasswordBytes, + const MTPauth_Authorization &result) { + if (_replacedBy) { + _replacedBy->closeBox(); + } + _setRequest = 0; + const auto weak = Ui::MakeWeak(this); + _newAuthorization.fire_copy(result); + _newPasswordSet.fire_copy(newPasswordBytes); + if (weak) { + getDelegate()->show(Box( + tr::lng_cloud_password_updated(tr::now))); + if (weak) { + closeBox(); + } + } +} + void PasscodeBox::setPasswordDone(const QByteArray &newPasswordBytes) { if (_replacedBy) { _replacedBy->closeBox(); } _setRequest = 0; - _newPasswordSet.fire_copy(newPasswordBytes); const auto weak = Ui::MakeWeak(this); - const auto text = _reenterPasscode->isHidden() - ? tr::lng_cloud_password_removed(tr::now) - : _oldPasscode->isHidden() - ? tr::lng_cloud_password_was_set(tr::now) - : tr::lng_cloud_password_updated(tr::now); - getDelegate()->show(Box(text)); + _newPasswordSet.fire_copy(newPasswordBytes); if (weak) { - closeBox(); + const auto text = _reenterPasscode->isHidden() + ? tr::lng_cloud_password_removed(tr::now) + : _oldPasscode->isHidden() + ? tr::lng_cloud_password_was_set(tr::now) + : tr::lng_cloud_password_updated(tr::now); + getDelegate()->show(Box(text)); + if (weak) { + closeBox(); + } } } @@ -799,25 +848,40 @@ void PasscodeBox::setNewCloudPassword(const QString &newPassword) { } const auto hint = _passwordHint->getLastText(); const auto email = _recoverEmail->getLastText().trimmed(); - const auto flags = MTPDaccount_passwordInputSettings::Flag::f_new_algo - | MTPDaccount_passwordInputSettings::Flag::f_new_password_hash - | MTPDaccount_passwordInputSettings::Flag::f_hint - | MTPDaccount_passwordInputSettings::Flag::f_email; + using Flag = MTPDaccount_passwordInputSettings::Flag; + const auto flags = Flag::f_new_algo + | Flag::f_new_password_hash + | Flag::f_hint + | (_cloudFields.fromRecoveryCode.isEmpty() ? Flag::f_email : Flag(0)); _checkPasswordCallback = nullptr; - _setRequest = _api.request(MTPaccount_UpdatePasswordSettings( - MTP_inputCheckPasswordEmpty(), - MTP_account_passwordInputSettings( - MTP_flags(flags), - Core::PrepareCloudPasswordAlgo(_cloudFields.newAlgo), - MTP_bytes(newPasswordHash.modpow), - MTP_string(hint), - MTP_string(email), - MTPSecureSecretSettings()) - )).done([=](const MTPBool &result) { - setPasswordDone(newPasswordBytes); - }).fail([=](const MTP::Error &error) { - setPasswordFail(newPasswordBytes, email, error); - }).handleFloodErrors().send(); + + const auto settings = MTP_account_passwordInputSettings( + MTP_flags(flags), + Core::PrepareCloudPasswordAlgo(_cloudFields.newAlgo), + MTP_bytes(newPasswordHash.modpow), + MTP_string(hint), + MTP_string(email), + MTPSecureSecretSettings()); + if (_cloudFields.fromRecoveryCode.isEmpty()) { + _setRequest = _api.request(MTPaccount_UpdatePasswordSettings( + MTP_inputCheckPasswordEmpty(), + settings + )).done([=](const MTPBool &result) { + setPasswordDone(newPasswordBytes); + }).fail([=](const MTP::Error &error) { + setPasswordFail(newPasswordBytes, email, error); + }).handleFloodErrors().send(); + } else { + _setRequest = _api.request(MTPauth_RecoverPassword( + MTP_flags(MTPauth_RecoverPassword::Flag::f_new_settings), + MTP_string(_cloudFields.fromRecoveryCode), + settings + )).done([=](const MTPauth_Authorization &result) { + + }).fail([=](const MTP::Error &error) { + setPasswordFail(newPasswordBytes, email, error); + }).handleFloodErrors().send(); + } } void PasscodeBox::changeCloudPassword( @@ -1005,6 +1069,7 @@ void PasscodeBox::emailChanged() { void PasscodeBox::recoverByEmail() { if (!_cloudFields.hasRecovery) { + Assert(_session != nullptr); const auto session = _session; const auto confirmBox = std::make_shared>(); const auto reset = crl::guard(this, [=] { @@ -1036,19 +1101,19 @@ void PasscodeBox::recoverExpired() { } void PasscodeBox::recover() { - if (_pattern == "-") return; + if (_pattern == "-" || !_session) { + return; + } const auto weak = Ui::MakeWeak(this); const auto box = getDelegate()->show(Box( + &_api.instance(), _session, _pattern, - _cloudFields.notEmptyPassport, - _cloudFields.pendingResetDate != 0, + _cloudFields, [weak] { if (weak) { weak->closeBox(); } })); - box->passwordCleared( - ) | rpl::map_to( - QByteArray() + box->newPasswordSet( ) | rpl::start_to_stream(_newPasswordSet, lifetime()); box->recoveryExpired( @@ -1071,18 +1136,19 @@ void PasscodeBox::recoverStartFail(const MTP::Error &error) { RecoverBox::RecoverBox( QWidget*, - not_null session, + not_null mtp, + Main::Session *session, const QString &pattern, - bool notEmptyPassport, - bool hasPendingReset, + const PasscodeBox::CloudFields &fields, Fn closeParent) -: _api(&session->mtp()) +: _session(session) +, _api(mtp) , _pattern(st::normalFont->elided(tr::lng_signin_recover_hint(tr::now, lt_recover_email, pattern), st::boxWidth - st::boxPadding.left() * 1.5)) -, _notEmptyPassport(notEmptyPassport) +, _cloudFields(fields) , _recoverCode(this, st::defaultInputField, tr::lng_signin_code()) , _noEmailAccess(this, tr::lng_signin_try_password(tr::now)) , _closeParent(std::move(closeParent)) { - if (hasPendingReset) { + if (_cloudFields.pendingResetDate != 0 || !session) { _noEmailAccess.destroy(); } else { _noEmailAccess->setClickedCallback([=] { @@ -1106,8 +1172,8 @@ RecoverBox::RecoverBox( } } -rpl::producer<> RecoverBox::passwordCleared() const { - return _passwordCleared.events(); +rpl::producer RecoverBox::newPasswordSet() const { + return _newPasswordSet.events(); } rpl::producer<> RecoverBox::recoveryExpired() const { @@ -1173,17 +1239,15 @@ void RecoverBox::submit() { } const auto send = crl::guard(this, [=] { - _submitRequest = _api.request(MTPauth_RecoverPassword( - MTP_flags(0), - MTP_string(code), - MTPaccount_PasswordInputSettings() - )).done([=](const MTPauth_Authorization &result) { - codeSubmitDone(result); + _submitRequest = _api.request(MTPauth_CheckRecoveryPassword( + MTP_string(code) + )).done([=](const MTPBool &result) { + checkSubmitDone(code, result); }).fail([=](const MTP::Error &error) { - codeSubmitFail(error); + checkSubmitFail(error); }).handleFloodErrors().send(); }); - if (_notEmptyPassport) { + if (_cloudFields.notEmptyPassport) { const auto confirmed = [=](Fn &&close) { send(); close(); @@ -1209,16 +1273,38 @@ void RecoverBox::codeChanged() { setError(QString()); } -void RecoverBox::codeSubmitDone(const MTPauth_Authorization &result) { +void RecoverBox::checkSubmitDone(const QString &code, const MTPBool &result) { _submitRequest = 0; - _passwordCleared.fire({}); - getDelegate()->show( - Box(tr::lng_cloud_password_removed(tr::now)), - Ui::LayerOption::CloseOther); + auto fields = _cloudFields; + fields.fromRecoveryCode = code; + fields.hasRecovery = false; + // we could've been turning off, no need to force new password then + // like if (_cloudFields.turningOff) { just RecoverPassword else Check } + fields.turningOff = ??? + fields.curRequest = {}; + auto box = Box(_session, fields); + + box->boxClosing( + ) | rpl::start_with_next([=] { + const auto weak = Ui::MakeWeak(this); + if (const auto onstack = _closeParent) { + onstack(); + } + if (weak) { + weak->closeBox(); + } + }, lifetime()); + + box->newPasswordSet( + ) | rpl::start_with_next([=](QByteArray &&password) { + _newPasswordSet.fire(std::move(password)); + }, lifetime()); + + getDelegate()->show(std::move(box)); } -void RecoverBox::codeSubmitFail(const MTP::Error &error) { +void RecoverBox::checkSubmitFail(const MTP::Error &error) { if (MTP::IsFloodError(error)) { _submitRequest = 0; setError(tr::lng_flood_error(tr::now)); @@ -1229,7 +1315,7 @@ void RecoverBox::codeSubmitFail(const MTP::Error &error) { const QString &err = error.type(); if (err == qstr("PASSWORD_EMPTY")) { - _passwordCleared.fire({}); + _newPasswordSet.fire(QByteArray()); getDelegate()->show( Box(tr::lng_cloud_password_removed(tr::now)), Ui::LayerOption::CloseOther); diff --git a/Telegram/SourceFiles/boxes/passcode_box.h b/Telegram/SourceFiles/boxes/passcode_box.h index 1d17f5fab..65c83bfa2 100644 --- a/Telegram/SourceFiles/boxes/passcode_box.h +++ b/Telegram/SourceFiles/boxes/passcode_box.h @@ -11,6 +11,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mtproto/sender.h" #include "core/core_cloud_password.h" +namespace MTP { +class Instance; +} // namespace MTP + namespace Main { class Session; } // namespace Main @@ -35,6 +39,7 @@ public: Core::CloudPasswordCheckRequest curRequest; Core::CloudPasswordAlgo newAlgo; bool hasRecovery = false; + QString fromRecoveryCode; bool notEmptyPassport = false; QString hint; Core::SecureSecretAlgo newSecureSecretAlgo; @@ -47,6 +52,11 @@ public: std::optional customDescription; rpl::producer customSubmitButton; }; + PasscodeBox( + QWidget*, + not_null mtp, + Main::Session *session, + const CloudFields &fields); PasscodeBox( QWidget*, not_null session, @@ -56,6 +66,8 @@ public: rpl::producer<> passwordReloadNeeded() const; rpl::producer<> clearUnconfirmedPassword() const; + rpl::producer newAuthorization() const; + bool handleCustomCheckError(const MTP::Error &error); bool handleCustomCheckError(const QString &type); @@ -83,6 +95,9 @@ private: bool onlyCheckCurrent() const; void setPasswordDone(const QByteArray &newPasswordBytes); + void recoverPasswordDone( + const QByteArray &newPasswordBytes, + const MTPauth_Authorization &result); void setPasswordFail(const MTP::Error &error); void setPasswordFail(const QString &type); void setPasswordFail( @@ -132,7 +147,7 @@ private: void passwordChecked(); void serverError(); - const not_null _session; + Main::Session *_session = nullptr; MTP::Sender _api; QString _pattern; @@ -163,6 +178,7 @@ private: QString _oldError, _newError, _emailError; rpl::event_stream _newPasswordSet; + rpl::event_stream _newAuthorization; rpl::event_stream<> _passwordReloadNeeded; rpl::event_stream<> _clearUnconfirmedPassword; @@ -172,14 +188,14 @@ class RecoverBox final : public Ui::BoxContent { public: RecoverBox( QWidget*, - not_null session, + not_null mtp, + Main::Session *session, const QString &pattern, - bool notEmptyPassport, - bool hasPendingReset, + const PasscodeBox::CloudFields &fields, Fn closeParent = nullptr); - rpl::producer<> passwordCleared() const; - rpl::producer<> recoveryExpired() const; + [[nodiscard]] rpl::producer newPasswordSet() const; + [[nodiscard]] rpl::producer<> recoveryExpired() const; //void reloadPassword(); //void recoveryExpired(); @@ -194,15 +210,17 @@ protected: private: void submit(); void codeChanged(); - void codeSubmitDone(const MTPauth_Authorization &result); - void codeSubmitFail(const MTP::Error &error); + void checkSubmitDone(const QString &code, const MTPBool &result); + void checkSubmitFail(const MTP::Error &error); void setError(const QString &error); + Main::Session *_session = nullptr; MTP::Sender _api; mtpRequestId _submitRequest = 0; QString _pattern; - bool _notEmptyPassport = false; + + PasscodeBox::CloudFields _cloudFields; object_ptr _recoverCode; object_ptr _noEmailAccess; @@ -210,7 +228,7 @@ private: QString _error; - rpl::event_stream<> _passwordCleared; + rpl::event_stream _newPasswordSet; rpl::event_stream<> _recoveryExpired; }; diff --git a/Telegram/SourceFiles/intro/intro_code.cpp b/Telegram/SourceFiles/intro/intro_code.cpp index 99073bb39..bdfcfa4dc 100644 --- a/Telegram/SourceFiles/intro/intro_code.cpp +++ b/Telegram/SourceFiles/intro/intro_code.cpp @@ -341,12 +341,12 @@ void CodeWidget::gotPassword(const MTPaccount_Password &result) { stopCheck(); _sentRequest = 0; const auto &d = result.c_account_password(); - getData()->pwdRequest = Core::ParseCloudPasswordCheckRequest(d); + getData()->pwdState = Core::ParseCloudPasswordState(d); if (!d.vcurrent_algo() || !d.vsrp_id() || !d.vsrp_B()) { LOG(("API Error: No current password received on login.")); _code->setFocus(); return; - } else if (!getData()->pwdRequest) { + } else if (!getData()->pwdState.request) { const auto callback = [=](Fn &&close) { Core::UpdateApplication(); close(); @@ -357,9 +357,6 @@ void CodeWidget::gotPassword(const MTPaccount_Password &result) { callback)); return; } - getData()->hasRecovery = d.is_has_recovery(); - getData()->pwdHint = qs(d.vhint().value_or_empty()); - getData()->pwdNotEmptyPassport = d.is_has_secure_values(); goReplace(Animate::Forward); } @@ -381,10 +378,7 @@ void CodeWidget::submit() { _checkRequestTimer.callEach(1000); _sentCode = text; - getData()->pwdRequest = Core::CloudPasswordCheckRequest(); - getData()->hasRecovery = false; - getData()->pwdHint = QString(); - getData()->pwdNotEmptyPassport = false; + getData()->pwdState = Core::CloudPasswordState(); _sentRequest = api().request(MTPauth_SignIn( MTP_string(getData()->phone), MTP_bytes(getData()->phoneHash), diff --git a/Telegram/SourceFiles/intro/intro_password_check.cpp b/Telegram/SourceFiles/intro/intro_password_check.cpp index 4110b2daf..7614f347c 100644 --- a/Telegram/SourceFiles/intro/intro_password_check.cpp +++ b/Telegram/SourceFiles/intro/intro_password_check.cpp @@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/file_utilities.h" #include "core/core_cloud_password.h" #include "boxes/confirm_box.h" +#include "boxes/passcode_box.h" #include "lang/lang_keys.h" #include "intro/intro_signup.h" #include "ui/widgets/buttons.h" @@ -29,16 +30,13 @@ PasswordCheckWidget::PasswordCheckWidget( not_null account, not_null data) : Step(parent, account, data) -, _request(getData()->pwdRequest) -, _hasRecovery(getData()->hasRecovery) -, _notEmptyPassport(getData()->pwdNotEmptyPassport) -, _hint(getData()->pwdHint) +, _passwordState(getData()->pwdState) , _pwdField(this, st::introPassword, tr::lng_signin_password()) , _pwdHint(this, st::introPasswordHint) , _codeField(this, st::introPassword, tr::lng_signin_code()) , _toRecover(this, tr::lng_signin_recover(tr::now)) , _toPassword(this, tr::lng_signin_try_password(tr::now)) { - Expects(!!_request); + Expects(!!_passwordState.request); Lang::Updated( ) | rpl::start_with_next([=] { @@ -53,11 +51,13 @@ PasswordCheckWidget::PasswordCheckWidget( setTitleText(tr::lng_signin_title()); updateDescriptionText(); - if (_hint.isEmpty()) { + if (_passwordState.hint.isEmpty()) { _pwdHint->hide(); } else { - _pwdHint->setText( - tr::lng_signin_hint(tr::now, lt_password_hint, _hint)); + _pwdHint->setText(tr::lng_signin_hint( + tr::now, + lt_password_hint, + _passwordState.hint)); } _codeField->hide(); _toPassword->hide(); @@ -73,9 +73,11 @@ void PasswordCheckWidget::refreshLang() { _toPassword->setText( tr::lng_signin_try_password(tr::now)); } - if (!_hint.isEmpty()) { - _pwdHint->setText( - tr::lng_signin_hint(tr::now, lt_password_hint, _hint)); + if (!_passwordState.hint.isEmpty()) { + _pwdHint->setText(tr::lng_signin_hint( + tr::now, + lt_password_hint, + _passwordState.hint)); } updateControlsGeometry(); } @@ -167,7 +169,7 @@ void PasswordCheckWidget::handleSrpIdInvalid() { const auto now = crl::now(); if (_lastSrpIdInvalidTime > 0 && now - _lastSrpIdInvalidTime < Core::kHandleSrpIdInvalidTimeout) { - _request.id = 0; + _passwordState.request.id = 0; showError(rpl::single(Lang::Hard::ServerError())); } else { _lastSrpIdInvalidTime = now; @@ -176,7 +178,7 @@ void PasswordCheckWidget::handleSrpIdInvalid() { } void PasswordCheckWidget::checkPasswordHash() { - if (_request.id) { + if (_passwordState.request.id) { passwordChecked(); } else { requestPasswordData(); @@ -190,12 +192,8 @@ void PasswordCheckWidget::requestPasswordData() { ).done([=](const MTPaccount_Password &result) { _sentRequest = 0; result.match([&](const MTPDaccount_password &data) { - auto request = Core::ParseCloudPasswordCheckRequest(data); - if (request && request.id) { - _request = std::move(request); - } else { - // Maybe the password was removed? Just submit it once again. - } + openssl::AddRandomSeed(bytes::make_span(data.vsecure_random().v)); + _passwordState = Core::ParseCloudPasswordState(data); passwordChecked(); }); }).send(); @@ -203,12 +201,12 @@ void PasswordCheckWidget::requestPasswordData() { void PasswordCheckWidget::passwordChecked() { const auto check = Core::ComputeCloudPasswordCheck( - _request, + _passwordState.request, _passwordHash); if (!check) { return serverError(); } - _request.id = 0; + _passwordState.request.id = 0; _sentRequest = api().request( MTPauth_CheckPassword(check.result) ).done([=](const MTPauth_Authorization &result) { @@ -222,6 +220,23 @@ void PasswordCheckWidget::serverError() { showError(rpl::single(Lang::Hard::ServerError())); } +void PasswordCheckWidget::codeSubmitDone( + const QString &code, + const MTPBool &result) { + auto fields = PasscodeBox::CloudFields::From(_passwordState); + fields.fromRecoveryCode = code; + fields.hasRecovery = false; + fields.curRequest = {}; + auto box = Box(&api().instance(), nullptr, fields); + + box->newAuthorization( + ) | rpl::start_with_next([=](const MTPauth_Authorization &result) { + pwdSubmitDone(true, result); + }, lifetime()); + + Ui::show(std::move(box)); +} + void PasswordCheckWidget::codeSubmitFail(const MTP::Error &error) { if (MTP::IsFloodError(error)) { showError(tr::lng_flood_error()); @@ -269,7 +284,7 @@ void PasswordCheckWidget::recoverStartFail(const MTP::Error &error) { } void PasswordCheckWidget::toRecover() { - if (_hasRecovery) { + if (_passwordState.hasRecovery) { if (_sentRequest) { api().request(base::take(_sentRequest)).cancel(); } @@ -339,18 +354,16 @@ void PasswordCheckWidget::submit() { return; } const auto send = crl::guard(this, [=] { - _sentRequest = api().request(MTPauth_RecoverPassword( - MTP_flags(0), - MTP_string(code), - MTPaccount_PasswordInputSettings() - )).done([=](const MTPauth_Authorization &result) { - pwdSubmitDone(true, result); + _sentRequest = api().request(MTPauth_CheckRecoveryPassword( + MTP_string(code) + )).done([=](const MTPBool &result) { + codeSubmitDone(code, result); }).fail([=](const MTP::Error &error) { codeSubmitFail(error); }).handleFloodErrors().send(); }); - if (_notEmptyPassport) { + if (_passwordState.notEmptyPassport) { const auto confirmed = [=](Fn &&close) { send(); close(); @@ -367,7 +380,7 @@ void PasswordCheckWidget::submit() { const auto password = _pwdField->getLastText().toUtf8(); _passwordHash = Core::ComputeCloudPasswordHash( - _request.algo, + _passwordState.request.algo, bytes::make_span(password)); checkPasswordHash(); } diff --git a/Telegram/SourceFiles/intro/intro_password_check.h b/Telegram/SourceFiles/intro/intro_password_check.h index aae6e9855..ddd117551 100644 --- a/Telegram/SourceFiles/intro/intro_password_check.h +++ b/Telegram/SourceFiles/intro/intro_password_check.h @@ -50,6 +50,7 @@ private: void pwdSubmitDone(bool recover, const MTPauth_Authorization &result); void pwdSubmitFail(const MTP::Error &error); + void codeSubmitDone(const QString &code, const MTPBool &result); void codeSubmitFail(const MTP::Error &error); void recoverStartFail(const MTP::Error &error); @@ -62,12 +63,10 @@ private: void passwordChecked(); void serverError(); - Core::CloudPasswordCheckRequest _request; + Core::CloudPasswordState _passwordState; crl::time _lastSrpIdInvalidTime = 0; bytes::vector _passwordHash; - bool _hasRecovery = false; - bool _notEmptyPassport = false; - QString _hint, _emailPattern; + QString _emailPattern; object_ptr _pwdField; object_ptr _pwdHint; diff --git a/Telegram/SourceFiles/intro/intro_qr.cpp b/Telegram/SourceFiles/intro/intro_qr.cpp index e93f01ee9..3be3db8eb 100644 --- a/Telegram/SourceFiles/intro/intro_qr.cpp +++ b/Telegram/SourceFiles/intro/intro_qr.cpp @@ -391,13 +391,12 @@ void QrWidget::sendCheckPasswordRequest() { _requestId = api().request(MTPaccount_GetPassword( )).done([=](const MTPaccount_Password &result) { result.match([&](const MTPDaccount_password &data) { - getData()->pwdRequest = Core::ParseCloudPasswordCheckRequest( - data); + getData()->pwdState = Core::ParseCloudPasswordState(data); if (!data.vcurrent_algo() || !data.vsrp_id() || !data.vsrp_B()) { LOG(("API Error: No current password received on login.")); goReplace(Animate::Forward); return; - } else if (!getData()->pwdRequest) { + } else if (!getData()->pwdState.request) { const auto callback = [=](Fn &&close) { Core::UpdateApplication(); close(); @@ -408,9 +407,6 @@ void QrWidget::sendCheckPasswordRequest() { callback)); return; } - getData()->hasRecovery = data.is_has_recovery(); - getData()->pwdHint = qs(data.vhint().value_or_empty()); - getData()->pwdNotEmptyPassport = data.is_has_secure_values(); goReplace(Animate::Forward); }); }).fail([=](const MTP::Error &error) { diff --git a/Telegram/SourceFiles/intro/intro_widget.h b/Telegram/SourceFiles/intro/intro_widget.h index 5f30c2206..b701a4efa 100644 --- a/Telegram/SourceFiles/intro/intro_widget.h +++ b/Telegram/SourceFiles/intro/intro_widget.h @@ -56,10 +56,7 @@ struct Data { int codeLength = 5; bool codeByTelegram = false; - Core::CloudPasswordCheckRequest pwdRequest; - bool hasRecovery = false; - QString pwdHint; - bool pwdNotEmptyPassport = false; + Core::CloudPasswordState pwdState; Window::TermsLock termsLock; diff --git a/Telegram/SourceFiles/passport/passport_form_controller.cpp b/Telegram/SourceFiles/passport/passport_form_controller.cpp index b48942325..6a18e2b02 100644 --- a/Telegram/SourceFiles/passport/passport_form_controller.cpp +++ b/Telegram/SourceFiles/passport/passport_form_controller.cpp @@ -1000,15 +1000,25 @@ void FormController::recoverPassword() { const auto &data = result.c_auth_passwordRecovery(); const auto pattern = qs(data.vemail_pattern()); + auto fields = PasscodeBox::CloudFields{ + .newAlgo = _password.newAlgo, + .hasRecovery = _password.hasRecovery, + .newSecureSecretAlgo = _password.newSecureAlgo, + .pendingResetDate = _password.pendingResetDate, + }; const auto box = _view->show(Box( + &_controller->session().mtp(), &_controller->session(), pattern, - _password.notEmptyPassport, - _password.pendingResetDate != 0)); + fields)); - box->passwordCleared( - ) | rpl::start_with_next([=] { - reloadPassword(); + box->newPasswordSet( + ) | rpl::start_with_next([=](const QByteArray &password) { + if (password.isEmpty()) { + reloadPassword(); + } else { + reloadAndSubmitPassword(password); + } }, box->lifetime()); box->recoveryExpired( diff --git a/Telegram/SourceFiles/passport/passport_panel_controller.cpp b/Telegram/SourceFiles/passport/passport_panel_controller.cpp index 05e27fdd3..f1197ddb8 100644 --- a/Telegram/SourceFiles/passport/passport_panel_controller.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_controller.cpp @@ -684,23 +684,23 @@ void PanelController::setupPassword() { return; } - auto fields = PasscodeBox::CloudFields(); - fields.newAlgo = settings.newAlgo; - fields.newSecureSecretAlgo = settings.newSecureAlgo; + auto fields = PasscodeBox::CloudFields{ + .newAlgo = settings.newAlgo, + .hasRecovery = settings.hasRecovery, + .newSecureSecretAlgo = settings.newSecureAlgo, + .pendingResetDate = settings.pendingResetDate, + }; auto box = show(Box(&_form->window()->session(), fields)); box->newPasswordSet( - ) | rpl::filter([=](const QByteArray &password) { - return !password.isEmpty(); - }) | rpl::start_with_next([=](const QByteArray &password) { - _form->reloadAndSubmitPassword(password); + ) | rpl::start_with_next([=](const QByteArray &password) { + if (password.isEmpty()) { + _form->reloadPassword(); + } else { + _form->reloadAndSubmitPassword(password); + } }, box->lifetime()); - rpl::merge( - box->passwordReloadNeeded(), - box->newPasswordSet( - ) | rpl::filter([=](const QByteArray &password) { - return password.isEmpty(); - }) | rpl::to_empty + box->passwordReloadNeeded( ) | rpl::start_with_next([=] { _form->reloadPassword(); }, box->lifetime());