diff --git a/Telegram/Resources/scheme.tl b/Telegram/Resources/scheme.tl index 1e59f42e7..0f79d5205 100644 --- a/Telegram/Resources/scheme.tl +++ b/Telegram/Resources/scheme.tl @@ -587,7 +587,7 @@ authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string s account.authorizations#1250abde authorizations:Vector = account.Authorizations; account.noPassword#5ea182f6 new_salt:bytes new_secure_salt:bytes secure_random:bytes email_unconfirmed_pattern:string = account.Password; -account.password#d06c5fc3 current_salt:bytes new_salt:bytes new_secure_salt:bytes secure_random:bytes hint:string has_recovery:Bool email_unconfirmed_pattern:string = account.Password; +account.password#ca39b447 flags:# has_recovery:flags.0?true has_secure_values:flags.1?true current_salt:bytes new_salt:bytes new_secure_salt:bytes secure_random:bytes hint:string email_unconfirmed_pattern:string = account.Password; account.passwordSettings#7bd9c3f1 email:string secure_salt:bytes secure_secret:bytes secure_secret_id:long = account.PasswordSettings; diff --git a/Telegram/SourceFiles/boxes/passcode_box.cpp b/Telegram/SourceFiles/boxes/passcode_box.cpp index bef44ab80..6ad516f82 100644 --- a/Telegram/SourceFiles/boxes/passcode_box.cpp +++ b/Telegram/SourceFiles/boxes/passcode_box.cpp @@ -33,6 +33,7 @@ PasscodeBox::PasscodeBox( const QByteArray &newSalt, const QByteArray &curSalt, bool hasRecovery, + bool notEmptyPassport, const QString &hint, const QByteArray &newSecureSecretSalt, bool turningOff) @@ -42,6 +43,7 @@ PasscodeBox::PasscodeBox( , _curSalt(curSalt) , _newSecureSecretSalt(newSecureSecretSalt) , _hasRecovery(hasRecovery) +, _notEmptyPassport(notEmptyPassport) , _about(st::boxWidth - st::boxPadding.left() * 1.5) , _oldPasscode(this, st::defaultInputField, langFactory(lng_cloud_password_enter_old)) , _newPasscode(this, st::defaultInputField, langFactory(curSalt.isEmpty() ? lng_cloud_password_enter_first : lng_cloud_password_enter_new)) @@ -339,30 +341,31 @@ void PasscodeBox::save(bool force) { void PasscodeBox::clearCloudPassword(const QString &oldPassword) { Expects(!_oldPasscode->isHidden()); + const auto send = [=] { + sendClearCloudPassword(oldPassword); + }; + if (_notEmptyPassport) { + const auto box = std::make_shared>(); + const auto confirmed = [=] { + send(); + if (*box) { + (*box)->closeBox(); + } + }; + *box = getDelegate()->show(Box( + lang(lng_cloud_password_passport_losing), + lang(lng_continue), + confirmed)); + } else { + send(); + } +} + +void PasscodeBox::sendClearCloudPassword(const QString &oldPassword) { const auto passwordUtf = oldPassword.toUtf8(); const auto oldPasswordData = (_curSalt + passwordUtf + _curSalt); auto oldPasswordHash = QByteArray(32, Qt::Uninitialized); hashSha256(oldPasswordData.constData(), oldPasswordData.size(), oldPasswordHash.data()); - _setRequest = request(MTPaccount_GetPasswordSettings( - MTP_bytes(oldPasswordHash) - )).done([=](const MTPaccount_PasswordSettings &result) { - _setRequest = 0; - - Expects(result.type() == mtpc_account_passwordSettings); - const auto &data = result.c_account_passwordSettings(); - - if (data.vsecure_secret.v.isEmpty()) { - sendClearCloudPassword(oldPasswordHash); - return; - } - warnPassportLoss(oldPasswordHash); - }).fail([=](const RPCError &error) { - setPasswordFail(error); - }).send(); -} - -void PasscodeBox::sendClearCloudPassword( - const QByteArray &oldPasswordHash) { const auto newPasswordData = QByteArray(); const auto newPasswordHash = QByteArray(); const auto hint = QString(); @@ -389,20 +392,6 @@ void PasscodeBox::sendClearCloudPassword( }).send(); } -void PasscodeBox::warnPassportLoss(const QByteArray &oldPasswordHash) { - const auto box = std::make_shared>(); - const auto sendAndClose = [=] { - sendClearCloudPassword(oldPasswordHash); - if (*box) { - (*box)->closeBox(); - } - }; - *box = getDelegate()->show(Box( - lang(lng_cloud_password_passport_losing), - lang(lng_continue), - sendAndClose)); -} - void PasscodeBox::setNewCloudPassword(const QString &newPassword) { const auto newPasswordData = (_newSalt + newPassword.toUtf8() + _newSalt); auto newPasswordHash = QByteArray(32, Qt::Uninitialized); @@ -611,7 +600,9 @@ void PasscodeBox::recoverExpired() { void PasscodeBox::recover() { if (_pattern == "-") return; - const auto box = getDelegate()->show(Box(_pattern)); + const auto box = getDelegate()->show(Box( + _pattern, + _notEmptyPassport)); connect(box, &RecoverBox::reloadPassword, this, &PasscodeBox::reloadPassword); connect(box, &RecoverBox::recoveryExpired, this, &PasscodeBox::recoverExpired); _replacedBy = box; @@ -630,8 +621,12 @@ bool PasscodeBox::recoverStartFail(const RPCError &error) { return true; } -RecoverBox::RecoverBox(QWidget*, const QString &pattern) +RecoverBox::RecoverBox( + QWidget*, + const QString &pattern, + bool notEmptyPassport) : _pattern(st::normalFont->elided(lng_signin_recover_hint(lt_recover_email, pattern), st::boxWidth - st::boxPadding.left() * 1.5)) +, _notEmptyPassport(notEmptyPassport) , _recoverCode(this, st::defaultInputField, langFactory(lng_signin_code)) { } @@ -684,7 +679,27 @@ void RecoverBox::submit() { return; } - _submitRequest = MTP::send(MTPauth_RecoverPassword(MTP_string(code)), rpcDone(&RecoverBox::codeSubmitDone, true), rpcFail(&RecoverBox::codeSubmitFail)); + const auto send = base::lambda_guarded(this, [=] { + _submitRequest = MTP::send( + MTPauth_RecoverPassword(MTP_string(code)), + rpcDone(&RecoverBox::codeSubmitDone, true), + rpcFail(&RecoverBox::codeSubmitFail)); + }); + if (_notEmptyPassport) { + const auto box = std::make_shared>(); + const auto confirmed = [=] { + send(); + if (*box) { + (*box)->closeBox(); + } + }; + *box = getDelegate()->show(Box( + lang(lng_cloud_password_passport_losing), + lang(lng_continue), + confirmed)); + } else { + send(); + } } void RecoverBox::codeChanged() { diff --git a/Telegram/SourceFiles/boxes/passcode_box.h b/Telegram/SourceFiles/boxes/passcode_box.h index 78e79ee19..b746b6085 100644 --- a/Telegram/SourceFiles/boxes/passcode_box.h +++ b/Telegram/SourceFiles/boxes/passcode_box.h @@ -26,6 +26,7 @@ public: const QByteArray &newSalt, const QByteArray &curSalt, bool hasRecovery, + bool notEmptyPassport, const QString &hint, const QByteArray &newSecureSecretSalt, bool turningOff = false); @@ -73,8 +74,7 @@ private: void resetSecretAndChangePassword( const QByteArray &oldPasswordHash, const QString &newPassword); - void sendClearCloudPassword(const QByteArray &oldPasswordHash); - void warnPassportLoss(const QByteArray &oldPasswordHash); + void sendClearCloudPassword(const QString &oldPassword); QString _pattern; @@ -85,6 +85,7 @@ private: QByteArray _newSalt, _curSalt, _newSecureSecretSalt; bool _hasRecovery = false; + bool _notEmptyPassport = false; bool _skipEmailWarning = false; int _aboutHeight = 0; @@ -106,7 +107,7 @@ class RecoverBox : public BoxContent, public RPCSender { Q_OBJECT public: - RecoverBox(QWidget*, const QString &pattern); + RecoverBox(QWidget*, const QString &pattern, bool notEmptyPassport); signals: void reloadPassword(); @@ -128,6 +129,7 @@ private: mtpRequestId _submitRequest = 0; QString _pattern; + bool _notEmptyPassport = false; object_ptr _recoverCode; diff --git a/Telegram/SourceFiles/intro/introcode.cpp b/Telegram/SourceFiles/intro/introcode.cpp index eae3431e9..f1d6d3376 100644 --- a/Telegram/SourceFiles/intro/introcode.cpp +++ b/Telegram/SourceFiles/intro/introcode.cpp @@ -296,8 +296,9 @@ void CodeWidget::gotPassword(const MTPaccount_Password &result) { case mtpc_account_password: { auto &d = result.c_account_password(); getData()->pwdSalt = qba(d.vcurrent_salt); - getData()->hasRecovery = mtpIsTrue(d.vhas_recovery); + getData()->hasRecovery = d.is_has_recovery(); getData()->pwdHint = qs(d.vhint); + getData()->pwdNotEmptyPassport = d.is_has_secure_values(); goReplace(new Intro::PwdCheckWidget(parentWidget(), getData())); } break; } @@ -314,6 +315,7 @@ void CodeWidget::submit() { getData()->pwdSalt = QByteArray(); getData()->hasRecovery = false; getData()->pwdHint = QString(); + getData()->pwdNotEmptyPassport = false; _sentRequest = MTP::send(MTPauth_SignIn(MTP_string(getData()->phone), MTP_bytes(getData()->phoneHash), MTP_string(_sentCode)), rpcDone(&CodeWidget::codeSubmitDone), rpcFail(&CodeWidget::codeSubmitFail)); } diff --git a/Telegram/SourceFiles/intro/intropwdcheck.cpp b/Telegram/SourceFiles/intro/intropwdcheck.cpp index b055bfc08..b4bcb6433 100644 --- a/Telegram/SourceFiles/intro/intropwdcheck.cpp +++ b/Telegram/SourceFiles/intro/intropwdcheck.cpp @@ -23,6 +23,7 @@ namespace Intro { PwdCheckWidget::PwdCheckWidget(QWidget *parent, Widget::Data *data) : Step(parent, data) , _salt(getData()->pwdSalt) , _hasRecovery(getData()->hasRecovery) +, _notEmptyPassport(getData()->pwdNotEmptyPassport) , _hint(getData()->pwdHint) , _pwdField(this, st::introPassword, langFactory(lng_signin_password)) , _pwdHint(this, st::introPasswordHint) @@ -276,8 +277,28 @@ void PwdCheckWidget::submit() { _codeField->showError(); return; } + const auto send = base::lambda_guarded(this, [=] { + _sentRequest = MTP::send( + MTPauth_RecoverPassword(MTP_string(code)), + rpcDone(&PwdCheckWidget::pwdSubmitDone, true), + rpcFail(&PwdCheckWidget::codeSubmitFail)); + }); - _sentRequest = MTP::send(MTPauth_RecoverPassword(MTP_string(code)), rpcDone(&PwdCheckWidget::pwdSubmitDone, true), rpcFail(&PwdCheckWidget::codeSubmitFail)); + if (_notEmptyPassport) { + const auto box = std::make_shared>(); + const auto confirmed = [=] { + send(); + if (*box) { + (*box)->closeBox(); + } + }; + *box = Ui::show(Box( + lang(lng_cloud_password_passport_losing), + lang(lng_continue), + confirmed)); + } else { + send(); + } } else { hideError(); diff --git a/Telegram/SourceFiles/intro/intropwdcheck.h b/Telegram/SourceFiles/intro/intropwdcheck.h index 804626cd4..3f5cc3b7f 100644 --- a/Telegram/SourceFiles/intro/intropwdcheck.h +++ b/Telegram/SourceFiles/intro/intropwdcheck.h @@ -55,7 +55,8 @@ private: void stopCheck(); QByteArray _salt; - bool _hasRecovery; + bool _hasRecovery = false; + bool _notEmptyPassport = false; QString _hint, _emailPattern; object_ptr _pwdField; diff --git a/Telegram/SourceFiles/intro/introwidget.h b/Telegram/SourceFiles/intro/introwidget.h index 054df4131..cec682ee1 100644 --- a/Telegram/SourceFiles/intro/introwidget.h +++ b/Telegram/SourceFiles/intro/introwidget.h @@ -76,6 +76,7 @@ public: QByteArray pwdSalt; bool hasRecovery = false; QString pwdHint; + bool pwdNotEmptyPassport = false; TextWithEntities termsText; bool termsPopup = false; diff --git a/Telegram/SourceFiles/passport/passport_form_controller.cpp b/Telegram/SourceFiles/passport/passport_form_controller.cpp index 31dd9569b..c5fdb6d41 100644 --- a/Telegram/SourceFiles/passport/passport_form_controller.cpp +++ b/Telegram/SourceFiles/passport/passport_form_controller.cpp @@ -408,7 +408,9 @@ void FormController::recoverPassword() { const auto &data = result.c_auth_passwordRecovery(); const auto pattern = qs(data.vemail_pattern); - const auto box = _view->show(Box(pattern)); + const auto box = _view->show(Box( + pattern, + _password.notEmptyPassport)); box->connect(box, &RecoverBox::reloadPassword, [=] { reloadPassword(); }); @@ -1910,7 +1912,8 @@ bool FormController::applyPassword(const MTPDaccount_noPassword &result) { bool FormController::applyPassword(const MTPDaccount_password &result) { auto settings = PasswordSettings(); settings.hint = qs(result.vhint); - settings.hasRecovery = mtpIsTrue(result.vhas_recovery); + settings.hasRecovery = result.is_has_recovery(); + settings.notEmptyPassport = result.is_has_secure_values(); settings.salt = bytes::make_vector(result.vcurrent_salt.v); settings.unconfirmedPattern = qs(result.vemail_unconfirmed_pattern); settings.newSalt = bytes::make_vector(result.vnew_salt.v); diff --git a/Telegram/SourceFiles/passport/passport_form_controller.h b/Telegram/SourceFiles/passport/passport_form_controller.h index d66eb503d..df453e130 100644 --- a/Telegram/SourceFiles/passport/passport_form_controller.h +++ b/Telegram/SourceFiles/passport/passport_form_controller.h @@ -182,6 +182,7 @@ struct PasswordSettings { QString unconfirmedPattern; QString confirmedEmail; bool hasRecovery = false; + bool notEmptyPassport = false; bool operator==(const PasswordSettings &other) const { return (salt == other.salt) diff --git a/Telegram/SourceFiles/passport/passport_panel_controller.cpp b/Telegram/SourceFiles/passport/passport_panel_controller.cpp index 8c39edb21..2d1173a43 100644 --- a/Telegram/SourceFiles/passport/passport_panel_controller.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_controller.cpp @@ -446,11 +446,13 @@ void PanelController::setupPassword() { newSecureSecretSalt).subspan(settings.newSecureSalt.size())); const auto currentSalt = QByteArray(); const auto hasRecovery = false; + const auto notEmptyPassport = false; const auto hint = QString(); auto box = show(Box( newPasswordSalt, currentSalt, hasRecovery, + notEmptyPassport, hint, newSecureSecretSalt)); box->connect(box, &PasscodeBox::reloadPassword, _panel.get(), [=] { @@ -697,7 +699,7 @@ void PanelController::suggestReset(base::lambda callback) { Lang::Hard::PassportCorrupted(), Lang::Hard::PassportCorruptedReset(), [=] { resetPassport(callback); }, - [=] { cancelReset(); })).data()); // #TODO passport no need for confirmation? + [=] { cancelReset(); })).data()); } void PanelController::resetPassport(base::lambda callback) { diff --git a/Telegram/SourceFiles/passport/passport_panel_details_row.cpp b/Telegram/SourceFiles/passport/passport_panel_details_row.cpp index 6db34120c..2a41182b3 100644 --- a/Telegram/SourceFiles/passport/passport_panel_details_row.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_details_row.cpp @@ -310,8 +310,12 @@ void CountryRow::errorAnimationCallback() { void CountryRow::chooseCountry() { const auto top = _value.current(); const auto name = CountrySelectBox::NameByISO(top); - const auto box = _controller->show(Box( - (name.isEmpty() ? Platform::SystemCountry() : top), + const auto isoByPhone = CountrySelectBox::ISOByPhone(App::self()->phone()); + const auto box = _controller->show(Box(!name.isEmpty() + ? top + : !isoByPhone.isEmpty() + ? isoByPhone + : Platform::SystemCountry(), CountrySelectBox::Type::Countries)); connect(box, &CountrySelectBox::countryChosen, this, [=](QString iso) { _value = iso; diff --git a/Telegram/SourceFiles/settings/settings_privacy_widget.cpp b/Telegram/SourceFiles/settings/settings_privacy_widget.cpp index 68e622707..de762564c 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_privacy_widget.cpp @@ -78,6 +78,7 @@ void CloudPasswordState::onEdit() { _newPasswordSalt, _curPasswordSalt, _hasPasswordRecovery, + _notEmptyPassport, _curPasswordHint, _newSecureSecretSalt)); connect(box, SIGNAL(reloadPassword()), this, SLOT(onReloadPassword())); @@ -106,6 +107,7 @@ void CloudPasswordState::onTurnOff() { _newPasswordSalt, _curPasswordSalt, _hasPasswordRecovery, + _notEmptyPassport, _curPasswordHint, _newSecureSecretSalt, true)); @@ -113,13 +115,21 @@ void CloudPasswordState::onTurnOff() { } } +void CloudPasswordState::onReloadPassword() { + if (_reloadRequestId) { + return; + } + _reloadRequestId = MTP::send(MTPaccount_GetPassword(), rpcDone(&CloudPasswordState::getPasswordDone), rpcFail(&CloudPasswordState::getPasswordFail)); +} + void CloudPasswordState::onReloadPassword(Qt::ApplicationState state) { - if (state == Qt::ApplicationActive) { - MTP::send(MTPaccount_GetPassword(), rpcDone(&CloudPasswordState::getPasswordDone)); + if (!_waitingConfirm.isEmpty() && state == Qt::ApplicationActive) { + onReloadPassword(); } } void CloudPasswordState::getPasswordDone(const MTPaccount_Password &result) { + _reloadRequestId = 0; _waitingConfirm = QString(); switch (result.type()) { @@ -127,6 +137,7 @@ void CloudPasswordState::getPasswordDone(const MTPaccount_Password &result) { auto &d = result.c_account_noPassword(); _curPasswordSalt = QByteArray(); _hasPasswordRecovery = false; + _notEmptyPassport = false; _curPasswordHint = QString(); _newPasswordSalt = qba(d.vnew_salt); _newSecureSecretSalt = qba(d.vnew_secure_salt); @@ -140,7 +151,8 @@ void CloudPasswordState::getPasswordDone(const MTPaccount_Password &result) { case mtpc_account_password: { auto &d = result.c_account_password(); _curPasswordSalt = qba(d.vcurrent_salt); - _hasPasswordRecovery = mtpIsTrue(d.vhas_recovery); + _hasPasswordRecovery = d.is_has_recovery(); + _notEmptyPassport = d.is_has_secure_values(); _curPasswordHint = qs(d.vhint); _newPasswordSalt = qba(d.vnew_salt); _newSecureSecretSalt = qba(d.vnew_secure_salt); @@ -166,6 +178,14 @@ void CloudPasswordState::getPasswordDone(const MTPaccount_Password &result) { 8); } +bool CloudPasswordState::getPasswordFail(const RPCError &error) { + if (MTP::isDefaultHandledError(error)) { + return false; + } + _reloadRequestId = 0; + return true; +} + void CloudPasswordState::paintEvent(QPaintEvent *e) { Painter p(this); diff --git a/Telegram/SourceFiles/settings/settings_privacy_widget.h b/Telegram/SourceFiles/settings/settings_privacy_widget.h index e81c10e6b..b0a070be5 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_widget.h +++ b/Telegram/SourceFiles/settings/settings_privacy_widget.h @@ -50,10 +50,12 @@ protected: private slots: void onEdit(); void onTurnOff(); - void onReloadPassword(Qt::ApplicationState state = Qt::ApplicationActive); + void onReloadPassword(); + void onReloadPassword(Qt::ApplicationState state); private: void getPasswordDone(const MTPaccount_Password &result); + bool getPasswordFail(const RPCError &error); void offPasswordDone(const MTPBool &result); bool offPasswordFail(const RPCError &error); @@ -63,9 +65,11 @@ private: QString _waitingConfirm; QByteArray _curPasswordSalt; bool _hasPasswordRecovery = false; + bool _notEmptyPassport = false; QString _curPasswordHint; QByteArray _newPasswordSalt; QByteArray _newSecureSecretSalt; + mtpRequestId _reloadRequestId = 0; }; diff --git a/Telegram/SourceFiles/ui/countryinput.cpp b/Telegram/SourceFiles/ui/countryinput.cpp index acf02c1ae..29d1482a9 100644 --- a/Telegram/SourceFiles/ui/countryinput.cpp +++ b/Telegram/SourceFiles/ui/countryinput.cpp @@ -219,6 +219,17 @@ QString CountrySelectBox::NameByISO(const QString &iso) { : QString::fromUtf8((*i)->name); } +QString CountrySelectBox::ISOByPhone(const QString &phone) { + if (_countriesByCode.isEmpty()) { + initCountries(); + } + const auto code = findValidCode(phone); + const auto i = _countriesByCode.find(code); + return (i == _countriesByCode.cend()) + ? QString() + : QString::fromUtf8((*i)->iso2); +} + void CountrySelectBox::prepare() { setTitle(langFactory(lng_country_select)); diff --git a/Telegram/SourceFiles/ui/countryinput.h b/Telegram/SourceFiles/ui/countryinput.h index bc2f941c6..9b277dc92 100644 --- a/Telegram/SourceFiles/ui/countryinput.h +++ b/Telegram/SourceFiles/ui/countryinput.h @@ -65,6 +65,7 @@ public: CountrySelectBox(QWidget*, const QString &iso, Type type); static QString NameByISO(const QString &iso); + static QString ISOByPhone(const QString &phone); signals: void countryChosen(const QString &iso);