Ask for a new password when recovering by email.

This commit is contained in:
John Preston 2021-07-30 17:33:26 +03:00
parent 5a882d1fdc
commit c3595f2e31
9 changed files with 256 additions and 143 deletions

View File

@ -189,21 +189,33 @@ PasscodeBox::PasscodeBox(
PasscodeBox::PasscodeBox(
QWidget*,
not_null<Main::Session*> session,
not_null<MTP::Instance*> 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<Main::Session*> session,
const CloudFields &fields)
: PasscodeBox(nullptr, &session->mtp(), session, fields) {
}
rpl::producer<QByteArray> PasscodeBox::newPasswordSet() const {
return _newPasswordSet.events();
}
@ -225,6 +244,10 @@ rpl::producer<> PasscodeBox::clearUnconfirmedPassword() const {
return _clearUnconfirmedPassword.events();
}
rpl::producer<MTPauth_Authorization> 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<InformBox>(
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<InformBox>(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<InformBox>(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<QPointer<BoxContent>>();
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<RecoverBox>(
&_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<Main::Session*> session,
not_null<MTP::Instance*> mtp,
Main::Session *session,
const QString &pattern,
bool notEmptyPassport,
bool hasPendingReset,
const PasscodeBox::CloudFields &fields,
Fn<void()> 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<QByteArray> 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<void()> &&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<InformBox>(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<PasscodeBox>(_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<InformBox>(tr::lng_cloud_password_removed(tr::now)),
Ui::LayerOption::CloseOther);

View File

@ -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<QString> customDescription;
rpl::producer<QString> customSubmitButton;
};
PasscodeBox(
QWidget*,
not_null<MTP::Instance*> mtp,
Main::Session *session,
const CloudFields &fields);
PasscodeBox(
QWidget*,
not_null<Main::Session*> session,
@ -56,6 +66,8 @@ public:
rpl::producer<> passwordReloadNeeded() const;
rpl::producer<> clearUnconfirmedPassword() const;
rpl::producer<MTPauth_Authorization> 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<Main::Session*> _session;
Main::Session *_session = nullptr;
MTP::Sender _api;
QString _pattern;
@ -163,6 +178,7 @@ private:
QString _oldError, _newError, _emailError;
rpl::event_stream<QByteArray> _newPasswordSet;
rpl::event_stream<MTPauth_Authorization> _newAuthorization;
rpl::event_stream<> _passwordReloadNeeded;
rpl::event_stream<> _clearUnconfirmedPassword;
@ -172,14 +188,14 @@ class RecoverBox final : public Ui::BoxContent {
public:
RecoverBox(
QWidget*,
not_null<Main::Session*> session,
not_null<MTP::Instance*> mtp,
Main::Session *session,
const QString &pattern,
bool notEmptyPassport,
bool hasPendingReset,
const PasscodeBox::CloudFields &fields,
Fn<void()> closeParent = nullptr);
rpl::producer<> passwordCleared() const;
rpl::producer<> recoveryExpired() const;
[[nodiscard]] rpl::producer<QByteArray> 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<Ui::InputField> _recoverCode;
object_ptr<Ui::LinkButton> _noEmailAccess;
@ -210,7 +228,7 @@ private:
QString _error;
rpl::event_stream<> _passwordCleared;
rpl::event_stream<QByteArray> _newPasswordSet;
rpl::event_stream<> _recoveryExpired;
};

View File

@ -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<void()> &&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<PasswordCheckWidget>(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),

View File

@ -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<Main::Account*> account,
not_null<Data*> 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<PasscodeBox>(&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<void()> &&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();
}

View File

@ -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<Ui::PasswordInput> _pwdField;
object_ptr<Ui::FlatLabel> _pwdHint;

View File

@ -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<QrWidget>(Animate::Forward);
return;
} else if (!getData()->pwdRequest) {
} else if (!getData()->pwdState.request) {
const auto callback = [=](Fn<void()> &&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<PasswordCheckWidget>(Animate::Forward);
});
}).fail([=](const MTP::Error &error) {

View File

@ -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;

View File

@ -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<RecoverBox>(
&_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(

View File

@ -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<PasscodeBox>(&_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());