mirror of https://github.com/procxx/kepka.git
Remember passport credentials for 30 minutes.
This commit is contained in:
parent
9929bfb281
commit
e3e8d083ea
|
@ -54,6 +54,14 @@ PasscodeBox::PasscodeBox(
|
||||||
if (!hint.isEmpty()) _hintText.setText(st::passcodeTextStyle, lng_signin_hint(lt_password_hint, hint));
|
if (!hint.isEmpty()) _hintText.setText(st::passcodeTextStyle, lng_signin_hint(lt_password_hint, hint));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpl::producer<QByteArray> PasscodeBox::newPasswordSet() const {
|
||||||
|
return _newPasswordSet.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<> PasscodeBox::passwordReloadNeeded() const {
|
||||||
|
return _passwordReloadNeeded.events();
|
||||||
|
}
|
||||||
|
|
||||||
void PasscodeBox::prepare() {
|
void PasscodeBox::prepare() {
|
||||||
addButton(langFactory(_turningOff ? lng_passcode_remove_button : lng_settings_save), [=] { save(); });
|
addButton(langFactory(_turningOff ? lng_passcode_remove_button : lng_settings_save), [=] { save(); });
|
||||||
addButton(langFactory(lng_cancel), [=] { closeBox(); });
|
addButton(langFactory(lng_cancel), [=] { closeBox(); });
|
||||||
|
@ -197,9 +205,9 @@ void PasscodeBox::setInnerFocus() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PasscodeBox::setPasswordDone() {
|
void PasscodeBox::setPasswordDone(const QByteArray &newPasswordBytes) {
|
||||||
_setRequest = 0;
|
_setRequest = 0;
|
||||||
emit reloadPassword();
|
_newPasswordSet.fire_copy(newPasswordBytes);
|
||||||
auto text = lang(_reenterPasscode->isHidden() ? lng_cloud_password_removed : (_oldPasscode->isHidden() ? lng_cloud_password_was_set : lng_cloud_password_updated));
|
auto text = lang(_reenterPasscode->isHidden() ? lng_cloud_password_removed : (_oldPasscode->isHidden() ? lng_cloud_password_was_set : lng_cloud_password_updated));
|
||||||
getDelegate()->show(Box<InformBox>(text), LayerOption::CloseOther);
|
getDelegate()->show(Box<InformBox>(text), LayerOption::CloseOther);
|
||||||
}
|
}
|
||||||
|
@ -236,7 +244,7 @@ bool PasscodeBox::setPasswordFail(const RPCError &error) {
|
||||||
QString err = error.type();
|
QString err = error.type();
|
||||||
if (err == qstr("PASSWORD_HASH_INVALID")) {
|
if (err == qstr("PASSWORD_HASH_INVALID")) {
|
||||||
if (_oldPasscode->isHidden()) {
|
if (_oldPasscode->isHidden()) {
|
||||||
emit reloadPassword();
|
_passwordReloadNeeded.fire({});
|
||||||
closeBox();
|
closeBox();
|
||||||
} else {
|
} else {
|
||||||
badOldPasscode();
|
badOldPasscode();
|
||||||
|
@ -247,20 +255,36 @@ bool PasscodeBox::setPasswordFail(const RPCError &error) {
|
||||||
_newError = lang(lng_cloud_password_bad);
|
_newError = lang(lng_cloud_password_bad);
|
||||||
update();
|
update();
|
||||||
} else if (err == qstr("NEW_SALT_INVALID")) {
|
} else if (err == qstr("NEW_SALT_INVALID")) {
|
||||||
emit reloadPassword();
|
_passwordReloadNeeded.fire({});
|
||||||
closeBox();
|
closeBox();
|
||||||
} else if (err == qstr("EMAIL_INVALID")) {
|
} else if (err == qstr("EMAIL_INVALID")) {
|
||||||
_emailError = lang(lng_cloud_password_bad_email);
|
_emailError = lang(lng_cloud_password_bad_email);
|
||||||
_recoverEmail->setFocus();
|
_recoverEmail->setFocus();
|
||||||
_recoverEmail->showError();
|
_recoverEmail->showError();
|
||||||
update();
|
update();
|
||||||
} else if (err == qstr("EMAIL_UNCONFIRMED")) {
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PasscodeBox::setPasswordFail(
|
||||||
|
const QByteArray &newPasswordBytes,
|
||||||
|
const RPCError &error) {
|
||||||
|
if (MTP::isFloodError(error)) {
|
||||||
|
return setPasswordFail(error);
|
||||||
|
} else if (MTP::isDefaultHandledError(error)) {
|
||||||
|
return setPasswordFail(error);
|
||||||
|
} else if (error.type() == qstr("EMAIL_UNCONFIRMED")) {
|
||||||
|
closeReplacedBy();
|
||||||
|
_setRequest = 0;
|
||||||
|
|
||||||
|
_newPasswordSet.fire_copy(newPasswordBytes);
|
||||||
getDelegate()->show(
|
getDelegate()->show(
|
||||||
Box<InformBox>(lang(lng_cloud_password_almost)),
|
Box<InformBox>(lang(lng_cloud_password_almost)),
|
||||||
LayerOption::CloseOther);
|
LayerOption::CloseOther);
|
||||||
emit reloadPassword();
|
return true;
|
||||||
|
} else {
|
||||||
|
return setPasswordFail(error);
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PasscodeBox::save(bool force) {
|
void PasscodeBox::save(bool force) {
|
||||||
|
@ -386,14 +410,15 @@ void PasscodeBox::sendClearCloudPassword(const QString &oldPassword) {
|
||||||
MTPbytes(), // new_secure_secret
|
MTPbytes(), // new_secure_secret
|
||||||
MTPlong()) // new_secure_secret_id
|
MTPlong()) // new_secure_secret_id
|
||||||
)).done([=](const MTPBool &result) {
|
)).done([=](const MTPBool &result) {
|
||||||
setPasswordDone();
|
setPasswordDone({});
|
||||||
}).fail([=](const RPCError &error) {
|
}).fail([=](const RPCError &error) {
|
||||||
setPasswordFail(error);
|
setPasswordFail({}, error);
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PasscodeBox::setNewCloudPassword(const QString &newPassword) {
|
void PasscodeBox::setNewCloudPassword(const QString &newPassword) {
|
||||||
const auto newPasswordData = (_newSalt + newPassword.toUtf8() + _newSalt);
|
const auto newPasswordBytes = newPassword.toUtf8();
|
||||||
|
const auto newPasswordData = (_newSalt + newPasswordBytes + _newSalt);
|
||||||
auto newPasswordHash = QByteArray(32, Qt::Uninitialized);
|
auto newPasswordHash = QByteArray(32, Qt::Uninitialized);
|
||||||
hashSha256(newPasswordData.constData(), newPasswordData.size(), newPasswordHash.data());
|
hashSha256(newPasswordData.constData(), newPasswordData.size(), newPasswordHash.data());
|
||||||
const auto oldPasswordData = QByteArray();
|
const auto oldPasswordData = QByteArray();
|
||||||
|
@ -416,9 +441,9 @@ void PasscodeBox::setNewCloudPassword(const QString &newPassword) {
|
||||||
MTPbytes(), // new_secure_secret
|
MTPbytes(), // new_secure_secret
|
||||||
MTPlong()) // new_secure_secret_id
|
MTPlong()) // new_secure_secret_id
|
||||||
)).done([=](const MTPBool &result) {
|
)).done([=](const MTPBool &result) {
|
||||||
setPasswordDone();
|
setPasswordDone(newPasswordBytes);
|
||||||
}).fail([=](const RPCError &error) {
|
}).fail([=](const RPCError &error) {
|
||||||
setPasswordFail(error);
|
setPasswordFail(newPasswordBytes, error);
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,9 +468,10 @@ void PasscodeBox::changeCloudPassword(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto secret = Passport::DecryptSecureSecret(
|
const auto secret = Passport::DecryptSecureSecret(
|
||||||
bytes::make_span(data.vsecure_salt.v),
|
|
||||||
bytes::make_span(data.vsecure_secret.v),
|
bytes::make_span(data.vsecure_secret.v),
|
||||||
bytes::make_span(passwordUtf));
|
Passport::CountPasswordHashForSecret(
|
||||||
|
bytes::make_span(data.vsecure_salt.v),
|
||||||
|
bytes::make_span(passwordUtf)));
|
||||||
if (secret.empty()) {
|
if (secret.empty()) {
|
||||||
LOG(("API Error: Failed to decrypt secure secret."));
|
LOG(("API Error: Failed to decrypt secure secret."));
|
||||||
suggestSecretReset(oldPasswordHash, newPassword);
|
suggestSecretReset(oldPasswordHash, newPassword);
|
||||||
|
@ -505,8 +531,8 @@ void PasscodeBox::sendChangeCloudPassword(
|
||||||
const QByteArray &oldPasswordHash,
|
const QByteArray &oldPasswordHash,
|
||||||
const QString &newPassword,
|
const QString &newPassword,
|
||||||
const QByteArray &secureSecret) {
|
const QByteArray &secureSecret) {
|
||||||
const auto passwordUtf = newPassword.toUtf8();
|
const auto newPasswordBytes = newPassword.toUtf8();
|
||||||
const auto newPasswordData = (_newSalt + passwordUtf + _newSalt);
|
const auto newPasswordData = (_newSalt + newPasswordBytes + _newSalt);
|
||||||
auto newPasswordHash = QByteArray(32, Qt::Uninitialized);
|
auto newPasswordHash = QByteArray(32, Qt::Uninitialized);
|
||||||
hashSha256(newPasswordData.constData(), newPasswordData.size(), newPasswordHash.data());
|
hashSha256(newPasswordData.constData(), newPasswordData.size(), newPasswordHash.data());
|
||||||
const auto hint = _passwordHint->getLastText();
|
const auto hint = _passwordHint->getLastText();
|
||||||
|
@ -522,9 +548,10 @@ void PasscodeBox::sendChangeCloudPassword(
|
||||||
newSecureSecretId = Passport::CountSecureSecretId(
|
newSecureSecretId = Passport::CountSecureSecretId(
|
||||||
bytes::make_span(secureSecret));
|
bytes::make_span(secureSecret));
|
||||||
newSecureSecret = Passport::EncryptSecureSecret(
|
newSecureSecret = Passport::EncryptSecureSecret(
|
||||||
bytes::make_span(_newSecureSecretSalt),
|
|
||||||
bytes::make_span(secureSecret),
|
bytes::make_span(secureSecret),
|
||||||
bytes::make_span(passwordUtf));
|
Passport::CountPasswordHashForSecret(
|
||||||
|
bytes::make_span(_newSecureSecretSalt),
|
||||||
|
bytes::make_span(newPasswordBytes)));
|
||||||
}
|
}
|
||||||
_setRequest = request(MTPaccount_UpdatePasswordSettings(
|
_setRequest = request(MTPaccount_UpdatePasswordSettings(
|
||||||
MTP_bytes(oldPasswordHash),
|
MTP_bytes(oldPasswordHash),
|
||||||
|
@ -538,9 +565,9 @@ void PasscodeBox::sendChangeCloudPassword(
|
||||||
MTP_bytes(newSecureSecret),
|
MTP_bytes(newSecureSecret),
|
||||||
MTP_long(newSecureSecretId))
|
MTP_long(newSecureSecretId))
|
||||||
)).done([=](const MTPBool &result) {
|
)).done([=](const MTPBool &result) {
|
||||||
setPasswordDone();
|
setPasswordDone(newPasswordBytes);
|
||||||
}).fail([=](const RPCError &error) {
|
}).fail([=](const RPCError &error) {
|
||||||
setPasswordFail(error);
|
setPasswordFail(newPasswordBytes, error);
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -603,8 +630,17 @@ void PasscodeBox::recover() {
|
||||||
const auto box = getDelegate()->show(Box<RecoverBox>(
|
const auto box = getDelegate()->show(Box<RecoverBox>(
|
||||||
_pattern,
|
_pattern,
|
||||||
_notEmptyPassport));
|
_notEmptyPassport));
|
||||||
connect(box, &RecoverBox::reloadPassword, this, &PasscodeBox::reloadPassword);
|
|
||||||
connect(box, &RecoverBox::recoveryExpired, this, &PasscodeBox::recoverExpired);
|
box->passwordCleared(
|
||||||
|
) | rpl::map([] {
|
||||||
|
return QByteArray();
|
||||||
|
}) | rpl::start_to_stream(_newPasswordSet, lifetime());
|
||||||
|
|
||||||
|
box->recoveryExpired(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
recoverExpired();
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
_replacedBy = box;
|
_replacedBy = box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -630,6 +666,14 @@ RecoverBox::RecoverBox(
|
||||||
, _recoverCode(this, st::defaultInputField, langFactory(lng_signin_code)) {
|
, _recoverCode(this, st::defaultInputField, langFactory(lng_signin_code)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpl::producer<> RecoverBox::passwordCleared() const {
|
||||||
|
return _passwordCleared.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<> RecoverBox::recoveryExpired() const {
|
||||||
|
return _recoveryExpired.events();
|
||||||
|
}
|
||||||
|
|
||||||
void RecoverBox::prepare() {
|
void RecoverBox::prepare() {
|
||||||
setTitle(langFactory(lng_signin_recover_title));
|
setTitle(langFactory(lng_signin_recover_title));
|
||||||
|
|
||||||
|
@ -707,10 +751,12 @@ void RecoverBox::codeChanged() {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecoverBox::codeSubmitDone(bool recover, const MTPauth_Authorization &result) {
|
void RecoverBox::codeSubmitDone(
|
||||||
|
bool recover,
|
||||||
|
const MTPauth_Authorization &result) {
|
||||||
_submitRequest = 0;
|
_submitRequest = 0;
|
||||||
|
|
||||||
emit reloadPassword();
|
_passwordCleared.fire({});
|
||||||
getDelegate()->show(
|
getDelegate()->show(
|
||||||
Box<InformBox>(lang(lng_cloud_password_removed)),
|
Box<InformBox>(lang(lng_cloud_password_removed)),
|
||||||
LayerOption::CloseOther);
|
LayerOption::CloseOther);
|
||||||
|
@ -730,7 +776,7 @@ bool RecoverBox::codeSubmitFail(const RPCError &error) {
|
||||||
|
|
||||||
const QString &err = error.type();
|
const QString &err = error.type();
|
||||||
if (err == qstr("PASSWORD_EMPTY")) {
|
if (err == qstr("PASSWORD_EMPTY")) {
|
||||||
emit reloadPassword();
|
_passwordCleared.fire({});
|
||||||
getDelegate()->show(
|
getDelegate()->show(
|
||||||
Box<InformBox>(lang(lng_cloud_password_removed)),
|
Box<InformBox>(lang(lng_cloud_password_removed)),
|
||||||
LayerOption::CloseOther);
|
LayerOption::CloseOther);
|
||||||
|
@ -739,7 +785,7 @@ bool RecoverBox::codeSubmitFail(const RPCError &error) {
|
||||||
closeBox();
|
closeBox();
|
||||||
return true;
|
return true;
|
||||||
} else if (err == qstr("PASSWORD_RECOVERY_EXPIRED")) {
|
} else if (err == qstr("PASSWORD_RECOVERY_EXPIRED")) {
|
||||||
emit recoveryExpired();
|
_recoveryExpired.fire({});
|
||||||
closeBox();
|
closeBox();
|
||||||
return true;
|
return true;
|
||||||
} else if (err == qstr("CODE_INVALID")) {
|
} else if (err == qstr("CODE_INVALID")) {
|
||||||
|
|
|
@ -17,8 +17,6 @@ class LinkButton;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
class PasscodeBox : public BoxContent, private MTP::Sender {
|
class PasscodeBox : public BoxContent, private MTP::Sender {
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PasscodeBox(QWidget*, bool turningOff);
|
PasscodeBox(QWidget*, bool turningOff);
|
||||||
PasscodeBox(
|
PasscodeBox(
|
||||||
|
@ -31,8 +29,8 @@ public:
|
||||||
const QByteArray &newSecureSecretSalt,
|
const QByteArray &newSecureSecretSalt,
|
||||||
bool turningOff = false);
|
bool turningOff = false);
|
||||||
|
|
||||||
signals:
|
rpl::producer<QByteArray> newPasswordSet() const;
|
||||||
void reloadPassword();
|
rpl::producer<> passwordReloadNeeded() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void prepare() override;
|
void prepare() override;
|
||||||
|
@ -52,8 +50,11 @@ private:
|
||||||
void recoverByEmail();
|
void recoverByEmail();
|
||||||
void recoverExpired();
|
void recoverExpired();
|
||||||
|
|
||||||
void setPasswordDone();
|
void setPasswordDone(const QByteArray &newPasswordBytes);
|
||||||
bool setPasswordFail(const RPCError &error);
|
bool setPasswordFail(const RPCError &error);
|
||||||
|
bool setPasswordFail(
|
||||||
|
const QByteArray &newPasswordBytes,
|
||||||
|
const RPCError &error);
|
||||||
|
|
||||||
void recoverStarted(const MTPauth_PasswordRecovery &result);
|
void recoverStarted(const MTPauth_PasswordRecovery &result);
|
||||||
bool recoverStartFail(const RPCError &error);
|
bool recoverStartFail(const RPCError &error);
|
||||||
|
@ -101,17 +102,20 @@ private:
|
||||||
|
|
||||||
QString _oldError, _newError, _emailError;
|
QString _oldError, _newError, _emailError;
|
||||||
|
|
||||||
|
rpl::event_stream<QByteArray> _newPasswordSet;
|
||||||
|
rpl::event_stream<> _passwordReloadNeeded;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class RecoverBox : public BoxContent, public RPCSender {
|
class RecoverBox : public BoxContent, public RPCSender {
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RecoverBox(QWidget*, const QString &pattern, bool notEmptyPassport);
|
RecoverBox(QWidget*, const QString &pattern, bool notEmptyPassport);
|
||||||
|
|
||||||
signals:
|
rpl::producer<> passwordCleared() const;
|
||||||
void reloadPassword();
|
rpl::producer<> recoveryExpired() const;
|
||||||
void recoveryExpired();
|
|
||||||
|
//void reloadPassword();
|
||||||
|
//void recoveryExpired();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void prepare() override;
|
void prepare() override;
|
||||||
|
@ -135,4 +139,7 @@ private:
|
||||||
|
|
||||||
QString _error;
|
QString _error;
|
||||||
|
|
||||||
|
rpl::event_stream<> _passwordCleared;
|
||||||
|
rpl::event_stream<> _recoveryExpired;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "inline_bots/inline_bot_layout_item.h"
|
#include "inline_bots/inline_bot_layout_item.h"
|
||||||
#include "storage/localstorage.h"
|
#include "storage/localstorage.h"
|
||||||
#include "boxes/abstract_box.h"
|
#include "boxes/abstract_box.h"
|
||||||
|
#include "passport/passport_form_controller.h"
|
||||||
#include "data/data_media_types.h"
|
#include "data/data_media_types.h"
|
||||||
#include "data/data_feed.h"
|
#include "data/data_feed.h"
|
||||||
#include "data/data_photo.h"
|
#include "data/data_photo.h"
|
||||||
|
@ -156,6 +157,30 @@ void Session::stopExport() {
|
||||||
_export = nullptr;
|
_export = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Passport::SavedCredentials *Session::passportCredentials() const {
|
||||||
|
return _passportCredentials ? &_passportCredentials->first : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::rememberPassportCredentials(
|
||||||
|
Passport::SavedCredentials data,
|
||||||
|
TimeMs rememberFor) {
|
||||||
|
Expects(rememberFor > 0);
|
||||||
|
|
||||||
|
static auto generation = 0;
|
||||||
|
_passportCredentials = std::make_unique<CredentialsWithGeneration>(
|
||||||
|
std::move(data),
|
||||||
|
++generation);
|
||||||
|
App::CallDelayed(rememberFor, _session, [=, check = generation] {
|
||||||
|
if (_passportCredentials && _passportCredentials->second == check) {
|
||||||
|
forgetPassportCredentials();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::forgetPassportCredentials() {
|
||||||
|
_passportCredentials = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void Session::setupContactViewsViewer() {
|
void Session::setupContactViewsViewer() {
|
||||||
Notify::PeerUpdateViewer(
|
Notify::PeerUpdateViewer(
|
||||||
Notify::PeerUpdate::Flag::UserIsContact
|
Notify::PeerUpdate::Flag::UserIsContact
|
||||||
|
|
|
@ -35,6 +35,10 @@ class PanelController;
|
||||||
} // namespace View
|
} // namespace View
|
||||||
} // namespace Export
|
} // namespace Export
|
||||||
|
|
||||||
|
namespace Passport {
|
||||||
|
struct SavedCredentials;
|
||||||
|
} // namespace Passport
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
class Feed;
|
class Feed;
|
||||||
|
@ -60,6 +64,12 @@ public:
|
||||||
void stopExportWithConfirmation(FnMut<void()> callback);
|
void stopExportWithConfirmation(FnMut<void()> callback);
|
||||||
void stopExport();
|
void stopExport();
|
||||||
|
|
||||||
|
const Passport::SavedCredentials *passportCredentials() const;
|
||||||
|
void rememberPassportCredentials(
|
||||||
|
Passport::SavedCredentials data,
|
||||||
|
TimeMs rememberFor);
|
||||||
|
void forgetPassportCredentials();
|
||||||
|
|
||||||
[[nodiscard]] base::Variable<bool> &contactsLoaded() {
|
[[nodiscard]] base::Variable<bool> &contactsLoaded() {
|
||||||
return _contactsLoaded;
|
return _contactsLoaded;
|
||||||
}
|
}
|
||||||
|
@ -610,6 +620,11 @@ private:
|
||||||
|
|
||||||
MessageIdsList _mimeForwardIds;
|
MessageIdsList _mimeForwardIds;
|
||||||
|
|
||||||
|
using CredentialsWithGeneration = std::pair<
|
||||||
|
const Passport::SavedCredentials,
|
||||||
|
int>;
|
||||||
|
std::unique_ptr<CredentialsWithGeneration> _passportCredentials;
|
||||||
|
|
||||||
rpl::lifetime _lifetime;
|
rpl::lifetime _lifetime;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1096,11 +1096,6 @@ void ApiWrap::appendChatsSlice(
|
||||||
auto filtered = ranges::view::all(
|
auto filtered = ranges::view::all(
|
||||||
info.list
|
info.list
|
||||||
) | ranges::view::filter([&](const Data::DialogInfo &info) {
|
) | ranges::view::filter([&](const Data::DialogInfo &info) {
|
||||||
#ifdef _DEBUG
|
|
||||||
return (info.name == "Anta");
|
|
||||||
#else
|
|
||||||
#error "test"
|
|
||||||
#endif
|
|
||||||
return (types & SettingsFromDialogsType(info.type)) != 0;
|
return (types & SettingsFromDialogsType(info.type)) != 0;
|
||||||
});
|
});
|
||||||
auto &list = to.info.list;
|
auto &list = to.info.list;
|
||||||
|
|
|
@ -19,10 +19,7 @@ namespace Export {
|
||||||
namespace Output {
|
namespace Output {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
#ifndef _DEBUG
|
constexpr auto kMessagesInFile = 1000;
|
||||||
#error test
|
|
||||||
#endif
|
|
||||||
constexpr auto kMessagesInFile = 50;
|
|
||||||
constexpr auto kPersonalUserpicSize = 90;
|
constexpr auto kPersonalUserpicSize = 90;
|
||||||
constexpr auto kEntryUserpicSize = 48;
|
constexpr auto kEntryUserpicSize = 48;
|
||||||
constexpr auto kServiceMessagePhotoSize = 60;
|
constexpr auto kServiceMessagePhotoSize = 60;
|
||||||
|
|
|
@ -90,15 +90,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "styles/style_history.h"
|
#include "styles/style_history.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
#include "export/output/export_output_html.h"
|
|
||||||
#include "export/output/export_output_stats.h"
|
|
||||||
#include "export/view/export_view_panel_controller.h"
|
|
||||||
#include "platform/platform_specific.h"
|
|
||||||
#else
|
|
||||||
#error "test"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
bool IsForceLogoutNotification(const MTPDupdateServiceNotification &data) {
|
bool IsForceLogoutNotification(const MTPDupdateServiceNotification &data) {
|
||||||
|
@ -261,10 +252,6 @@ MainWidget::MainWidget(
|
||||||
Messenger::Instance().mtp()->setUpdatesHandler(rpcDone(&MainWidget::updateReceived));
|
Messenger::Instance().mtp()->setUpdatesHandler(rpcDone(&MainWidget::updateReceived));
|
||||||
Messenger::Instance().mtp()->setGlobalFailHandler(rpcFail(&MainWidget::updateFail));
|
Messenger::Instance().mtp()->setGlobalFailHandler(rpcFail(&MainWidget::updateFail));
|
||||||
|
|
||||||
//Export::Output::HtmlWriter writer;
|
|
||||||
//writer.produceTestExample(psDownloadPath(), Export::View::PrepareEnvironment());
|
|
||||||
//crl::on_main([] { App::quit(); });
|
|
||||||
|
|
||||||
_ptsWaiter.setRequesting(true);
|
_ptsWaiter.setRequesting(true);
|
||||||
updateScrollColors();
|
updateScrollColors();
|
||||||
setupConnectingWidget();
|
setupConnectingWidget();
|
||||||
|
|
|
@ -16,6 +16,7 @@ namespace {
|
||||||
constexpr auto kAesKeyLength = 32;
|
constexpr auto kAesKeyLength = 32;
|
||||||
constexpr auto kAesIvLength = 16;
|
constexpr auto kAesIvLength = 16;
|
||||||
constexpr auto kSecretSize = 32;
|
constexpr auto kSecretSize = 32;
|
||||||
|
constexpr auto kAesParamsHashSize = 64;
|
||||||
constexpr auto kMinPadding = 32;
|
constexpr auto kMinPadding = 32;
|
||||||
constexpr auto kMaxPadding = 255;
|
constexpr auto kMaxPadding = 255;
|
||||||
constexpr auto kAlignTo = 16;
|
constexpr auto kAlignTo = 16;
|
||||||
|
@ -27,18 +28,21 @@ struct AesParams {
|
||||||
bytes::vector iv;
|
bytes::vector iv;
|
||||||
};
|
};
|
||||||
|
|
||||||
AesParams PrepareAesParams(bytes::const_span bytesForEncryptionKey) {
|
AesParams PrepareAesParamsWithHash(bytes::const_span hashForEncryptionKey) {
|
||||||
const auto hash = openssl::Sha512(bytesForEncryptionKey);
|
Expects(hashForEncryptionKey.size() == kAesParamsHashSize);
|
||||||
const auto view = gsl::make_span(hash);
|
|
||||||
|
|
||||||
auto result = AesParams();
|
auto result = AesParams();
|
||||||
result.key = bytes::make_vector(
|
result.key = bytes::make_vector(
|
||||||
view.subspan(0, kAesKeyLength));
|
hashForEncryptionKey.subspan(0, kAesKeyLength));
|
||||||
result.iv = bytes::make_vector(
|
result.iv = bytes::make_vector(
|
||||||
view.subspan(kAesKeyLength, kAesIvLength));
|
hashForEncryptionKey.subspan(kAesKeyLength, kAesIvLength));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AesParams PrepareAesParams(bytes::const_span bytesForEncryptionKey) {
|
||||||
|
return PrepareAesParamsWithHash(openssl::Sha512(bytesForEncryptionKey));
|
||||||
|
}
|
||||||
|
|
||||||
bytes::vector EncryptOrDecrypt(
|
bytes::vector EncryptOrDecrypt(
|
||||||
bytes::const_span initial,
|
bytes::const_span initial,
|
||||||
AesParams &¶ms,
|
AesParams &¶ms,
|
||||||
|
@ -112,9 +116,9 @@ bytes::vector GenerateSecretBytes() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes::vector DecryptSecretBytes(
|
bytes::vector DecryptSecretBytesWithHash(
|
||||||
bytes::const_span encryptedSecret,
|
bytes::const_span encryptedSecret,
|
||||||
bytes::const_span bytesForEncryptionKey) {
|
bytes::const_span hashForEncryptionKey) {
|
||||||
if (encryptedSecret.empty()) {
|
if (encryptedSecret.empty()) {
|
||||||
return {};
|
return {};
|
||||||
} else if (encryptedSecret.size() != kSecretSize) {
|
} else if (encryptedSecret.size() != kSecretSize) {
|
||||||
|
@ -122,7 +126,7 @@ bytes::vector DecryptSecretBytes(
|
||||||
).arg(encryptedSecret.size()));
|
).arg(encryptedSecret.size()));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto params = PrepareAesParams(bytesForEncryptionKey);
|
auto params = PrepareAesParamsWithHash(hashForEncryptionKey);
|
||||||
auto result = Decrypt(encryptedSecret, std::move(params));
|
auto result = Decrypt(encryptedSecret, std::move(params));
|
||||||
if (!CheckSecretBytes(result)) {
|
if (!CheckSecretBytes(result)) {
|
||||||
LOG(("API Error: Bad secret bytes."));
|
LOG(("API Error: Bad secret bytes."));
|
||||||
|
@ -131,6 +135,24 @@ bytes::vector DecryptSecretBytes(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bytes::vector DecryptSecretBytes(
|
||||||
|
bytes::const_span encryptedSecret,
|
||||||
|
bytes::const_span bytesForEncryptionKey) {
|
||||||
|
return DecryptSecretBytesWithHash(
|
||||||
|
encryptedSecret,
|
||||||
|
openssl::Sha512(bytesForEncryptionKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes::vector EncryptSecretBytesWithHash(
|
||||||
|
bytes::const_span secret,
|
||||||
|
bytes::const_span hashForEncryptionKey) {
|
||||||
|
Expects(secret.size() == kSecretSize);
|
||||||
|
Expects(CheckSecretBytes(secret) == true);
|
||||||
|
|
||||||
|
auto params = PrepareAesParamsWithHash(hashForEncryptionKey);
|
||||||
|
return Encrypt(secret, std::move(params));
|
||||||
|
}
|
||||||
|
|
||||||
bytes::vector EncryptSecretBytes(
|
bytes::vector EncryptSecretBytes(
|
||||||
bytes::const_span secret,
|
bytes::const_span secret,
|
||||||
bytes::const_span bytesForEncryptionKey) {
|
bytes::const_span bytesForEncryptionKey) {
|
||||||
|
@ -141,34 +163,31 @@ bytes::vector EncryptSecretBytes(
|
||||||
return Encrypt(secret, std::move(params));
|
return Encrypt(secret, std::move(params));
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes::vector DecryptSecureSecret(
|
bytes::vector CountPasswordHashForSecret(
|
||||||
bytes::const_span salt,
|
bytes::const_span salt,
|
||||||
bytes::const_span encryptedSecret,
|
|
||||||
bytes::const_span password) {
|
bytes::const_span password) {
|
||||||
Expects(!salt.empty());
|
return openssl::Sha512(bytes::concatenate(
|
||||||
Expects(!encryptedSecret.empty());
|
|
||||||
Expects(!password.empty());
|
|
||||||
|
|
||||||
const auto bytesForEncryptionKey = bytes::concatenate(
|
|
||||||
salt,
|
salt,
|
||||||
password,
|
password,
|
||||||
salt);
|
salt));
|
||||||
return DecryptSecretBytes(encryptedSecret, bytesForEncryptionKey);
|
}
|
||||||
|
|
||||||
|
bytes::vector DecryptSecureSecret(
|
||||||
|
bytes::const_span encryptedSecret,
|
||||||
|
bytes::const_span passwordHashForSecret) {
|
||||||
|
Expects(!encryptedSecret.empty());
|
||||||
|
|
||||||
|
return DecryptSecretBytesWithHash(
|
||||||
|
encryptedSecret,
|
||||||
|
passwordHashForSecret);
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes::vector EncryptSecureSecret(
|
bytes::vector EncryptSecureSecret(
|
||||||
bytes::const_span salt,
|
|
||||||
bytes::const_span secret,
|
bytes::const_span secret,
|
||||||
bytes::const_span password) {
|
bytes::const_span passwordHashForSecret) {
|
||||||
Expects(!salt.empty());
|
|
||||||
Expects(secret.size() == kSecretSize);
|
Expects(secret.size() == kSecretSize);
|
||||||
Expects(!password.empty());
|
|
||||||
|
|
||||||
const auto bytesForEncryptionKey = bytes::concatenate(
|
return EncryptSecretBytesWithHash(secret, passwordHashForSecret);
|
||||||
salt,
|
|
||||||
password,
|
|
||||||
salt);
|
|
||||||
return EncryptSecretBytes(secret, bytesForEncryptionKey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes::vector SerializeData(const std::map<QString, QString> &data) {
|
bytes::vector SerializeData(const std::map<QString, QString> &data) {
|
||||||
|
|
|
@ -11,14 +11,15 @@ namespace Passport {
|
||||||
|
|
||||||
bytes::vector GenerateSecretBytes();
|
bytes::vector GenerateSecretBytes();
|
||||||
|
|
||||||
|
bytes::vector CountPasswordHashForSecret(
|
||||||
|
bytes::const_span salt,
|
||||||
|
bytes::const_span password);
|
||||||
bytes::vector EncryptSecureSecret(
|
bytes::vector EncryptSecureSecret(
|
||||||
bytes::const_span salt,
|
|
||||||
bytes::const_span secret,
|
bytes::const_span secret,
|
||||||
bytes::const_span password);
|
bytes::const_span passwordHashForSecret);
|
||||||
bytes::vector DecryptSecureSecret(
|
bytes::vector DecryptSecureSecret(
|
||||||
bytes::const_span salt,
|
|
||||||
bytes::const_span encryptedSecret,
|
bytes::const_span encryptedSecret,
|
||||||
bytes::const_span password);
|
bytes::const_span passwordHashForSecret);
|
||||||
|
|
||||||
bytes::vector SerializeData(const std::map<QString, QString> &data);
|
bytes::vector SerializeData(const std::map<QString, QString> &data);
|
||||||
std::map<QString, QString> DeserializeData(bytes::const_span bytes);
|
std::map<QString, QString> DeserializeData(bytes::const_span bytes);
|
||||||
|
|
|
@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "lang/lang_hardcoded.h"
|
#include "lang/lang_hardcoded.h"
|
||||||
#include "base/openssl_help.h"
|
#include "base/openssl_help.h"
|
||||||
#include "base/qthelp_url.h"
|
#include "base/qthelp_url.h"
|
||||||
|
#include "data/data_session.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "window/window_controller.h"
|
#include "window/window_controller.h"
|
||||||
#include "core/click_handler_types.h"
|
#include "core/click_handler_types.h"
|
||||||
|
@ -30,6 +31,7 @@ namespace {
|
||||||
|
|
||||||
constexpr auto kDocumentScansLimit = 20;
|
constexpr auto kDocumentScansLimit = 20;
|
||||||
constexpr auto kShortPollTimeout = TimeMs(3000);
|
constexpr auto kShortPollTimeout = TimeMs(3000);
|
||||||
|
constexpr auto kRememberCredentialsDelay = TimeMs(1800 * 1000);
|
||||||
|
|
||||||
bool ForwardServiceErrorRequired(const QString &error) {
|
bool ForwardServiceErrorRequired(const QString &error) {
|
||||||
return (error == qstr("BOT_INVALID"))
|
return (error == qstr("BOT_INVALID"))
|
||||||
|
@ -436,32 +438,54 @@ std::vector<not_null<const Value*>> FormController::submitGetErrors() {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void FormController::submitPassword(const QString &password) {
|
void FormController::submitPassword(const QByteArray &password) {
|
||||||
Expects(!_password.salt.empty());
|
Expects(!_password.salt.empty());
|
||||||
|
|
||||||
|
const auto submitSaved = !base::take(_savedPasswordValue).isEmpty();
|
||||||
if (_passwordCheckRequestId) {
|
if (_passwordCheckRequestId) {
|
||||||
return;
|
return;
|
||||||
} else if (password.isEmpty()) {
|
} else if (password.isEmpty()) {
|
||||||
_passwordError.fire(QString());
|
_passwordError.fire(QString());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
const auto passwordBytes = password.toUtf8();
|
|
||||||
_passwordCheckRequestId = request(MTPaccount_GetPasswordSettings(
|
_passwordCheckRequestId = request(MTPaccount_GetPasswordSettings(
|
||||||
MTP_bytes(passwordHashForAuth(bytes::make_span(passwordBytes)))
|
MTP_bytes(passwordHashForAuth(bytes::make_span(password)))
|
||||||
)).handleFloodErrors(
|
)).handleFloodErrors(
|
||||||
).done([=](const MTPaccount_PasswordSettings &result) {
|
).done([=](const MTPaccount_PasswordSettings &result) {
|
||||||
Expects(result.type() == mtpc_account_passwordSettings);
|
Expects(result.type() == mtpc_account_passwordSettings);
|
||||||
|
|
||||||
_passwordCheckRequestId = 0;
|
_passwordCheckRequestId = 0;
|
||||||
|
_savedPasswordValue = QByteArray();
|
||||||
const auto &data = result.c_account_passwordSettings();
|
const auto &data = result.c_account_passwordSettings();
|
||||||
|
const auto hashForAuth = passwordHashForAuth(
|
||||||
|
bytes::make_span(password));
|
||||||
|
const auto hashForSecret = (data.vsecure_salt.v.isEmpty()
|
||||||
|
? bytes::vector()
|
||||||
|
: CountPasswordHashForSecret(
|
||||||
|
bytes::make_span(data.vsecure_salt.v),
|
||||||
|
bytes::make_span(password)));
|
||||||
_password.confirmedEmail = qs(data.vemail);
|
_password.confirmedEmail = qs(data.vemail);
|
||||||
validateSecureSecret(
|
validateSecureSecret(
|
||||||
bytes::make_span(data.vsecure_salt.v),
|
|
||||||
bytes::make_span(data.vsecure_secret.v),
|
bytes::make_span(data.vsecure_secret.v),
|
||||||
bytes::make_span(passwordBytes),
|
hashForSecret,
|
||||||
|
bytes::make_span(password),
|
||||||
data.vsecure_secret_id.v);
|
data.vsecure_secret_id.v);
|
||||||
|
if (!_secret.empty()) {
|
||||||
|
auto saved = SavedCredentials();
|
||||||
|
saved.hashForAuth = hashForAuth;
|
||||||
|
saved.hashForSecret = hashForSecret;
|
||||||
|
saved.secretId = _secretId;
|
||||||
|
Auth().data().rememberPassportCredentials(
|
||||||
|
std::move(saved),
|
||||||
|
kRememberCredentialsDelay);
|
||||||
|
}
|
||||||
}).fail([=](const RPCError &error) {
|
}).fail([=](const RPCError &error) {
|
||||||
_passwordCheckRequestId = 0;
|
_passwordCheckRequestId = 0;
|
||||||
if (MTP::isFloodError(error)) {
|
if (submitSaved) {
|
||||||
|
// Force reload and show form.
|
||||||
|
_password = PasswordSettings();
|
||||||
|
reloadPassword();
|
||||||
|
} else if (MTP::isFloodError(error)) {
|
||||||
_passwordError.fire(lang(lng_flood_error));
|
_passwordError.fire(lang(lng_flood_error));
|
||||||
} else if (error.type() == qstr("PASSWORD_HASH_INVALID")) {
|
} else if (error.type() == qstr("PASSWORD_HASH_INVALID")) {
|
||||||
_passwordError.fire(lang(lng_passport_password_wrong));
|
_passwordError.fire(lang(lng_passport_password_wrong));
|
||||||
|
@ -471,6 +495,35 @@ void FormController::submitPassword(const QString &password) {
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FormController::checkSavedPasswordSettings(
|
||||||
|
const SavedCredentials &credentials) {
|
||||||
|
_passwordCheckRequestId = request(MTPaccount_GetPasswordSettings(
|
||||||
|
MTP_bytes(credentials.hashForAuth)
|
||||||
|
)).done([=](const MTPaccount_PasswordSettings &result) {
|
||||||
|
Expects(result.type() == mtpc_account_passwordSettings);
|
||||||
|
|
||||||
|
_passwordCheckRequestId = 0;
|
||||||
|
const auto &data = result.c_account_passwordSettings();
|
||||||
|
if (!data.vsecure_secret.v.isEmpty()
|
||||||
|
&& data.vsecure_secret_id.v == credentials.secretId) {
|
||||||
|
_password.confirmedEmail = qs(data.vemail);
|
||||||
|
validateSecureSecret(
|
||||||
|
bytes::make_span(data.vsecure_secret.v),
|
||||||
|
credentials.hashForSecret,
|
||||||
|
{},
|
||||||
|
data.vsecure_secret_id.v);
|
||||||
|
}
|
||||||
|
if (_secret.empty()) {
|
||||||
|
Auth().data().forgetPassportCredentials();
|
||||||
|
showForm();
|
||||||
|
}
|
||||||
|
}).fail([=](const RPCError &error) {
|
||||||
|
_passwordCheckRequestId = 0;
|
||||||
|
Auth().data().forgetPassportCredentials();
|
||||||
|
showForm();
|
||||||
|
}).send();
|
||||||
|
}
|
||||||
|
|
||||||
void FormController::recoverPassword() {
|
void FormController::recoverPassword() {
|
||||||
if (!_password.hasRecovery) {
|
if (!_password.hasRecovery) {
|
||||||
_view->show(Box<InformBox>(lang(lng_signin_no_email_forgot)));
|
_view->show(Box<InformBox>(lang(lng_signin_no_email_forgot)));
|
||||||
|
@ -489,14 +542,16 @@ void FormController::recoverPassword() {
|
||||||
const auto box = _view->show(Box<RecoverBox>(
|
const auto box = _view->show(Box<RecoverBox>(
|
||||||
pattern,
|
pattern,
|
||||||
_password.notEmptyPassport));
|
_password.notEmptyPassport));
|
||||||
box->connect(box, &RecoverBox::reloadPassword, [=] {
|
|
||||||
|
box->passwordCleared(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
reloadPassword();
|
reloadPassword();
|
||||||
});
|
}, box->lifetime());
|
||||||
box->connect(box, &RecoverBox::recoveryExpired, [=] {
|
|
||||||
if (box) {
|
box->recoveryExpired(
|
||||||
box->closeBox();
|
) | rpl::start_with_next([=] {
|
||||||
}
|
box->closeBox();
|
||||||
});
|
}, box->lifetime());
|
||||||
}).fail([=](const RPCError &error) {
|
}).fail([=](const RPCError &error) {
|
||||||
_recoverRequestId = 0;
|
_recoverRequestId = 0;
|
||||||
_view->show(Box<InformBox>(Lang::Hard::ServerError()
|
_view->show(Box<InformBox>(Lang::Hard::ServerError()
|
||||||
|
@ -509,6 +564,11 @@ void FormController::reloadPassword() {
|
||||||
requestPassword();
|
requestPassword();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FormController::reloadAndSubmitPassword(const QByteArray &password) {
|
||||||
|
_savedPasswordValue = password;
|
||||||
|
requestPassword();
|
||||||
|
}
|
||||||
|
|
||||||
void FormController::cancelPassword() {
|
void FormController::cancelPassword() {
|
||||||
if (_passwordRequestId) {
|
if (_passwordRequestId) {
|
||||||
return;
|
return;
|
||||||
|
@ -534,22 +594,30 @@ void FormController::cancelPassword() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FormController::validateSecureSecret(
|
void FormController::validateSecureSecret(
|
||||||
bytes::const_span salt,
|
|
||||||
bytes::const_span encryptedSecret,
|
bytes::const_span encryptedSecret,
|
||||||
bytes::const_span password,
|
bytes::const_span passwordHashForSecret,
|
||||||
|
bytes::const_span passwordBytes,
|
||||||
uint64 serverSecretId) {
|
uint64 serverSecretId) {
|
||||||
if (!salt.empty() && !encryptedSecret.empty()) {
|
Expects(!passwordBytes.empty() || !passwordHashForSecret.empty());
|
||||||
_secret = DecryptSecureSecret(salt, encryptedSecret, password);
|
|
||||||
|
if (!passwordHashForSecret.empty() && !encryptedSecret.empty()) {
|
||||||
|
_secret = DecryptSecureSecret(
|
||||||
|
encryptedSecret,
|
||||||
|
passwordHashForSecret);
|
||||||
if (_secret.empty()) {
|
if (_secret.empty()) {
|
||||||
_secretId = 0;
|
_secretId = 0;
|
||||||
LOG(("API Error: Failed to decrypt secure secret."));
|
LOG(("API Error: Failed to decrypt secure secret."));
|
||||||
suggestReset(bytes::make_vector(password));
|
if (!passwordBytes.empty()) {
|
||||||
|
suggestReset(bytes::make_vector(passwordBytes));
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
} else if (CountSecureSecretId(_secret) != serverSecretId) {
|
} else if (CountSecureSecretId(_secret) != serverSecretId) {
|
||||||
_secret.clear();
|
_secret.clear();
|
||||||
_secretId = 0;
|
_secretId = 0;
|
||||||
LOG(("API Error: Wrong secure secret id."));
|
LOG(("API Error: Wrong secure secret id."));
|
||||||
suggestReset(bytes::make_vector(password));
|
if (!passwordBytes.empty()) {
|
||||||
|
suggestReset(bytes::make_vector(passwordBytes));
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
_secretId = serverSecretId;
|
_secretId = serverSecretId;
|
||||||
|
@ -557,7 +625,7 @@ void FormController::validateSecureSecret(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_secret.empty()) {
|
if (_secret.empty()) {
|
||||||
generateSecret(password);
|
generateSecret(passwordBytes);
|
||||||
}
|
}
|
||||||
_secretReady.fire({});
|
_secretReady.fire({});
|
||||||
}
|
}
|
||||||
|
@ -569,13 +637,9 @@ void FormController::suggestReset(bytes::vector password) {
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
_view->suggestReset([=] {
|
_view->suggestReset([=] {
|
||||||
const auto hashForAuth = openssl::Sha256(bytes::concatenate(
|
|
||||||
_password.salt,
|
|
||||||
password,
|
|
||||||
_password.salt));
|
|
||||||
using Flag = MTPDaccount_passwordInputSettings::Flag;
|
using Flag = MTPDaccount_passwordInputSettings::Flag;
|
||||||
_saveSecretRequestId = request(MTPaccount_UpdatePasswordSettings(
|
_saveSecretRequestId = request(MTPaccount_UpdatePasswordSettings(
|
||||||
MTP_bytes(hashForAuth),
|
MTP_bytes(passwordHashForAuth(password)),
|
||||||
MTP_account_passwordInputSettings(
|
MTP_account_passwordInputSettings(
|
||||||
MTP_flags(Flag::f_new_secure_salt
|
MTP_flags(Flag::f_new_secure_salt
|
||||||
| Flag::f_new_secure_secret
|
| Flag::f_new_secure_secret
|
||||||
|
@ -1696,6 +1760,8 @@ void FormController::valueSaveFailed(not_null<Value*> value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FormController::generateSecret(bytes::const_span password) {
|
void FormController::generateSecret(bytes::const_span password) {
|
||||||
|
Expects(!password.empty());
|
||||||
|
|
||||||
if (_saveSecretRequestId) {
|
if (_saveSecretRequestId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1707,20 +1773,20 @@ void FormController::generateSecret(bytes::const_span password) {
|
||||||
_password.newSecureSalt,
|
_password.newSecureSalt,
|
||||||
randomSaltPart);
|
randomSaltPart);
|
||||||
|
|
||||||
auto secureSecretId = CountSecureSecretId(secret);
|
auto saved = SavedCredentials();
|
||||||
auto encryptedSecret = EncryptSecureSecret(
|
saved.hashForAuth = passwordHashForAuth(password);
|
||||||
|
saved.hashForSecret = CountPasswordHashForSecret(
|
||||||
newSecureSaltFull,
|
newSecureSaltFull,
|
||||||
secret,
|
|
||||||
password);
|
password);
|
||||||
|
saved.secretId = CountSecureSecretId(secret);
|
||||||
|
|
||||||
const auto hashForAuth = openssl::Sha256(bytes::concatenate(
|
auto encryptedSecret = EncryptSecureSecret(
|
||||||
_password.salt,
|
secret,
|
||||||
password,
|
saved.hashForSecret);
|
||||||
_password.salt));
|
|
||||||
|
|
||||||
using Flag = MTPDaccount_passwordInputSettings::Flag;
|
using Flag = MTPDaccount_passwordInputSettings::Flag;
|
||||||
_saveSecretRequestId = request(MTPaccount_UpdatePasswordSettings(
|
_saveSecretRequestId = request(MTPaccount_UpdatePasswordSettings(
|
||||||
MTP_bytes(hashForAuth),
|
MTP_bytes(saved.hashForAuth),
|
||||||
MTP_account_passwordInputSettings(
|
MTP_account_passwordInputSettings(
|
||||||
MTP_flags(Flag::f_new_secure_salt
|
MTP_flags(Flag::f_new_secure_salt
|
||||||
| Flag::f_new_secure_secret
|
| Flag::f_new_secure_secret
|
||||||
|
@ -1731,11 +1797,15 @@ void FormController::generateSecret(bytes::const_span password) {
|
||||||
MTPstring(), // email
|
MTPstring(), // email
|
||||||
MTP_bytes(newSecureSaltFull),
|
MTP_bytes(newSecureSaltFull),
|
||||||
MTP_bytes(encryptedSecret),
|
MTP_bytes(encryptedSecret),
|
||||||
MTP_long(secureSecretId))
|
MTP_long(saved.secretId))
|
||||||
)).done([=](const MTPBool &result) {
|
)).done([=](const MTPBool &result) {
|
||||||
|
Auth().data().rememberPassportCredentials(
|
||||||
|
std::move(saved),
|
||||||
|
kRememberCredentialsDelay);
|
||||||
|
|
||||||
_saveSecretRequestId = 0;
|
_saveSecretRequestId = 0;
|
||||||
_secret = secret;
|
_secret = secret;
|
||||||
_secretId = secureSecretId;
|
_secretId = saved.secretId;
|
||||||
//_password.salt = newPasswordSaltFull;
|
//_password.salt = newPasswordSaltFull;
|
||||||
for (const auto &callback : base::take(_secretCallbacks)) {
|
for (const auto &callback : base::take(_secretCallbacks)) {
|
||||||
callback();
|
callback();
|
||||||
|
@ -1988,6 +2058,7 @@ void FormController::parseForm(const MTPaccount_AuthorizationForm &result) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FormController::formFail(const QString &error) {
|
void FormController::formFail(const QString &error) {
|
||||||
|
_savedPasswordValue = QByteArray();
|
||||||
_serviceErrorText = error;
|
_serviceErrorText = error;
|
||||||
_view->showCriticalError(
|
_view->showCriticalError(
|
||||||
lang(lng_passport_form_error) + "\n" + error);
|
lang(lng_passport_form_error) + "\n" + error);
|
||||||
|
@ -2036,7 +2107,13 @@ void FormController::showForm() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!_password.salt.empty()) {
|
if (!_password.salt.empty()) {
|
||||||
_view->showAskPassword();
|
if (!_savedPasswordValue.isEmpty()) {
|
||||||
|
submitPassword(base::duplicate(_savedPasswordValue));
|
||||||
|
} else if (const auto saved = Auth().data().passportCredentials()) {
|
||||||
|
checkSavedPasswordSettings(*saved);
|
||||||
|
} else {
|
||||||
|
_view->showAskPassword();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
_view->showNoPassword();
|
_view->showNoPassword();
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,12 @@ class Controller;
|
||||||
|
|
||||||
namespace Passport {
|
namespace Passport {
|
||||||
|
|
||||||
|
struct SavedCredentials {
|
||||||
|
bytes::vector hashForAuth;
|
||||||
|
bytes::vector hashForSecret;
|
||||||
|
uint64 secretId = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class ViewController;
|
class ViewController;
|
||||||
|
|
||||||
struct FormRequest {
|
struct FormRequest {
|
||||||
|
@ -247,11 +253,12 @@ public:
|
||||||
UserData *bot() const;
|
UserData *bot() const;
|
||||||
QString privacyPolicyUrl() const;
|
QString privacyPolicyUrl() const;
|
||||||
std::vector<not_null<const Value*>> submitGetErrors();
|
std::vector<not_null<const Value*>> submitGetErrors();
|
||||||
void submitPassword(const QString &password);
|
void submitPassword(const QByteArray &password);
|
||||||
void recoverPassword();
|
void recoverPassword();
|
||||||
rpl::producer<QString> passwordError() const;
|
rpl::producer<QString> passwordError() const;
|
||||||
const PasswordSettings &passwordSettings() const;
|
const PasswordSettings &passwordSettings() const;
|
||||||
void reloadPassword();
|
void reloadPassword();
|
||||||
|
void reloadAndSubmitPassword(const QByteArray &password);
|
||||||
void cancelPassword();
|
void cancelPassword();
|
||||||
|
|
||||||
bool canAddScan(not_null<const Value*> value) const;
|
bool canAddScan(not_null<const Value*> value) const;
|
||||||
|
@ -335,10 +342,11 @@ private:
|
||||||
bool applyPassword(const MTPDaccount_password &settings);
|
bool applyPassword(const MTPDaccount_password &settings);
|
||||||
bool applyPassword(PasswordSettings &&settings);
|
bool applyPassword(PasswordSettings &&settings);
|
||||||
bytes::vector passwordHashForAuth(bytes::const_span password) const;
|
bytes::vector passwordHashForAuth(bytes::const_span password) const;
|
||||||
|
void checkSavedPasswordSettings(const SavedCredentials &credentials);
|
||||||
void validateSecureSecret(
|
void validateSecureSecret(
|
||||||
bytes::const_span salt,
|
|
||||||
bytes::const_span encryptedSecret,
|
bytes::const_span encryptedSecret,
|
||||||
bytes::const_span password,
|
bytes::const_span passwordHashForSecret,
|
||||||
|
bytes::const_span passwordBytes,
|
||||||
uint64 serverSecretId);
|
uint64 serverSecretId);
|
||||||
void decryptValues();
|
void decryptValues();
|
||||||
void decryptValue(Value &value);
|
void decryptValue(Value &value);
|
||||||
|
@ -413,6 +421,7 @@ private:
|
||||||
mtpRequestId _passwordCheckRequestId = 0;
|
mtpRequestId _passwordCheckRequestId = 0;
|
||||||
|
|
||||||
PasswordSettings _password;
|
PasswordSettings _password;
|
||||||
|
QByteArray _savedPasswordValue;
|
||||||
Form _form;
|
Form _form;
|
||||||
bool _cancelled = false;
|
bool _cancelled = false;
|
||||||
mtpRequestId _recoverRequestId = 0;
|
mtpRequestId _recoverRequestId = 0;
|
||||||
|
|
|
@ -362,9 +362,8 @@ PanelController::PanelController(not_null<FormController*> form)
|
||||||
, _scopes(ComputeScopes(_form)) {
|
, _scopes(ComputeScopes(_form)) {
|
||||||
_form->secretReadyEvents(
|
_form->secretReadyEvents(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
if (_panel) {
|
ensurePanelCreated();
|
||||||
_panel->showForm();
|
_panel->showForm();
|
||||||
}
|
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
_form->verificationNeeded(
|
_form->verificationNeeded(
|
||||||
|
@ -435,7 +434,7 @@ void PanelController::submitForm() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanelController::submitPassword(const QString &password) {
|
void PanelController::submitPassword(const QByteArray &password) {
|
||||||
_form->submitPassword(password);
|
_form->submitPassword(password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,7 +466,10 @@ void PanelController::setupPassword() {
|
||||||
Expects(_panel != nullptr);
|
Expects(_panel != nullptr);
|
||||||
|
|
||||||
const auto &settings = _form->passwordSettings();
|
const auto &settings = _form->passwordSettings();
|
||||||
Assert(settings.salt.empty());
|
if (!settings.salt.empty()) {
|
||||||
|
showAskPassword();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
constexpr auto kRandomPart = 8;
|
constexpr auto kRandomPart = 8;
|
||||||
auto newPasswordSalt = QByteArray(
|
auto newPasswordSalt = QByteArray(
|
||||||
|
@ -494,9 +496,22 @@ void PanelController::setupPassword() {
|
||||||
notEmptyPassport,
|
notEmptyPassport,
|
||||||
hint,
|
hint,
|
||||||
newSecureSecretSalt));
|
newSecureSecretSalt));
|
||||||
box->connect(box, &PasscodeBox::reloadPassword, [=] {
|
box->newPasswordSet(
|
||||||
|
) | rpl::filter([=](const QByteArray &password) {
|
||||||
|
return !password.isEmpty();
|
||||||
|
}) | rpl::start_with_next([=](const QByteArray &password) {
|
||||||
|
_form->reloadAndSubmitPassword(password);
|
||||||
|
}, box->lifetime());
|
||||||
|
|
||||||
|
rpl::merge(
|
||||||
|
box->passwordReloadNeeded(),
|
||||||
|
box->newPasswordSet(
|
||||||
|
) | rpl::filter([=](const QByteArray &password) {
|
||||||
|
return password.isEmpty();
|
||||||
|
}) | rpl::map([] { return rpl::empty_value(); })
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
_form->reloadPassword();
|
_form->reloadPassword();
|
||||||
});
|
}, box->lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanelController::cancelPasswordSubmit() {
|
void PanelController::cancelPasswordSubmit() {
|
||||||
|
|
|
@ -68,7 +68,7 @@ public:
|
||||||
not_null<UserData*> bot() const;
|
not_null<UserData*> bot() const;
|
||||||
QString privacyPolicyUrl() const;
|
QString privacyPolicyUrl() const;
|
||||||
void submitForm();
|
void submitForm();
|
||||||
void submitPassword(const QString &password);
|
void submitPassword(const QByteArray &password);
|
||||||
void recoverPassword();
|
void recoverPassword();
|
||||||
rpl::producer<QString> passwordError() const;
|
rpl::producer<QString> passwordError() const;
|
||||||
QString passwordHint() const;
|
QString passwordHint() const;
|
||||||
|
|
|
@ -93,7 +93,7 @@ void PanelAskPassword::hideError() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanelAskPassword::submit() {
|
void PanelAskPassword::submit() {
|
||||||
_controller->submitPassword(_password->getLastText());
|
_controller->submitPassword(_password->getLastText().toUtf8());
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanelAskPassword::recover() {
|
void PanelAskPassword::recover() {
|
||||||
|
|
|
@ -83,7 +83,12 @@ void CloudPasswordState::onEdit() {
|
||||||
_notEmptyPassport,
|
_notEmptyPassport,
|
||||||
_curPasswordHint,
|
_curPasswordHint,
|
||||||
_newSecureSecretSalt));
|
_newSecureSecretSalt));
|
||||||
connect(box, SIGNAL(reloadPassword()), this, SLOT(onReloadPassword()));
|
rpl::merge(
|
||||||
|
box->newPasswordSet() | rpl::map([] { return rpl::empty_value(); }),
|
||||||
|
box->passwordReloadNeeded()
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
onReloadPassword();
|
||||||
|
}, box->lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CloudPasswordState::onTurnOff() {
|
void CloudPasswordState::onTurnOff() {
|
||||||
|
@ -113,7 +118,13 @@ void CloudPasswordState::onTurnOff() {
|
||||||
_curPasswordHint,
|
_curPasswordHint,
|
||||||
_newSecureSecretSalt,
|
_newSecureSecretSalt,
|
||||||
true));
|
true));
|
||||||
connect(box, SIGNAL(reloadPassword()), this, SLOT(onReloadPassword()));
|
rpl::merge(
|
||||||
|
box->newPasswordSet(
|
||||||
|
) | rpl::map([] { return rpl::empty_value(); }),
|
||||||
|
box->passwordReloadNeeded()
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
onReloadPassword();
|
||||||
|
}, box->lifetime());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue