diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index fe64ace2ef..1febca0d39 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -406,6 +406,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_cloud_password_differ" = "Passwords do not match"; "lng_cloud_password_wrong" = "Wrong cloud password"; "lng_cloud_password_is_same" = "Password was not changed"; +"lng_cloud_password_passport_losing" = "Warning! All data saved in your Telegram Passport will be lost!"; "lng_connection_type" = "Connection type:"; "lng_connection_auto_connecting" = "Default (connecting...)"; diff --git a/Telegram/SourceFiles/boxes/passcode_box.cpp b/Telegram/SourceFiles/boxes/passcode_box.cpp index 6eb1173814..bef44ab804 100644 --- a/Telegram/SourceFiles/boxes/passcode_box.cpp +++ b/Telegram/SourceFiles/boxes/passcode_box.cpp @@ -12,9 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/confirm_box.h" #include "mainwindow.h" #include "storage/localstorage.h" -#include "styles/style_boxes.h" #include "ui/widgets/buttons.h" #include "ui/widgets/input_fields.h" +#include "passport/passport_encryption.h" +#include "styles/style_boxes.h" PasscodeBox::PasscodeBox(QWidget*, bool turningOff) : _turningOff(turningOff) @@ -27,11 +28,19 @@ PasscodeBox::PasscodeBox(QWidget*, bool turningOff) , _recover(this, lang(lng_signin_recover)) { } -PasscodeBox::PasscodeBox(QWidget*, const QByteArray &newSalt, const QByteArray &curSalt, bool hasRecovery, const QString &hint, bool turningOff) +PasscodeBox::PasscodeBox( + QWidget*, + const QByteArray &newSalt, + const QByteArray &curSalt, + bool hasRecovery, + const QString &hint, + const QByteArray &newSecureSecretSalt, + bool turningOff) : _turningOff(turningOff) , _cloudPwd(true) , _newSalt(newSalt) , _curSalt(curSalt) +, _newSecureSecretSalt(newSecureSecretSalt) , _hasRecovery(hasRecovery) , _about(st::boxWidth - st::boxPadding.left() * 1.5) , _oldPasscode(this, st::defaultInputField, langFactory(lng_cloud_password_enter_old)) @@ -186,7 +195,7 @@ void PasscodeBox::setInnerFocus() { } } -void PasscodeBox::setPasswordDone(const MTPBool &result) { +void PasscodeBox::setPasswordDone() { _setRequest = 0; emit reloadPassword(); auto text = lang(_reenterPasscode->isHidden() ? lng_cloud_password_removed : (_oldPasscode->isHidden() ? lng_cloud_password_was_set : lng_cloud_password_updated)); @@ -312,43 +321,12 @@ void PasscodeBox::save(bool force) { _replacedBy = getDelegate()->show(Box(lang(lng_cloud_password_about_recover), lang(lng_cloud_password_skip_email), st::attentionBoxButton, base::lambda_guarded(this, [this] { save(true); }))); + } else if (_newPasscode->isHidden()) { + clearCloudPassword(old); + } else if (_oldPasscode->isHidden()) { + setNewCloudPassword(pwd); } else { - QByteArray newPasswordData = pwd.isEmpty() ? QByteArray() : (_newSalt + pwd.toUtf8() + _newSalt); - QByteArray newPasswordHash = pwd.isEmpty() ? QByteArray() : QByteArray(32, Qt::Uninitialized); - if (pwd.isEmpty()) { - hint = QString(); - email = QString(); - } else { - hashSha256(newPasswordData.constData(), newPasswordData.size(), newPasswordHash.data()); - } - QByteArray oldPasswordData = _oldPasscode->isHidden() ? QByteArray() : (_curSalt + old.toUtf8() + _curSalt); - QByteArray oldPasswordHash = _oldPasscode->isHidden() ? QByteArray() : QByteArray(32, Qt::Uninitialized); - if (!_oldPasscode->isHidden()) { - hashSha256(oldPasswordData.constData(), oldPasswordData.size(), oldPasswordHash.data()); - } - auto flags = MTPDaccount_passwordInputSettings::Flag::f_new_salt - | MTPDaccount_passwordInputSettings::Flag::f_new_password_hash - | MTPDaccount_passwordInputSettings::Flag::f_hint; - if (_oldPasscode->isHidden() || _newPasscode->isHidden()) { - flags |= MTPDaccount_passwordInputSettings::Flag::f_email; - } - const auto newSecureSecret = bytes::vector(); - const auto newSecureSalt = bytes::vector(); - const auto newSecureSecretHash = 0ULL; - _setRequest = MTP::send( - MTPaccount_UpdatePasswordSettings( - MTP_bytes(oldPasswordHash), - MTP_account_passwordInputSettings( - MTP_flags(flags), - MTP_bytes(_newSalt), - MTP_bytes(newPasswordHash), - MTP_string(hint), - MTP_string(email), - MTP_bytes(newSecureSalt), - MTP_bytes(newSecureSecret), - MTP_long(newSecureSecretHash))), - rpcDone(&PasscodeBox::setPasswordDone), - rpcFail(&PasscodeBox::setPasswordFail)); + changeCloudPassword(old, pwd); } } else { cSetPasscodeBadTries(0); @@ -358,6 +336,225 @@ void PasscodeBox::save(bool force) { } } +void PasscodeBox::clearCloudPassword(const QString &oldPassword) { + Expects(!_oldPasscode->isHidden()); + + 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(); + const auto email = QString(); + const auto flags = MTPDaccount_passwordInputSettings::Flag::f_new_salt + | MTPDaccount_passwordInputSettings::Flag::f_new_password_hash + | MTPDaccount_passwordInputSettings::Flag::f_hint + | MTPDaccount_passwordInputSettings::Flag::f_email; + _setRequest = request(MTPaccount_UpdatePasswordSettings( + MTP_bytes(oldPasswordHash), + MTP_account_passwordInputSettings( + MTP_flags(flags), + MTP_bytes(_newSalt), + MTP_bytes(newPasswordHash), + MTP_string(hint), + MTP_string(email), + MTPbytes(), // new_secure_salt + MTPbytes(), // new_secure_secret + MTPlong()) // new_secure_secret_id + )).done([=](const MTPBool &result) { + setPasswordDone(); + }).fail([=](const RPCError &error) { + setPasswordFail(error); + }).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); + hashSha256(newPasswordData.constData(), newPasswordData.size(), newPasswordHash.data()); + const auto oldPasswordData = QByteArray(); + const auto oldPasswordHash = QByteArray(); + const auto hint = _passwordHint->getLastText(); + const auto email = _recoverEmail->getLastText().trimmed(); + const auto flags = MTPDaccount_passwordInputSettings::Flag::f_new_salt + | MTPDaccount_passwordInputSettings::Flag::f_new_password_hash + | MTPDaccount_passwordInputSettings::Flag::f_hint + | MTPDaccount_passwordInputSettings::Flag::f_email; + _setRequest = request(MTPaccount_UpdatePasswordSettings( + MTP_bytes(oldPasswordHash), + MTP_account_passwordInputSettings( + MTP_flags(flags), + MTP_bytes(_newSalt), + MTP_bytes(newPasswordHash), + MTP_string(hint), + MTP_string(email), + MTPbytes(), // new_secure_salt + MTPbytes(), // new_secure_secret + MTPlong()) // new_secure_secret_id + )).done([=](const MTPBool &result) { + setPasswordDone(); + }).fail([=](const RPCError &error) { + setPasswordFail(error); + }).send(); +} + +void PasscodeBox::changeCloudPassword( + const QString &oldPassword, + const QString &newPassword) { + 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()) { + const auto empty = QByteArray(); + sendChangeCloudPassword(oldPasswordHash, newPassword, empty); + return; + } + const auto secret = Passport::DecryptSecureSecret( + bytes::make_span(data.vsecure_salt.v), + bytes::make_span(data.vsecure_secret.v), + bytes::make_span(passwordUtf)); + if (secret.empty()) { + LOG(("API Error: Failed to decrypt secure secret.")); + suggestSecretReset(oldPasswordHash, newPassword); + } else if (Passport::CountSecureSecretId(secret) != data.vsecure_secret_id.v) { + LOG(("API Error: Wrong secure secret id.")); + suggestSecretReset(oldPasswordHash, newPassword); + } else { + sendChangeCloudPassword( + oldPasswordHash, + newPassword, + QByteArray::fromRawData( + reinterpret_cast(secret.data()), + secret.size())); + } + }).fail([=](const RPCError &error) { + setPasswordFail(error); + }).send(); +} + +void PasscodeBox::suggestSecretReset( + const QByteArray &oldPasswordHash, + const QString &newPassword) { + const auto box = std::make_shared>(); + const auto resetSecretAndSave = [=] { + using Flag = MTPDaccount_passwordInputSettings::Flag; + _setRequest = request(MTPaccount_UpdatePasswordSettings( + MTP_bytes(oldPasswordHash), + MTP_account_passwordInputSettings( + MTP_flags(Flag::f_new_secure_salt + | Flag::f_new_secure_secret + | Flag::f_new_secure_secret_id), + MTPbytes(), // new_salt + MTPbytes(), // new_password_hash + MTPstring(), // hint + MTPstring(), // email + MTP_bytes(QByteArray()), // new_secure_salt + MTP_bytes(QByteArray()), // new_secure_secret + MTP_long(0)) // new_secure_secret_id + )).done([=](const MTPBool &result) { + _setRequest = 0; + const auto empty = QByteArray(); + if (*box) { + (*box)->closeBox(); + } + sendChangeCloudPassword(oldPasswordHash, newPassword, empty); + }).fail([=](const RPCError &error) { + _setRequest = 0; + }).send(); + }; + *box = getDelegate()->show(Box( + Lang::Hard::PassportCorrupted(), + Lang::Hard::PassportCorruptedReset(), + [=] { resetSecretAndSave(); })); +} + +void PasscodeBox::sendChangeCloudPassword( + const QByteArray &oldPasswordHash, + const QString &newPassword, + const QByteArray &secureSecret) { + const auto passwordUtf = newPassword.toUtf8(); + const auto newPasswordData = (_newSalt + passwordUtf + _newSalt); + auto newPasswordHash = QByteArray(32, Qt::Uninitialized); + hashSha256(newPasswordData.constData(), newPasswordData.size(), newPasswordHash.data()); + const auto hint = _passwordHint->getLastText(); + auto flags = MTPDaccount_passwordInputSettings::Flag::f_new_salt + | MTPDaccount_passwordInputSettings::Flag::f_new_password_hash + | MTPDaccount_passwordInputSettings::Flag::f_hint; + auto newSecureSecret = bytes::vector(); + auto newSecureSecretId = 0ULL; + if (!secureSecret.isEmpty()) { + flags |= MTPDaccount_passwordInputSettings::Flag::f_new_secure_salt + | MTPDaccount_passwordInputSettings::Flag::f_new_secure_secret + | MTPDaccount_passwordInputSettings::Flag::f_new_secure_secret_id; + newSecureSecretId = Passport::CountSecureSecretId( + bytes::make_span(secureSecret)); + newSecureSecret = Passport::EncryptSecureSecret( + bytes::make_span(_newSecureSecretSalt), + bytes::make_span(secureSecret), + bytes::make_span(passwordUtf)); + } + _setRequest = request(MTPaccount_UpdatePasswordSettings( + MTP_bytes(oldPasswordHash), + MTP_account_passwordInputSettings( + MTP_flags(flags), + MTP_bytes(_newSalt), + MTP_bytes(newPasswordHash), + MTP_string(hint), + MTPstring(), // email is not changing + MTP_bytes(_newSecureSecretSalt), + MTP_bytes(newSecureSecret), + MTP_long(newSecureSecretId)) + )).done([=](const MTPBool &result) { + setPasswordDone(); + }).fail([=](const RPCError &error) { + setPasswordFail(error); + }).send(); +} + void PasscodeBox::badOldPasscode() { _oldPasscode->selectAll(); _oldPasscode->setFocus(); @@ -396,7 +593,12 @@ void PasscodeBox::emailChanged() { void PasscodeBox::recoverByEmail() { if (_pattern.isEmpty()) { _pattern = "-"; - MTP::send(MTPauth_RequestPasswordRecovery(), rpcDone(&PasscodeBox::recoverStarted), rpcFail(&PasscodeBox::recoverStartFail)); + request(MTPauth_RequestPasswordRecovery( + )).done([=](const MTPauth_PasswordRecovery &result) { + recoverStarted(result); + }).fail([=](const RPCError &error) { + recoverStartFail(error); + }).send(); } else { recover(); } diff --git a/Telegram/SourceFiles/boxes/passcode_box.h b/Telegram/SourceFiles/boxes/passcode_box.h index f339d27d8a..78e79ee19e 100644 --- a/Telegram/SourceFiles/boxes/passcode_box.h +++ b/Telegram/SourceFiles/boxes/passcode_box.h @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "boxes/abstract_box.h" +#include "mtproto/sender.h" namespace Ui { class InputField; @@ -15,12 +16,19 @@ class PasswordInput; class LinkButton; } // namespace Ui -class PasscodeBox : public BoxContent, public RPCSender { +class PasscodeBox : public BoxContent, private MTP::Sender { Q_OBJECT public: PasscodeBox(QWidget*, bool turningOff); - PasscodeBox(QWidget*, const QByteArray &newSalt, const QByteArray &curSalt, bool hasRecovery, const QString &hint, bool turningOff = false); + PasscodeBox( + QWidget*, + const QByteArray &newSalt, + const QByteArray &curSalt, + bool hasRecovery, + const QString &hint, + const QByteArray &newSecureSecretSalt, + bool turningOff = false); signals: void reloadPassword(); @@ -43,13 +51,31 @@ private: void recoverByEmail(); void recoverExpired(); - void setPasswordDone(const MTPBool &result); + void setPasswordDone(); bool setPasswordFail(const RPCError &error); void recoverStarted(const MTPauth_PasswordRecovery &result); bool recoverStartFail(const RPCError &error); void recover(); + void clearCloudPassword(const QString &oldPassword); + void setNewCloudPassword(const QString &newPassword); + void changeCloudPassword( + const QString &oldPassword, + const QString &newPassword); + void sendChangeCloudPassword( + const QByteArray &oldPasswordHash, + const QString &newPassword, + const QByteArray &secureSecret); + void suggestSecretReset( + const QByteArray &oldPasswordHash, + const QString &newPassword); + void resetSecretAndChangePassword( + const QByteArray &oldPasswordHash, + const QString &newPassword); + void sendClearCloudPassword(const QByteArray &oldPasswordHash); + void warnPassportLoss(const QByteArray &oldPasswordHash); + QString _pattern; QPointer _replacedBy; @@ -57,7 +83,7 @@ private: bool _cloudPwd = false; mtpRequestId _setRequest = 0; - QByteArray _newSalt, _curSalt; + QByteArray _newSalt, _curSalt, _newSecureSecretSalt; bool _hasRecovery = false; bool _skipEmailWarning = false; diff --git a/Telegram/SourceFiles/passport/passport_form_controller.cpp b/Telegram/SourceFiles/passport/passport_form_controller.cpp index 8b35518e7d..8b5b8e62a1 100644 --- a/Telegram/SourceFiles/passport/passport_form_controller.cpp +++ b/Telegram/SourceFiles/passport/passport_form_controller.cpp @@ -462,7 +462,9 @@ void FormController::suggestReset(bytes::vector password) { _saveSecretRequestId = request(MTPaccount_UpdatePasswordSettings( MTP_bytes(hashForAuth), MTP_account_passwordInputSettings( - MTP_flags(Flag::f_new_secure_secret), + MTP_flags(Flag::f_new_secure_salt + | Flag::f_new_secure_secret + | Flag::f_new_secure_secret_id), MTPbytes(), // new_salt MTPbytes(), // new_password_hash MTPstring(), // hint @@ -1482,7 +1484,9 @@ void FormController::generateSecret(bytes::const_span password) { _saveSecretRequestId = request(MTPaccount_UpdatePasswordSettings( MTP_bytes(hashForAuth), MTP_account_passwordInputSettings( - MTP_flags(Flag::f_new_secure_secret), + MTP_flags(Flag::f_new_secure_salt + | Flag::f_new_secure_secret + | Flag::f_new_secure_secret_id), MTPbytes(), // new_salt MTPbytes(), // new_password_hash MTPstring(), // hint diff --git a/Telegram/SourceFiles/passport/passport_panel_controller.cpp b/Telegram/SourceFiles/passport/passport_panel_controller.cpp index f9b036e0a6..e6433251bb 100644 --- a/Telegram/SourceFiles/passport/passport_panel_controller.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_controller.cpp @@ -427,20 +427,28 @@ void PanelController::setupPassword() { Assert(settings.salt.empty()); constexpr auto kRandomPart = 8; - auto newSalt = QByteArray( + auto newPasswordSalt = QByteArray( reinterpret_cast(settings.newSalt.data()), settings.newSalt.size()); - newSalt.resize(newSalt.size() + kRandomPart); + newPasswordSalt.resize(newPasswordSalt.size() + kRandomPart); bytes::set_random( - bytes::make_span(newSalt).subspan(settings.newSalt.size())); + bytes::make_span(newPasswordSalt).subspan(settings.newSalt.size())); + auto newSecureSecretSalt = QByteArray( + reinterpret_cast(settings.newSecureSalt.data()), + settings.newSecureSalt.size()); + newSecureSecretSalt.resize(newSecureSecretSalt.size() + kRandomPart); + bytes::set_random( + bytes::make_span( + newSecureSecretSalt).subspan(settings.newSecureSalt.size())); const auto currentSalt = QByteArray(); const auto hasRecovery = false; const auto hint = QString(); auto box = show(Box( - newSalt, + newPasswordSalt, currentSalt, hasRecovery, - hint)); + hint, + newSecureSecretSalt)); box->connect(box, &PasscodeBox::reloadPassword, _panel.get(), [=] { _form->reloadPassword(); }); diff --git a/Telegram/SourceFiles/settings/settings_privacy_widget.cpp b/Telegram/SourceFiles/settings/settings_privacy_widget.cpp index 224fc5cf21..68e6227072 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_privacy_widget.cpp @@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lang/lang_keys.h" #include "application.h" #include "platform/platform_specific.h" +#include "base/openssl_help.h" #include "boxes/sessions_box.h" #include "boxes/passcode_box.h" #include "boxes/autolock_box.h" @@ -73,7 +74,12 @@ int CloudPasswordState::resizeGetHeight(int newWidth) { } void CloudPasswordState::onEdit() { - auto box = Ui::show(Box(_newPasswordSalt, _curPasswordSalt, _hasPasswordRecovery, _curPasswordHint)); + auto box = Ui::show(Box( + _newPasswordSalt, + _curPasswordSalt, + _hasPasswordRecovery, + _curPasswordHint, + _newSecureSecretSalt)); connect(box, SIGNAL(reloadPassword()), this, SLOT(onReloadPassword())); } @@ -96,7 +102,13 @@ void CloudPasswordState::onTurnOff() { rpcDone(&CloudPasswordState::offPasswordDone), rpcFail(&CloudPasswordState::offPasswordFail)); } else { - auto box = Ui::show(Box(_newPasswordSalt, _curPasswordSalt, _hasPasswordRecovery, _curPasswordHint, true)); + auto box = Ui::show(Box( + _newPasswordSalt, + _curPasswordSalt, + _hasPasswordRecovery, + _curPasswordHint, + _newSecureSecretSalt, + true)); connect(box, SIGNAL(reloadPassword()), this, SLOT(onReloadPassword())); } } @@ -117,10 +129,12 @@ void CloudPasswordState::getPasswordDone(const MTPaccount_Password &result) { _hasPasswordRecovery = false; _curPasswordHint = QString(); _newPasswordSalt = qba(d.vnew_salt); + _newSecureSecretSalt = qba(d.vnew_secure_salt); auto pattern = qs(d.vemail_unconfirmed_pattern); if (!pattern.isEmpty()) { _waitingConfirm = lng_cloud_password_waiting(lt_email, pattern); } + openssl::AddRandomSeed(bytes::make_span(d.vsecure_random.v)); } break; case mtpc_account_password: { @@ -129,10 +143,12 @@ void CloudPasswordState::getPasswordDone(const MTPaccount_Password &result) { _hasPasswordRecovery = mtpIsTrue(d.vhas_recovery); _curPasswordHint = qs(d.vhint); _newPasswordSalt = qba(d.vnew_salt); + _newSecureSecretSalt = qba(d.vnew_secure_salt); auto pattern = qs(d.vemail_unconfirmed_pattern); if (!pattern.isEmpty()) { _waitingConfirm = lng_cloud_password_waiting(lt_email, pattern); } + openssl::AddRandomSeed(bytes::make_span(d.vsecure_random.v)); } break; } _edit->setText(lang(_curPasswordSalt.isEmpty() ? lng_cloud_password_set : lng_cloud_password_edit)); @@ -141,7 +157,13 @@ void CloudPasswordState::getPasswordDone(const MTPaccount_Password &result) { update(); _newPasswordSalt.resize(_newPasswordSalt.size() + 8); - memset_rand(_newPasswordSalt.data() + _newPasswordSalt.size() - 8, 8); + memset_rand( + _newPasswordSalt.data() + _newPasswordSalt.size() - 8, + 8); + _newSecureSecretSalt.resize(_newSecureSecretSalt.size() + 8); + memset_rand( + _newSecureSecretSalt.data() + _newSecureSecretSalt.size() - 8, + 8); } void CloudPasswordState::paintEvent(QPaintEvent *e) { diff --git a/Telegram/SourceFiles/settings/settings_privacy_widget.h b/Telegram/SourceFiles/settings/settings_privacy_widget.h index b110061671..e81c10e6b2 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_widget.h +++ b/Telegram/SourceFiles/settings/settings_privacy_widget.h @@ -65,6 +65,7 @@ private: bool _hasPasswordRecovery = false; QString _curPasswordHint; QByteArray _newPasswordSalt; + QByteArray _newSecureSecretSalt; };