mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +02:00
Add ability to reset cloud password in 7 days.
This commit is contained in:
parent
c100055fac
commit
256546071b
11 changed files with 299 additions and 30 deletions
|
@ -82,6 +82,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
"lng_box_ok" = "OK";
|
||||
"lng_box_done" = "Done";
|
||||
"lng_box_yes" = "Yes";
|
||||
"lng_box_no" = "No";
|
||||
|
||||
"lng_cancel" = "Cancel";
|
||||
"lng_continue" = "Continue";
|
||||
|
@ -596,6 +598,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_cloud_password_remove" = "Remove cloud password";
|
||||
"lng_cloud_password_set" = "Enable two-step verification";
|
||||
"lng_cloud_password_edit" = "Change cloud password";
|
||||
"lng_cloud_password_reset_in" = "Reset password in";
|
||||
"lng_cloud_password_reset_ready" = "Reset password";
|
||||
"lng_cloud_password_reset_cancel" = "Cancel password reset";
|
||||
"lng_cloud_password_enter_old" = "Enter current password";
|
||||
"lng_cloud_password_enter_first" = "Enter a password";
|
||||
"lng_cloud_password_enter_new" = "Enter new password";
|
||||
|
@ -618,6 +623,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_cloud_password_passport_losing" = "Warning! All data saved in your Telegram Passport will be lost!";
|
||||
"lng_cloud_password_resend" = "Resend code";
|
||||
"lng_cloud_password_resent" = "Code was resent.";
|
||||
"lng_cloud_password_reset_title" = "Reset password";
|
||||
"lng_cloud_password_reset_no_email" = "Since you didn't provide a recovery email when setting up your password, your remaining options are either to remember your password or wait 7 days until your password is reset.";
|
||||
"lng_cloud_password_reset_with_email" = "If you don't have access to your recovery email, your remaining options are either to remember your password or wait 7 days until your password resets.";
|
||||
"lng_cloud_password_reset_ok" = "Reset";
|
||||
"lng_cloud_password_reset_cancel_title" = "Cancel reset";
|
||||
"lng_cloud_password_reset_cancel_sure" = "Cancel the password reset process? If you request a new reset later, it will take another 7 days.";
|
||||
"lng_cloud_password_reset_later" = "You recently requested a password reset that was cancelled. Please wait {duration} before making a new request.";
|
||||
|
||||
"lng_connection_auto_connecting" = "Default (connecting...)";
|
||||
"lng_connection_auto" = "Default ({transport} used)";
|
||||
|
|
|
@ -4764,6 +4764,23 @@ void ApiWrap::reloadPasswordState() {
|
|||
}).send();
|
||||
}
|
||||
|
||||
void ApiWrap::applyPendingReset(const MTPaccount_ResetPasswordResult &data) {
|
||||
if (!_passwordState) {
|
||||
reloadPasswordState();
|
||||
return;
|
||||
}
|
||||
data.match([&](const MTPDaccount_resetPasswordOk &data) {
|
||||
reloadPasswordState();
|
||||
}, [&](const MTPDaccount_resetPasswordRequestedWait &data) {
|
||||
const auto until = data.vuntil_date().v;
|
||||
if (_passwordState->pendingResetDate != until) {
|
||||
_passwordState->pendingResetDate = until;
|
||||
_passwordStateChanges.fire_copy(*_passwordState);
|
||||
}
|
||||
}, [&](const MTPDaccount_resetPasswordFailedWait &data) {
|
||||
});
|
||||
}
|
||||
|
||||
void ApiWrap::clearUnconfirmedPassword() {
|
||||
_passwordRequestId = request(MTPaccount_CancelPasswordEmail(
|
||||
)).done([=](const MTPBool &result) {
|
||||
|
|
|
@ -434,6 +434,7 @@ public:
|
|||
void clearPeerPhoto(not_null<PhotoData*> photo);
|
||||
|
||||
void reloadPasswordState();
|
||||
void applyPendingReset(const MTPaccount_ResetPasswordResult &data);
|
||||
void clearUnconfirmedPassword();
|
||||
rpl::producer<Core::CloudPasswordState> passwordState() const;
|
||||
std::optional<Core::CloudPasswordState> passwordStateCurrent() const;
|
||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "lang/lang_keys.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "boxes/confirm_phone_box.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "mainwindow.h"
|
||||
#include "apiwrap.h"
|
||||
#include "main/main_session.h"
|
||||
|
@ -95,6 +96,56 @@ void TransferPasswordError(
|
|||
}
|
||||
}
|
||||
|
||||
void StartPendingReset(
|
||||
not_null<Main::Session*> session,
|
||||
not_null<Ui::BoxContent*> context,
|
||||
Fn<void()> close) {
|
||||
const auto weak = Ui::MakeWeak(context.get());
|
||||
session->api().request(MTPaccount_ResetPassword(
|
||||
)).done([=](const MTPaccount_ResetPasswordResult &result) {
|
||||
session->api().applyPendingReset(result);
|
||||
result.match([&](const MTPDaccount_resetPasswordOk &data) {
|
||||
}, [&](const MTPDaccount_resetPasswordRequestedWait &data) {
|
||||
}, [&](const MTPDaccount_resetPasswordFailedWait &data) {
|
||||
constexpr auto kMinute = 60;
|
||||
constexpr auto kHour = 3600;
|
||||
constexpr auto kDay = 86400;
|
||||
const auto left = std::max(
|
||||
data.vretry_date().v - base::unixtime::now(),
|
||||
kMinute);
|
||||
const auto days = (left / kDay);
|
||||
const auto hours = (left / kHour);
|
||||
const auto minutes = (left / kMinute);
|
||||
const auto duration = days
|
||||
? tr::lng_group_call_duration_days(tr::now, lt_count, days)
|
||||
: hours
|
||||
? tr::lng_group_call_duration_hours(tr::now, lt_count, hours)
|
||||
: tr::lng_group_call_duration_minutes(
|
||||
tr::now,
|
||||
lt_count,
|
||||
minutes);
|
||||
if (const auto strong = weak.data()) {
|
||||
strong->getDelegate()->show(Box<InformBox>(
|
||||
tr::lng_cloud_password_reset_later(
|
||||
tr::now,
|
||||
lt_duration,
|
||||
duration)));
|
||||
}
|
||||
});
|
||||
if (const auto strong = weak.data()) {
|
||||
strong->closeBox();
|
||||
}
|
||||
close();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
if (const auto strong = weak.data()) {
|
||||
strong->getDelegate()->show(
|
||||
Box<InformBox>("Error: " + error.type()));
|
||||
strong->closeBox();
|
||||
}
|
||||
close();
|
||||
}).send();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
PasscodeBox::CloudFields PasscodeBox::CloudFields::From(
|
||||
|
@ -106,6 +157,7 @@ PasscodeBox::CloudFields PasscodeBox::CloudFields::From(
|
|||
result.hasRecovery = current.hasRecovery;
|
||||
result.notEmptyPassport = current.notEmptyPassport;
|
||||
result.hint = current.hint;
|
||||
result.pendingResetDate = current.pendingResetDate;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -145,7 +197,8 @@ PasscodeBox::PasscodeBox(
|
|||
, _reenterPasscode(this, st::defaultInputField, tr::lng_cloud_password_confirm_new())
|
||||
, _passwordHint(this, st::defaultInputField, fields.curRequest ? tr::lng_cloud_password_change_hint() : tr::lng_cloud_password_hint())
|
||||
, _recoverEmail(this, st::defaultInputField, tr::lng_cloud_password_email())
|
||||
, _recover(this, tr::lng_signin_recover(tr::now)) {
|
||||
, _recover(this, tr::lng_signin_recover(tr::now))
|
||||
, _showRecoverLink(_cloudFields.hasRecovery || !_cloudFields.pendingResetDate) {
|
||||
Expects(!_turningOff || _cloudFields.curRequest);
|
||||
|
||||
if (!_cloudFields.hint.isEmpty()) {
|
||||
|
@ -203,14 +256,14 @@ void PasscodeBox::prepare() {
|
|||
: _cloudPwd
|
||||
? tr::lng_cloud_password_remove()
|
||||
: tr::lng_passcode_remove());
|
||||
setDimensions(st::boxWidth, st::passcodePadding.top() + _oldPasscode->height() + st::passcodeTextLine + ((_cloudFields.hasRecovery && !_hintText.isEmpty()) ? st::passcodeTextLine : 0) + st::passcodeAboutSkip + _aboutHeight + st::passcodePadding.bottom());
|
||||
setDimensions(st::boxWidth, st::passcodePadding.top() + _oldPasscode->height() + st::passcodeTextLine + ((_showRecoverLink && !_hintText.isEmpty()) ? st::passcodeTextLine : 0) + st::passcodeAboutSkip + _aboutHeight + st::passcodePadding.bottom());
|
||||
} else {
|
||||
if (currentlyHave()) {
|
||||
_oldPasscode->show();
|
||||
setTitle(_cloudPwd
|
||||
? tr::lng_cloud_password_change()
|
||||
: tr::lng_passcode_change());
|
||||
setDimensions(st::boxWidth, st::passcodePadding.top() + _oldPasscode->height() + st::passcodeTextLine + ((_cloudFields.hasRecovery && !_hintText.isEmpty()) ? st::passcodeTextLine : 0) + _newPasscode->height() + st::passcodeLittleSkip + _reenterPasscode->height() + st::passcodeSkip + (_cloudPwd ? _passwordHint->height() + st::passcodeLittleSkip : 0) + st::passcodeAboutSkip + _aboutHeight + st::passcodePadding.bottom());
|
||||
setDimensions(st::boxWidth, st::passcodePadding.top() + _oldPasscode->height() + st::passcodeTextLine + ((_showRecoverLink && !_hintText.isEmpty()) ? st::passcodeTextLine : 0) + _newPasscode->height() + st::passcodeLittleSkip + _reenterPasscode->height() + st::passcodeSkip + (_cloudPwd ? _passwordHint->height() + st::passcodeLittleSkip : 0) + st::passcodeAboutSkip + _aboutHeight + st::passcodePadding.bottom());
|
||||
} else {
|
||||
_oldPasscode->hide();
|
||||
setTitle(_cloudPwd
|
||||
|
@ -237,7 +290,9 @@ void PasscodeBox::prepare() {
|
|||
|
||||
const auto has = currentlyHave();
|
||||
_oldPasscode->setVisible(onlyCheck || has);
|
||||
_recover->setVisible((onlyCheck || has) && _cloudPwd && _cloudFields.hasRecovery);
|
||||
_recover->setVisible((onlyCheck || has)
|
||||
&& _cloudPwd
|
||||
&& _showRecoverLink);
|
||||
_newPasscode->setVisible(!onlyCheck);
|
||||
_reenterPasscode->setVisible(!onlyCheck);
|
||||
_passwordHint->setVisible(!onlyCheck && _cloudPwd);
|
||||
|
@ -285,7 +340,7 @@ void PasscodeBox::paintEvent(QPaintEvent *e) {
|
|||
Painter p(this);
|
||||
|
||||
int32 w = st::boxWidth - st::boxPadding.left() * 1.5;
|
||||
int32 abouty = (_passwordHint->isHidden() ? ((_reenterPasscode->isHidden() ? (_oldPasscode->y() + (_cloudFields.hasRecovery && !_hintText.isEmpty() ? st::passcodeTextLine : 0)) : _reenterPasscode->y()) + st::passcodeSkip) : _passwordHint->y()) + _oldPasscode->height() + st::passcodeLittleSkip + st::passcodeAboutSkip;
|
||||
int32 abouty = (_passwordHint->isHidden() ? ((_reenterPasscode->isHidden() ? (_oldPasscode->y() + (_showRecoverLink && !_hintText.isEmpty() ? st::passcodeTextLine : 0)) : _reenterPasscode->y()) + st::passcodeSkip) : _passwordHint->y()) + _oldPasscode->height() + st::passcodeLittleSkip + st::passcodeAboutSkip;
|
||||
p.setPen(st::boxTextFg);
|
||||
_about.drawLeft(p, st::boxPadding.left(), abouty, w, width());
|
||||
|
||||
|
@ -317,7 +372,7 @@ void PasscodeBox::resizeEvent(QResizeEvent *e) {
|
|||
_oldPasscode->resize(w, _oldPasscode->height());
|
||||
_oldPasscode->moveToLeft(st::boxPadding.left(), st::passcodePadding.top());
|
||||
_newPasscode->resize(w, _newPasscode->height());
|
||||
_newPasscode->moveToLeft(st::boxPadding.left(), _oldPasscode->y() + ((_turningOff || has) ? (_oldPasscode->height() + st::passcodeTextLine + ((_cloudFields.hasRecovery && !_hintText.isEmpty()) ? st::passcodeTextLine : 0)) : 0));
|
||||
_newPasscode->moveToLeft(st::boxPadding.left(), _oldPasscode->y() + ((_turningOff || has) ? (_oldPasscode->height() + st::passcodeTextLine + ((_showRecoverLink && !_hintText.isEmpty()) ? st::passcodeTextLine : 0)) : 0));
|
||||
_reenterPasscode->resize(w, _reenterPasscode->height());
|
||||
_reenterPasscode->moveToLeft(st::boxPadding.left(), _newPasscode->y() + _newPasscode->height() + st::passcodeLittleSkip);
|
||||
_passwordHint->resize(w, _passwordHint->height());
|
||||
|
@ -379,7 +434,7 @@ void PasscodeBox::setPasswordFail(const QString &type) {
|
|||
_oldPasscode->setFocus();
|
||||
_oldPasscode->showError();
|
||||
_oldError = tr::lng_flood_error(tr::now);
|
||||
if (_cloudFields.hasRecovery && _hintText.isEmpty()) {
|
||||
if (_showRecoverLink && _hintText.isEmpty()) {
|
||||
_recover->hide();
|
||||
}
|
||||
update();
|
||||
|
@ -913,7 +968,7 @@ void PasscodeBox::badOldPasscode() {
|
|||
_oldError = _cloudPwd
|
||||
? tr::lng_cloud_password_wrong(tr::now)
|
||||
: tr::lng_passcode_wrong(tr::now);
|
||||
if (_cloudFields.hasRecovery && _hintText.isEmpty()) {
|
||||
if (_showRecoverLink && _hintText.isEmpty()) {
|
||||
_recover->hide();
|
||||
}
|
||||
update();
|
||||
|
@ -922,7 +977,7 @@ void PasscodeBox::badOldPasscode() {
|
|||
void PasscodeBox::oldChanged() {
|
||||
if (!_oldError.isEmpty()) {
|
||||
_oldError = QString();
|
||||
if (_cloudFields.hasRecovery && _hintText.isEmpty()) {
|
||||
if (_showRecoverLink && _hintText.isEmpty()) {
|
||||
_recover->show();
|
||||
}
|
||||
update();
|
||||
|
@ -944,7 +999,21 @@ void PasscodeBox::emailChanged() {
|
|||
}
|
||||
|
||||
void PasscodeBox::recoverByEmail() {
|
||||
if (_pattern.isEmpty()) {
|
||||
if (!_cloudFields.hasRecovery) {
|
||||
const auto session = _session;
|
||||
const auto confirmBox = std::make_shared<QPointer<BoxContent>>();
|
||||
const auto reset = crl::guard(this, [=] {
|
||||
StartPendingReset(session, this, [=] {
|
||||
if (const auto box = *confirmBox) {
|
||||
box->closeBox();
|
||||
}
|
||||
});
|
||||
});
|
||||
*confirmBox = getDelegate()->show(Box<ConfirmBox>(
|
||||
tr::lng_cloud_password_reset_no_email(tr::now),
|
||||
tr::lng_cloud_password_reset_ok(tr::now),
|
||||
reset));
|
||||
} else if (_pattern.isEmpty()) {
|
||||
_pattern = "-";
|
||||
_api.request(MTPauth_RequestPasswordRecovery(
|
||||
)).done([=](const MTPauth_PasswordRecovery &result) {
|
||||
|
@ -964,10 +1033,13 @@ void PasscodeBox::recoverExpired() {
|
|||
void PasscodeBox::recover() {
|
||||
if (_pattern == "-") return;
|
||||
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
const auto box = getDelegate()->show(Box<RecoverBox>(
|
||||
_session,
|
||||
_pattern,
|
||||
_cloudFields.notEmptyPassport));
|
||||
_cloudFields.notEmptyPassport,
|
||||
_cloudFields.pendingResetDate != 0,
|
||||
[weak] { if (weak) { weak->closeBox(); } }));
|
||||
|
||||
box->passwordCleared(
|
||||
) | rpl::map_to(
|
||||
|
@ -996,11 +1068,37 @@ RecoverBox::RecoverBox(
|
|||
QWidget*,
|
||||
not_null<Main::Session*> session,
|
||||
const QString &pattern,
|
||||
bool notEmptyPassport)
|
||||
bool notEmptyPassport,
|
||||
bool hasPendingReset,
|
||||
Fn<void()> closeParent)
|
||||
: _api(&session->mtp())
|
||||
, _pattern(st::normalFont->elided(tr::lng_signin_recover_hint(tr::now, lt_recover_email, pattern), st::boxWidth - st::boxPadding.left() * 1.5))
|
||||
, _notEmptyPassport(notEmptyPassport)
|
||||
, _recoverCode(this, st::defaultInputField, tr::lng_signin_code()) {
|
||||
, _recoverCode(this, st::defaultInputField, tr::lng_signin_code())
|
||||
, _noEmailAccess(this, tr::lng_signin_try_password(tr::now))
|
||||
, _closeParent(std::move(closeParent)) {
|
||||
if (hasPendingReset) {
|
||||
_noEmailAccess.destroy();
|
||||
} else {
|
||||
_noEmailAccess->setClickedCallback([=] {
|
||||
const auto confirmBox = std::make_shared<QPointer<BoxContent>>();
|
||||
const auto reset = crl::guard(this, [=] {
|
||||
const auto closeParent = _closeParent;
|
||||
StartPendingReset(session, this, [=] {
|
||||
if (closeParent) {
|
||||
closeParent();
|
||||
}
|
||||
if (const auto box = *confirmBox) {
|
||||
box->closeBox();
|
||||
}
|
||||
});
|
||||
});
|
||||
*confirmBox = getDelegate()->show(Box<ConfirmBox>(
|
||||
tr::lng_cloud_password_reset_with_email(tr::now),
|
||||
tr::lng_cloud_password_reset_ok(tr::now),
|
||||
reset));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
rpl::producer<> RecoverBox::passwordCleared() const {
|
||||
|
@ -1017,7 +1115,13 @@ void RecoverBox::prepare() {
|
|||
addButton(tr::lng_passcode_submit(), [=] { submit(); });
|
||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||
|
||||
setDimensions(st::boxWidth, st::passcodePadding.top() + st::passcodePadding.bottom() + st::passcodeTextLine + _recoverCode->height() + st::passcodeTextLine);
|
||||
setDimensions(
|
||||
st::boxWidth,
|
||||
(st::passcodePadding.top()
|
||||
+ st::passcodePadding.bottom()
|
||||
+ st::passcodeTextLine
|
||||
+ _recoverCode->height()
|
||||
+ st::passcodeTextLine));
|
||||
|
||||
connect(_recoverCode, &Ui::InputField::changed, [=] { codeChanged(); });
|
||||
connect(_recoverCode, &Ui::InputField::submitted, [=] { submit(); });
|
||||
|
@ -1044,6 +1148,9 @@ void RecoverBox::resizeEvent(QResizeEvent *e) {
|
|||
|
||||
_recoverCode->resize(st::boxWidth - st::boxPadding.left() - st::boxPadding.right(), _recoverCode->height());
|
||||
_recoverCode->moveToLeft(st::boxPadding.left(), st::passcodePadding.top() + st::passcodePadding.bottom() + st::passcodeTextLine);
|
||||
if (_noEmailAccess) {
|
||||
_noEmailAccess->moveToLeft(st::boxPadding.left(), _recoverCode->y() + _recoverCode->height() + (st::passcodeTextLine - _noEmailAccess->height()) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
void RecoverBox::setInnerFocus() {
|
||||
|
@ -1085,11 +1192,18 @@ void RecoverBox::submit() {
|
|||
}
|
||||
}
|
||||
|
||||
void RecoverBox::codeChanged() {
|
||||
_error = QString();
|
||||
void RecoverBox::setError(const QString &error) {
|
||||
_error = error;
|
||||
if (_noEmailAccess) {
|
||||
_noEmailAccess->setVisible(error.isEmpty());
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void RecoverBox::codeChanged() {
|
||||
setError(QString());
|
||||
}
|
||||
|
||||
void RecoverBox::codeSubmitDone(const MTPauth_Authorization &result) {
|
||||
_submitRequest = 0;
|
||||
|
||||
|
@ -1102,8 +1216,7 @@ void RecoverBox::codeSubmitDone(const MTPauth_Authorization &result) {
|
|||
void RecoverBox::codeSubmitFail(const MTP::Error &error) {
|
||||
if (MTP::IsFloodError(error)) {
|
||||
_submitRequest = 0;
|
||||
_error = tr::lng_flood_error(tr::now);
|
||||
update();
|
||||
setError(tr::lng_flood_error(tr::now));
|
||||
_recoverCode->showError();
|
||||
return;
|
||||
}
|
||||
|
@ -1121,18 +1234,14 @@ void RecoverBox::codeSubmitFail(const MTP::Error &error) {
|
|||
_recoveryExpired.fire({});
|
||||
closeBox();
|
||||
} else if (err == qstr("CODE_INVALID")) {
|
||||
_error = tr::lng_signin_wrong_code(tr::now);
|
||||
update();
|
||||
setError(tr::lng_signin_wrong_code(tr::now));
|
||||
_recoverCode->selectAll();
|
||||
_recoverCode->setFocus();
|
||||
_recoverCode->showError();
|
||||
} else {
|
||||
if (Logs::DebugEnabled()) { // internal server error
|
||||
_error = err + ": " + error.description();
|
||||
} else {
|
||||
_error = Lang::Hard::ServerError();
|
||||
}
|
||||
update();
|
||||
setError(Logs::DebugEnabled() // internal server error
|
||||
? (err + ": " + error.description())
|
||||
: Lang::Hard::ServerError());
|
||||
_recoverCode->setFocus();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ public:
|
|||
QString hint;
|
||||
Core::SecureSecretAlgo newSecureSecretAlgo;
|
||||
bool turningOff = false;
|
||||
TimeId pendingResetDate = 0;
|
||||
|
||||
// Check cloud password for some action.
|
||||
Fn<void(const Core::CloudPasswordResult &)> customCheckCallback;
|
||||
|
@ -157,6 +158,7 @@ private:
|
|||
object_ptr<Ui::InputField> _passwordHint;
|
||||
object_ptr<Ui::InputField> _recoverEmail;
|
||||
object_ptr<Ui::LinkButton> _recover;
|
||||
bool _showRecoverLink = false;
|
||||
|
||||
QString _oldError, _newError, _emailError;
|
||||
|
||||
|
@ -172,7 +174,9 @@ public:
|
|||
QWidget*,
|
||||
not_null<Main::Session*> session,
|
||||
const QString &pattern,
|
||||
bool notEmptyPassport);
|
||||
bool notEmptyPassport,
|
||||
bool hasPendingReset,
|
||||
Fn<void()> closeParent = nullptr);
|
||||
|
||||
rpl::producer<> passwordCleared() const;
|
||||
rpl::producer<> recoveryExpired() const;
|
||||
|
@ -192,6 +196,7 @@ private:
|
|||
void codeChanged();
|
||||
void codeSubmitDone(const MTPauth_Authorization &result);
|
||||
void codeSubmitFail(const MTP::Error &error);
|
||||
void setError(const QString &error);
|
||||
|
||||
MTP::Sender _api;
|
||||
mtpRequestId _submitRequest = 0;
|
||||
|
@ -200,6 +205,8 @@ private:
|
|||
bool _notEmptyPassport = false;
|
||||
|
||||
object_ptr<Ui::InputField> _recoverCode;
|
||||
object_ptr<Ui::LinkButton> _noEmailAccess;
|
||||
Fn<void()> _closeParent;
|
||||
|
||||
QString _error;
|
||||
|
||||
|
|
|
@ -314,6 +314,7 @@ CloudPasswordState ParseCloudPasswordState(
|
|||
ParseSecureSecretAlgo(data.vnew_secure_algo()));
|
||||
result.unconfirmedPattern =
|
||||
qs(data.vemail_unconfirmed_pattern().value_or_empty());
|
||||
result.pendingResetDate = data.vpending_reset_date().value_or_empty();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -130,6 +130,7 @@ struct CloudPasswordState {
|
|||
CloudPasswordAlgo newPassword;
|
||||
SecureSecretAlgo newSecureSecret;
|
||||
QString unconfirmedPattern;
|
||||
TimeId pendingResetDate = 0;
|
||||
};
|
||||
|
||||
CloudPasswordState ParseCloudPasswordState(
|
||||
|
|
|
@ -1001,7 +1001,8 @@ void FormController::recoverPassword() {
|
|||
const auto box = _view->show(Box<RecoverBox>(
|
||||
&_controller->session(),
|
||||
pattern,
|
||||
_password.notEmptyPassport));
|
||||
_password.notEmptyPassport,
|
||||
_password.pendingResetDate != 0));
|
||||
|
||||
box->passwordCleared(
|
||||
) | rpl::start_with_next([=] {
|
||||
|
@ -2636,6 +2637,7 @@ bool FormController::applyPassword(const MTPDaccount_password &result) {
|
|||
Core::ParseCloudPasswordAlgo(result.vnew_algo()));
|
||||
settings.newSecureAlgo = Core::ValidateNewSecureSecretAlgo(
|
||||
Core::ParseSecureSecretAlgo(result.vnew_secure_algo()));
|
||||
settings.pendingResetDate = result.vpending_reset_date().value_or_empty();
|
||||
openssl::AddRandomSeed(bytes::make_span(result.vsecure_random().v));
|
||||
return applyPassword(std::move(settings));
|
||||
}
|
||||
|
|
|
@ -280,6 +280,7 @@ struct PasswordSettings {
|
|||
bool hasRecovery = false;
|
||||
bool notEmptyPassport = false;
|
||||
bool unknownAlgo = false;
|
||||
TimeId pendingResetDate = 0;
|
||||
|
||||
bool operator==(const PasswordSettings &other) const {
|
||||
return (request == other.request)
|
||||
|
@ -296,7 +297,8 @@ struct PasswordSettings {
|
|||
&& (unconfirmedPattern == other.unconfirmedPattern)
|
||||
&& (confirmedEmail == other.confirmedEmail)
|
||||
&& (hasRecovery == other.hasRecovery)
|
||||
&& (unknownAlgo == other.unknownAlgo);
|
||||
&& (unknownAlgo == other.unknownAlgo)
|
||||
&& (pendingResetDate == other.pendingResetDate);
|
||||
}
|
||||
bool operator!=(const PasswordSettings &other) const {
|
||||
return !(*this == other);
|
||||
|
|
|
@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "settings/settings_common.h"
|
||||
#include "settings/settings_privacy_controllers.h"
|
||||
#include "base/timer_rpl.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "boxes/peer_list_box.h"
|
||||
#include "boxes/edit_privacy_box.h"
|
||||
#include "boxes/passcode_box.h"
|
||||
|
@ -359,6 +360,10 @@ void SetupCloudPassword(
|
|||
) | rpl::then(rpl::duplicate(
|
||||
unconfirmed
|
||||
));
|
||||
auto resetAt = session->api().passwordState(
|
||||
) | rpl::map([](const State &state) {
|
||||
return state.pendingResetDate;
|
||||
});
|
||||
const auto label = container->add(
|
||||
object_ptr<Ui::SlideWrap<Ui::FlatLabel>>(
|
||||
container,
|
||||
|
@ -464,6 +469,118 @@ void SetupCloudPassword(
|
|||
_1 && !_2));
|
||||
disable->entity()->addClickHandler(remove);
|
||||
|
||||
auto resetInSeconds = rpl::duplicate(
|
||||
resetAt
|
||||
) | rpl::filter([](TimeId time) {
|
||||
return time != 0;
|
||||
}) | rpl::map([](TimeId time) {
|
||||
return rpl::single(
|
||||
rpl::empty_value()
|
||||
) | rpl::then(base::timer_each(
|
||||
999
|
||||
)) | rpl::map([=] {
|
||||
const auto now = base::unixtime::now();
|
||||
return (time - now);
|
||||
}) | rpl::distinct_until_changed(
|
||||
) | rpl::take_while([](TimeId left) {
|
||||
return left > 0;
|
||||
}) | rpl::then(rpl::single(TimeId(0)));
|
||||
}) | rpl::flatten_latest(
|
||||
) | rpl::start_spawning(container->lifetime());
|
||||
|
||||
auto resetText = rpl::duplicate(
|
||||
resetInSeconds
|
||||
) | rpl::map([](TimeId left) {
|
||||
return (left > 0);
|
||||
}) | rpl::distinct_until_changed(
|
||||
) | rpl::map([](bool waiting) {
|
||||
return waiting
|
||||
? tr::lng_cloud_password_reset_in()
|
||||
: tr::lng_cloud_password_reset_ready();
|
||||
}) | rpl::flatten_latest();
|
||||
|
||||
constexpr auto kMinute = 60;
|
||||
constexpr auto kHour = 3600;
|
||||
constexpr auto kDay = 86400;
|
||||
auto resetLabel = rpl::duplicate(
|
||||
resetInSeconds
|
||||
) | rpl::map([](TimeId left) {
|
||||
return (left >= kDay)
|
||||
? ((left / kDay) * kDay)
|
||||
: (left >= kHour)
|
||||
? ((left / kHour) * kHour)
|
||||
: (left >= kMinute)
|
||||
? ((left / kMinute) * kMinute)
|
||||
: left;
|
||||
}) | rpl::distinct_until_changed(
|
||||
) | rpl::map([](TimeId left) {
|
||||
const auto days = left / kDay;
|
||||
const auto hours = left / kHour;
|
||||
const auto minutes = left / kMinute;
|
||||
return days
|
||||
? tr::lng_group_call_duration_days(tr::now, lt_count, days)
|
||||
: hours
|
||||
? tr::lng_group_call_duration_hours(tr::now, lt_count, hours)
|
||||
: minutes
|
||||
? tr::lng_group_call_duration_minutes(tr::now, lt_count, minutes)
|
||||
: left
|
||||
? tr::lng_group_call_duration_seconds(tr::now, lt_count, left)
|
||||
: QString();
|
||||
});
|
||||
|
||||
const auto reset = container->add(
|
||||
object_ptr<Ui::SlideWrap<Button>>(
|
||||
container,
|
||||
object_ptr<Button>(
|
||||
container,
|
||||
rpl::duplicate(resetText),
|
||||
st::settingsButton))
|
||||
)->setDuration(0);
|
||||
CreateRightLabel(
|
||||
reset->entity(),
|
||||
std::move(resetLabel),
|
||||
st::settingsButton,
|
||||
std::move(resetText));
|
||||
|
||||
reset->toggleOn(rpl::duplicate(
|
||||
resetAt
|
||||
) | rpl::map([](TimeId time) {
|
||||
return time != 0;
|
||||
}));
|
||||
const auto sent = std::make_shared<mtpRequestId>(0);
|
||||
reset->entity()->addClickHandler([=] {
|
||||
const auto api = &session->api();
|
||||
const auto state = api->passwordStateCurrent();
|
||||
const auto date = state ? state->pendingResetDate : TimeId(0);
|
||||
if (!date || *sent) {
|
||||
return;
|
||||
} else if (base::unixtime::now() >= date) {
|
||||
*sent = api->request(MTPaccount_ResetPassword(
|
||||
)).done([=](const MTPaccount_ResetPasswordResult &result) {
|
||||
*sent = 0;
|
||||
api->applyPendingReset(result);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
*sent = 0;
|
||||
}).send();
|
||||
} else {
|
||||
const auto cancel = [=] {
|
||||
Ui::hideLayer();
|
||||
*sent = api->request(MTPaccount_DeclinePasswordReset(
|
||||
)).done([=] {
|
||||
*sent = 0;
|
||||
api->reloadPasswordState();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
*sent = 0;
|
||||
}).send();
|
||||
};
|
||||
Ui::show(Box<ConfirmBox>(
|
||||
tr::lng_cloud_password_reset_cancel_sure(tr::now),
|
||||
tr::lng_box_yes(tr::now),
|
||||
tr::lng_box_no(tr::now),
|
||||
cancel));
|
||||
}
|
||||
});
|
||||
|
||||
const auto abort = container->add(
|
||||
object_ptr<Ui::SlideWrap<Button>>(
|
||||
container,
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 65712d18253905d72db28d10d319e3c53616c915
|
||||
Subproject commit a23c05c44e4f01dc4428f4d75d4db98c59d313a6
|
Loading…
Add table
Reference in a new issue