mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +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_ok" = "OK";
|
||||||
"lng_box_done" = "Done";
|
"lng_box_done" = "Done";
|
||||||
|
"lng_box_yes" = "Yes";
|
||||||
|
"lng_box_no" = "No";
|
||||||
|
|
||||||
"lng_cancel" = "Cancel";
|
"lng_cancel" = "Cancel";
|
||||||
"lng_continue" = "Continue";
|
"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_remove" = "Remove cloud password";
|
||||||
"lng_cloud_password_set" = "Enable two-step verification";
|
"lng_cloud_password_set" = "Enable two-step verification";
|
||||||
"lng_cloud_password_edit" = "Change cloud password";
|
"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_old" = "Enter current password";
|
||||||
"lng_cloud_password_enter_first" = "Enter a password";
|
"lng_cloud_password_enter_first" = "Enter a password";
|
||||||
"lng_cloud_password_enter_new" = "Enter new 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_passport_losing" = "Warning! All data saved in your Telegram Passport will be lost!";
|
||||||
"lng_cloud_password_resend" = "Resend code";
|
"lng_cloud_password_resend" = "Resend code";
|
||||||
"lng_cloud_password_resent" = "Code was resent.";
|
"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_connecting" = "Default (connecting...)";
|
||||||
"lng_connection_auto" = "Default ({transport} used)";
|
"lng_connection_auto" = "Default ({transport} used)";
|
||||||
|
|
|
@ -4764,6 +4764,23 @@ void ApiWrap::reloadPasswordState() {
|
||||||
}).send();
|
}).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() {
|
void ApiWrap::clearUnconfirmedPassword() {
|
||||||
_passwordRequestId = request(MTPaccount_CancelPasswordEmail(
|
_passwordRequestId = request(MTPaccount_CancelPasswordEmail(
|
||||||
)).done([=](const MTPBool &result) {
|
)).done([=](const MTPBool &result) {
|
||||||
|
|
|
@ -434,6 +434,7 @@ public:
|
||||||
void clearPeerPhoto(not_null<PhotoData*> photo);
|
void clearPeerPhoto(not_null<PhotoData*> photo);
|
||||||
|
|
||||||
void reloadPasswordState();
|
void reloadPasswordState();
|
||||||
|
void applyPendingReset(const MTPaccount_ResetPasswordResult &data);
|
||||||
void clearUnconfirmedPassword();
|
void clearUnconfirmedPassword();
|
||||||
rpl::producer<Core::CloudPasswordState> passwordState() const;
|
rpl::producer<Core::CloudPasswordState> passwordState() const;
|
||||||
std::optional<Core::CloudPasswordState> passwordStateCurrent() 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 "lang/lang_keys.h"
|
||||||
#include "boxes/confirm_box.h"
|
#include "boxes/confirm_box.h"
|
||||||
#include "boxes/confirm_phone_box.h"
|
#include "boxes/confirm_phone_box.h"
|
||||||
|
#include "base/unixtime.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "main/main_session.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
|
} // namespace
|
||||||
|
|
||||||
PasscodeBox::CloudFields PasscodeBox::CloudFields::From(
|
PasscodeBox::CloudFields PasscodeBox::CloudFields::From(
|
||||||
|
@ -106,6 +157,7 @@ PasscodeBox::CloudFields PasscodeBox::CloudFields::From(
|
||||||
result.hasRecovery = current.hasRecovery;
|
result.hasRecovery = current.hasRecovery;
|
||||||
result.notEmptyPassport = current.notEmptyPassport;
|
result.notEmptyPassport = current.notEmptyPassport;
|
||||||
result.hint = current.hint;
|
result.hint = current.hint;
|
||||||
|
result.pendingResetDate = current.pendingResetDate;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,7 +197,8 @@ PasscodeBox::PasscodeBox(
|
||||||
, _reenterPasscode(this, st::defaultInputField, tr::lng_cloud_password_confirm_new())
|
, _reenterPasscode(this, st::defaultInputField, tr::lng_cloud_password_confirm_new())
|
||||||
, _passwordHint(this, st::defaultInputField, fields.curRequest ? tr::lng_cloud_password_change_hint() : tr::lng_cloud_password_hint())
|
, _passwordHint(this, st::defaultInputField, fields.curRequest ? tr::lng_cloud_password_change_hint() : tr::lng_cloud_password_hint())
|
||||||
, _recoverEmail(this, st::defaultInputField, tr::lng_cloud_password_email())
|
, _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);
|
Expects(!_turningOff || _cloudFields.curRequest);
|
||||||
|
|
||||||
if (!_cloudFields.hint.isEmpty()) {
|
if (!_cloudFields.hint.isEmpty()) {
|
||||||
|
@ -203,14 +256,14 @@ void PasscodeBox::prepare() {
|
||||||
: _cloudPwd
|
: _cloudPwd
|
||||||
? tr::lng_cloud_password_remove()
|
? tr::lng_cloud_password_remove()
|
||||||
: tr::lng_passcode_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 {
|
} else {
|
||||||
if (currentlyHave()) {
|
if (currentlyHave()) {
|
||||||
_oldPasscode->show();
|
_oldPasscode->show();
|
||||||
setTitle(_cloudPwd
|
setTitle(_cloudPwd
|
||||||
? tr::lng_cloud_password_change()
|
? tr::lng_cloud_password_change()
|
||||||
: tr::lng_passcode_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 {
|
} else {
|
||||||
_oldPasscode->hide();
|
_oldPasscode->hide();
|
||||||
setTitle(_cloudPwd
|
setTitle(_cloudPwd
|
||||||
|
@ -237,7 +290,9 @@ void PasscodeBox::prepare() {
|
||||||
|
|
||||||
const auto has = currentlyHave();
|
const auto has = currentlyHave();
|
||||||
_oldPasscode->setVisible(onlyCheck || has);
|
_oldPasscode->setVisible(onlyCheck || has);
|
||||||
_recover->setVisible((onlyCheck || has) && _cloudPwd && _cloudFields.hasRecovery);
|
_recover->setVisible((onlyCheck || has)
|
||||||
|
&& _cloudPwd
|
||||||
|
&& _showRecoverLink);
|
||||||
_newPasscode->setVisible(!onlyCheck);
|
_newPasscode->setVisible(!onlyCheck);
|
||||||
_reenterPasscode->setVisible(!onlyCheck);
|
_reenterPasscode->setVisible(!onlyCheck);
|
||||||
_passwordHint->setVisible(!onlyCheck && _cloudPwd);
|
_passwordHint->setVisible(!onlyCheck && _cloudPwd);
|
||||||
|
@ -285,7 +340,7 @@ void PasscodeBox::paintEvent(QPaintEvent *e) {
|
||||||
Painter p(this);
|
Painter p(this);
|
||||||
|
|
||||||
int32 w = st::boxWidth - st::boxPadding.left() * 1.5;
|
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);
|
p.setPen(st::boxTextFg);
|
||||||
_about.drawLeft(p, st::boxPadding.left(), abouty, w, width());
|
_about.drawLeft(p, st::boxPadding.left(), abouty, w, width());
|
||||||
|
|
||||||
|
@ -317,7 +372,7 @@ void PasscodeBox::resizeEvent(QResizeEvent *e) {
|
||||||
_oldPasscode->resize(w, _oldPasscode->height());
|
_oldPasscode->resize(w, _oldPasscode->height());
|
||||||
_oldPasscode->moveToLeft(st::boxPadding.left(), st::passcodePadding.top());
|
_oldPasscode->moveToLeft(st::boxPadding.left(), st::passcodePadding.top());
|
||||||
_newPasscode->resize(w, _newPasscode->height());
|
_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->resize(w, _reenterPasscode->height());
|
||||||
_reenterPasscode->moveToLeft(st::boxPadding.left(), _newPasscode->y() + _newPasscode->height() + st::passcodeLittleSkip);
|
_reenterPasscode->moveToLeft(st::boxPadding.left(), _newPasscode->y() + _newPasscode->height() + st::passcodeLittleSkip);
|
||||||
_passwordHint->resize(w, _passwordHint->height());
|
_passwordHint->resize(w, _passwordHint->height());
|
||||||
|
@ -379,7 +434,7 @@ void PasscodeBox::setPasswordFail(const QString &type) {
|
||||||
_oldPasscode->setFocus();
|
_oldPasscode->setFocus();
|
||||||
_oldPasscode->showError();
|
_oldPasscode->showError();
|
||||||
_oldError = tr::lng_flood_error(tr::now);
|
_oldError = tr::lng_flood_error(tr::now);
|
||||||
if (_cloudFields.hasRecovery && _hintText.isEmpty()) {
|
if (_showRecoverLink && _hintText.isEmpty()) {
|
||||||
_recover->hide();
|
_recover->hide();
|
||||||
}
|
}
|
||||||
update();
|
update();
|
||||||
|
@ -913,7 +968,7 @@ void PasscodeBox::badOldPasscode() {
|
||||||
_oldError = _cloudPwd
|
_oldError = _cloudPwd
|
||||||
? tr::lng_cloud_password_wrong(tr::now)
|
? tr::lng_cloud_password_wrong(tr::now)
|
||||||
: tr::lng_passcode_wrong(tr::now);
|
: tr::lng_passcode_wrong(tr::now);
|
||||||
if (_cloudFields.hasRecovery && _hintText.isEmpty()) {
|
if (_showRecoverLink && _hintText.isEmpty()) {
|
||||||
_recover->hide();
|
_recover->hide();
|
||||||
}
|
}
|
||||||
update();
|
update();
|
||||||
|
@ -922,7 +977,7 @@ void PasscodeBox::badOldPasscode() {
|
||||||
void PasscodeBox::oldChanged() {
|
void PasscodeBox::oldChanged() {
|
||||||
if (!_oldError.isEmpty()) {
|
if (!_oldError.isEmpty()) {
|
||||||
_oldError = QString();
|
_oldError = QString();
|
||||||
if (_cloudFields.hasRecovery && _hintText.isEmpty()) {
|
if (_showRecoverLink && _hintText.isEmpty()) {
|
||||||
_recover->show();
|
_recover->show();
|
||||||
}
|
}
|
||||||
update();
|
update();
|
||||||
|
@ -944,7 +999,21 @@ void PasscodeBox::emailChanged() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PasscodeBox::recoverByEmail() {
|
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 = "-";
|
_pattern = "-";
|
||||||
_api.request(MTPauth_RequestPasswordRecovery(
|
_api.request(MTPauth_RequestPasswordRecovery(
|
||||||
)).done([=](const MTPauth_PasswordRecovery &result) {
|
)).done([=](const MTPauth_PasswordRecovery &result) {
|
||||||
|
@ -964,10 +1033,13 @@ void PasscodeBox::recoverExpired() {
|
||||||
void PasscodeBox::recover() {
|
void PasscodeBox::recover() {
|
||||||
if (_pattern == "-") return;
|
if (_pattern == "-") return;
|
||||||
|
|
||||||
|
const auto weak = Ui::MakeWeak(this);
|
||||||
const auto box = getDelegate()->show(Box<RecoverBox>(
|
const auto box = getDelegate()->show(Box<RecoverBox>(
|
||||||
_session,
|
_session,
|
||||||
_pattern,
|
_pattern,
|
||||||
_cloudFields.notEmptyPassport));
|
_cloudFields.notEmptyPassport,
|
||||||
|
_cloudFields.pendingResetDate != 0,
|
||||||
|
[weak] { if (weak) { weak->closeBox(); } }));
|
||||||
|
|
||||||
box->passwordCleared(
|
box->passwordCleared(
|
||||||
) | rpl::map_to(
|
) | rpl::map_to(
|
||||||
|
@ -996,11 +1068,37 @@ RecoverBox::RecoverBox(
|
||||||
QWidget*,
|
QWidget*,
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
const QString &pattern,
|
const QString &pattern,
|
||||||
bool notEmptyPassport)
|
bool notEmptyPassport,
|
||||||
|
bool hasPendingReset,
|
||||||
|
Fn<void()> closeParent)
|
||||||
: _api(&session->mtp())
|
: _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))
|
, _pattern(st::normalFont->elided(tr::lng_signin_recover_hint(tr::now, lt_recover_email, pattern), st::boxWidth - st::boxPadding.left() * 1.5))
|
||||||
, _notEmptyPassport(notEmptyPassport)
|
, _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 {
|
rpl::producer<> RecoverBox::passwordCleared() const {
|
||||||
|
@ -1017,7 +1115,13 @@ void RecoverBox::prepare() {
|
||||||
addButton(tr::lng_passcode_submit(), [=] { submit(); });
|
addButton(tr::lng_passcode_submit(), [=] { submit(); });
|
||||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
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::changed, [=] { codeChanged(); });
|
||||||
connect(_recoverCode, &Ui::InputField::submitted, [=] { submit(); });
|
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->resize(st::boxWidth - st::boxPadding.left() - st::boxPadding.right(), _recoverCode->height());
|
||||||
_recoverCode->moveToLeft(st::boxPadding.left(), st::passcodePadding.top() + st::passcodePadding.bottom() + st::passcodeTextLine);
|
_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() {
|
void RecoverBox::setInnerFocus() {
|
||||||
|
@ -1085,11 +1192,18 @@ void RecoverBox::submit() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecoverBox::codeChanged() {
|
void RecoverBox::setError(const QString &error) {
|
||||||
_error = QString();
|
_error = error;
|
||||||
|
if (_noEmailAccess) {
|
||||||
|
_noEmailAccess->setVisible(error.isEmpty());
|
||||||
|
}
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RecoverBox::codeChanged() {
|
||||||
|
setError(QString());
|
||||||
|
}
|
||||||
|
|
||||||
void RecoverBox::codeSubmitDone(const MTPauth_Authorization &result) {
|
void RecoverBox::codeSubmitDone(const MTPauth_Authorization &result) {
|
||||||
_submitRequest = 0;
|
_submitRequest = 0;
|
||||||
|
|
||||||
|
@ -1102,8 +1216,7 @@ void RecoverBox::codeSubmitDone(const MTPauth_Authorization &result) {
|
||||||
void RecoverBox::codeSubmitFail(const MTP::Error &error) {
|
void RecoverBox::codeSubmitFail(const MTP::Error &error) {
|
||||||
if (MTP::IsFloodError(error)) {
|
if (MTP::IsFloodError(error)) {
|
||||||
_submitRequest = 0;
|
_submitRequest = 0;
|
||||||
_error = tr::lng_flood_error(tr::now);
|
setError(tr::lng_flood_error(tr::now));
|
||||||
update();
|
|
||||||
_recoverCode->showError();
|
_recoverCode->showError();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1121,18 +1234,14 @@ void RecoverBox::codeSubmitFail(const MTP::Error &error) {
|
||||||
_recoveryExpired.fire({});
|
_recoveryExpired.fire({});
|
||||||
closeBox();
|
closeBox();
|
||||||
} else if (err == qstr("CODE_INVALID")) {
|
} else if (err == qstr("CODE_INVALID")) {
|
||||||
_error = tr::lng_signin_wrong_code(tr::now);
|
setError(tr::lng_signin_wrong_code(tr::now));
|
||||||
update();
|
|
||||||
_recoverCode->selectAll();
|
_recoverCode->selectAll();
|
||||||
_recoverCode->setFocus();
|
_recoverCode->setFocus();
|
||||||
_recoverCode->showError();
|
_recoverCode->showError();
|
||||||
} else {
|
} else {
|
||||||
if (Logs::DebugEnabled()) { // internal server error
|
setError(Logs::DebugEnabled() // internal server error
|
||||||
_error = err + ": " + error.description();
|
? (err + ": " + error.description())
|
||||||
} else {
|
: Lang::Hard::ServerError());
|
||||||
_error = Lang::Hard::ServerError();
|
|
||||||
}
|
|
||||||
update();
|
|
||||||
_recoverCode->setFocus();
|
_recoverCode->setFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ public:
|
||||||
QString hint;
|
QString hint;
|
||||||
Core::SecureSecretAlgo newSecureSecretAlgo;
|
Core::SecureSecretAlgo newSecureSecretAlgo;
|
||||||
bool turningOff = false;
|
bool turningOff = false;
|
||||||
|
TimeId pendingResetDate = 0;
|
||||||
|
|
||||||
// Check cloud password for some action.
|
// Check cloud password for some action.
|
||||||
Fn<void(const Core::CloudPasswordResult &)> customCheckCallback;
|
Fn<void(const Core::CloudPasswordResult &)> customCheckCallback;
|
||||||
|
@ -157,6 +158,7 @@ private:
|
||||||
object_ptr<Ui::InputField> _passwordHint;
|
object_ptr<Ui::InputField> _passwordHint;
|
||||||
object_ptr<Ui::InputField> _recoverEmail;
|
object_ptr<Ui::InputField> _recoverEmail;
|
||||||
object_ptr<Ui::LinkButton> _recover;
|
object_ptr<Ui::LinkButton> _recover;
|
||||||
|
bool _showRecoverLink = false;
|
||||||
|
|
||||||
QString _oldError, _newError, _emailError;
|
QString _oldError, _newError, _emailError;
|
||||||
|
|
||||||
|
@ -172,7 +174,9 @@ public:
|
||||||
QWidget*,
|
QWidget*,
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
const QString &pattern,
|
const QString &pattern,
|
||||||
bool notEmptyPassport);
|
bool notEmptyPassport,
|
||||||
|
bool hasPendingReset,
|
||||||
|
Fn<void()> closeParent = nullptr);
|
||||||
|
|
||||||
rpl::producer<> passwordCleared() const;
|
rpl::producer<> passwordCleared() const;
|
||||||
rpl::producer<> recoveryExpired() const;
|
rpl::producer<> recoveryExpired() const;
|
||||||
|
@ -192,6 +196,7 @@ private:
|
||||||
void codeChanged();
|
void codeChanged();
|
||||||
void codeSubmitDone(const MTPauth_Authorization &result);
|
void codeSubmitDone(const MTPauth_Authorization &result);
|
||||||
void codeSubmitFail(const MTP::Error &error);
|
void codeSubmitFail(const MTP::Error &error);
|
||||||
|
void setError(const QString &error);
|
||||||
|
|
||||||
MTP::Sender _api;
|
MTP::Sender _api;
|
||||||
mtpRequestId _submitRequest = 0;
|
mtpRequestId _submitRequest = 0;
|
||||||
|
@ -200,6 +205,8 @@ private:
|
||||||
bool _notEmptyPassport = false;
|
bool _notEmptyPassport = false;
|
||||||
|
|
||||||
object_ptr<Ui::InputField> _recoverCode;
|
object_ptr<Ui::InputField> _recoverCode;
|
||||||
|
object_ptr<Ui::LinkButton> _noEmailAccess;
|
||||||
|
Fn<void()> _closeParent;
|
||||||
|
|
||||||
QString _error;
|
QString _error;
|
||||||
|
|
||||||
|
|
|
@ -314,6 +314,7 @@ CloudPasswordState ParseCloudPasswordState(
|
||||||
ParseSecureSecretAlgo(data.vnew_secure_algo()));
|
ParseSecureSecretAlgo(data.vnew_secure_algo()));
|
||||||
result.unconfirmedPattern =
|
result.unconfirmedPattern =
|
||||||
qs(data.vemail_unconfirmed_pattern().value_or_empty());
|
qs(data.vemail_unconfirmed_pattern().value_or_empty());
|
||||||
|
result.pendingResetDate = data.vpending_reset_date().value_or_empty();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,7 @@ struct CloudPasswordState {
|
||||||
CloudPasswordAlgo newPassword;
|
CloudPasswordAlgo newPassword;
|
||||||
SecureSecretAlgo newSecureSecret;
|
SecureSecretAlgo newSecureSecret;
|
||||||
QString unconfirmedPattern;
|
QString unconfirmedPattern;
|
||||||
|
TimeId pendingResetDate = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
CloudPasswordState ParseCloudPasswordState(
|
CloudPasswordState ParseCloudPasswordState(
|
||||||
|
|
|
@ -1001,7 +1001,8 @@ void FormController::recoverPassword() {
|
||||||
const auto box = _view->show(Box<RecoverBox>(
|
const auto box = _view->show(Box<RecoverBox>(
|
||||||
&_controller->session(),
|
&_controller->session(),
|
||||||
pattern,
|
pattern,
|
||||||
_password.notEmptyPassport));
|
_password.notEmptyPassport,
|
||||||
|
_password.pendingResetDate != 0));
|
||||||
|
|
||||||
box->passwordCleared(
|
box->passwordCleared(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
|
@ -2636,6 +2637,7 @@ bool FormController::applyPassword(const MTPDaccount_password &result) {
|
||||||
Core::ParseCloudPasswordAlgo(result.vnew_algo()));
|
Core::ParseCloudPasswordAlgo(result.vnew_algo()));
|
||||||
settings.newSecureAlgo = Core::ValidateNewSecureSecretAlgo(
|
settings.newSecureAlgo = Core::ValidateNewSecureSecretAlgo(
|
||||||
Core::ParseSecureSecretAlgo(result.vnew_secure_algo()));
|
Core::ParseSecureSecretAlgo(result.vnew_secure_algo()));
|
||||||
|
settings.pendingResetDate = result.vpending_reset_date().value_or_empty();
|
||||||
openssl::AddRandomSeed(bytes::make_span(result.vsecure_random().v));
|
openssl::AddRandomSeed(bytes::make_span(result.vsecure_random().v));
|
||||||
return applyPassword(std::move(settings));
|
return applyPassword(std::move(settings));
|
||||||
}
|
}
|
||||||
|
|
|
@ -280,6 +280,7 @@ struct PasswordSettings {
|
||||||
bool hasRecovery = false;
|
bool hasRecovery = false;
|
||||||
bool notEmptyPassport = false;
|
bool notEmptyPassport = false;
|
||||||
bool unknownAlgo = false;
|
bool unknownAlgo = false;
|
||||||
|
TimeId pendingResetDate = 0;
|
||||||
|
|
||||||
bool operator==(const PasswordSettings &other) const {
|
bool operator==(const PasswordSettings &other) const {
|
||||||
return (request == other.request)
|
return (request == other.request)
|
||||||
|
@ -296,7 +297,8 @@ struct PasswordSettings {
|
||||||
&& (unconfirmedPattern == other.unconfirmedPattern)
|
&& (unconfirmedPattern == other.unconfirmedPattern)
|
||||||
&& (confirmedEmail == other.confirmedEmail)
|
&& (confirmedEmail == other.confirmedEmail)
|
||||||
&& (hasRecovery == other.hasRecovery)
|
&& (hasRecovery == other.hasRecovery)
|
||||||
&& (unknownAlgo == other.unknownAlgo);
|
&& (unknownAlgo == other.unknownAlgo)
|
||||||
|
&& (pendingResetDate == other.pendingResetDate);
|
||||||
}
|
}
|
||||||
bool operator!=(const PasswordSettings &other) const {
|
bool operator!=(const PasswordSettings &other) const {
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
|
|
|
@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "settings/settings_common.h"
|
#include "settings/settings_common.h"
|
||||||
#include "settings/settings_privacy_controllers.h"
|
#include "settings/settings_privacy_controllers.h"
|
||||||
#include "base/timer_rpl.h"
|
#include "base/timer_rpl.h"
|
||||||
|
#include "base/unixtime.h"
|
||||||
#include "boxes/peer_list_box.h"
|
#include "boxes/peer_list_box.h"
|
||||||
#include "boxes/edit_privacy_box.h"
|
#include "boxes/edit_privacy_box.h"
|
||||||
#include "boxes/passcode_box.h"
|
#include "boxes/passcode_box.h"
|
||||||
|
@ -359,6 +360,10 @@ void SetupCloudPassword(
|
||||||
) | rpl::then(rpl::duplicate(
|
) | rpl::then(rpl::duplicate(
|
||||||
unconfirmed
|
unconfirmed
|
||||||
));
|
));
|
||||||
|
auto resetAt = session->api().passwordState(
|
||||||
|
) | rpl::map([](const State &state) {
|
||||||
|
return state.pendingResetDate;
|
||||||
|
});
|
||||||
const auto label = container->add(
|
const auto label = container->add(
|
||||||
object_ptr<Ui::SlideWrap<Ui::FlatLabel>>(
|
object_ptr<Ui::SlideWrap<Ui::FlatLabel>>(
|
||||||
container,
|
container,
|
||||||
|
@ -464,6 +469,118 @@ void SetupCloudPassword(
|
||||||
_1 && !_2));
|
_1 && !_2));
|
||||||
disable->entity()->addClickHandler(remove);
|
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(
|
const auto abort = container->add(
|
||||||
object_ptr<Ui::SlideWrap<Button>>(
|
object_ptr<Ui::SlideWrap<Button>>(
|
||||||
container,
|
container,
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 65712d18253905d72db28d10d319e3c53616c915
|
Subproject commit a23c05c44e4f01dc4428f4d75d4db98c59d313a6
|
Loading…
Add table
Reference in a new issue