Warn user about passport reset.

Also suggest country by phone number in passport.
This commit is contained in:
John Preston 2018-04-20 20:42:51 +04:00
parent 275ec3e679
commit ab5f35e952
15 changed files with 141 additions and 53 deletions

View File

@ -587,7 +587,7 @@ authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string s
account.authorizations#1250abde authorizations:Vector<Authorization> = account.Authorizations;
account.noPassword#5ea182f6 new_salt:bytes new_secure_salt:bytes secure_random:bytes email_unconfirmed_pattern:string = account.Password;
account.password#d06c5fc3 current_salt:bytes new_salt:bytes new_secure_salt:bytes secure_random:bytes hint:string has_recovery:Bool email_unconfirmed_pattern:string = account.Password;
account.password#ca39b447 flags:# has_recovery:flags.0?true has_secure_values:flags.1?true current_salt:bytes new_salt:bytes new_secure_salt:bytes secure_random:bytes hint:string email_unconfirmed_pattern:string = account.Password;
account.passwordSettings#7bd9c3f1 email:string secure_salt:bytes secure_secret:bytes secure_secret_id:long = account.PasswordSettings;

View File

@ -33,6 +33,7 @@ PasscodeBox::PasscodeBox(
const QByteArray &newSalt,
const QByteArray &curSalt,
bool hasRecovery,
bool notEmptyPassport,
const QString &hint,
const QByteArray &newSecureSecretSalt,
bool turningOff)
@ -42,6 +43,7 @@ PasscodeBox::PasscodeBox(
, _curSalt(curSalt)
, _newSecureSecretSalt(newSecureSecretSalt)
, _hasRecovery(hasRecovery)
, _notEmptyPassport(notEmptyPassport)
, _about(st::boxWidth - st::boxPadding.left() * 1.5)
, _oldPasscode(this, st::defaultInputField, langFactory(lng_cloud_password_enter_old))
, _newPasscode(this, st::defaultInputField, langFactory(curSalt.isEmpty() ? lng_cloud_password_enter_first : lng_cloud_password_enter_new))
@ -339,30 +341,31 @@ void PasscodeBox::save(bool force) {
void PasscodeBox::clearCloudPassword(const QString &oldPassword) {
Expects(!_oldPasscode->isHidden());
const auto send = [=] {
sendClearCloudPassword(oldPassword);
};
if (_notEmptyPassport) {
const auto box = std::make_shared<QPointer<BoxContent>>();
const auto confirmed = [=] {
send();
if (*box) {
(*box)->closeBox();
}
};
*box = getDelegate()->show(Box<ConfirmBox>(
lang(lng_cloud_password_passport_losing),
lang(lng_continue),
confirmed));
} else {
send();
}
}
void PasscodeBox::sendClearCloudPassword(const QString &oldPassword) {
const auto passwordUtf = oldPassword.toUtf8();
const auto oldPasswordData = (_curSalt + passwordUtf + _curSalt);
auto oldPasswordHash = QByteArray(32, Qt::Uninitialized);
hashSha256(oldPasswordData.constData(), oldPasswordData.size(), oldPasswordHash.data());
_setRequest = request(MTPaccount_GetPasswordSettings(
MTP_bytes(oldPasswordHash)
)).done([=](const MTPaccount_PasswordSettings &result) {
_setRequest = 0;
Expects(result.type() == mtpc_account_passwordSettings);
const auto &data = result.c_account_passwordSettings();
if (data.vsecure_secret.v.isEmpty()) {
sendClearCloudPassword(oldPasswordHash);
return;
}
warnPassportLoss(oldPasswordHash);
}).fail([=](const RPCError &error) {
setPasswordFail(error);
}).send();
}
void PasscodeBox::sendClearCloudPassword(
const QByteArray &oldPasswordHash) {
const auto newPasswordData = QByteArray();
const auto newPasswordHash = QByteArray();
const auto hint = QString();
@ -389,20 +392,6 @@ void PasscodeBox::sendClearCloudPassword(
}).send();
}
void PasscodeBox::warnPassportLoss(const QByteArray &oldPasswordHash) {
const auto box = std::make_shared<QPointer<BoxContent>>();
const auto sendAndClose = [=] {
sendClearCloudPassword(oldPasswordHash);
if (*box) {
(*box)->closeBox();
}
};
*box = getDelegate()->show(Box<ConfirmBox>(
lang(lng_cloud_password_passport_losing),
lang(lng_continue),
sendAndClose));
}
void PasscodeBox::setNewCloudPassword(const QString &newPassword) {
const auto newPasswordData = (_newSalt + newPassword.toUtf8() + _newSalt);
auto newPasswordHash = QByteArray(32, Qt::Uninitialized);
@ -611,7 +600,9 @@ void PasscodeBox::recoverExpired() {
void PasscodeBox::recover() {
if (_pattern == "-") return;
const auto box = getDelegate()->show(Box<RecoverBox>(_pattern));
const auto box = getDelegate()->show(Box<RecoverBox>(
_pattern,
_notEmptyPassport));
connect(box, &RecoverBox::reloadPassword, this, &PasscodeBox::reloadPassword);
connect(box, &RecoverBox::recoveryExpired, this, &PasscodeBox::recoverExpired);
_replacedBy = box;
@ -630,8 +621,12 @@ bool PasscodeBox::recoverStartFail(const RPCError &error) {
return true;
}
RecoverBox::RecoverBox(QWidget*, const QString &pattern)
RecoverBox::RecoverBox(
QWidget*,
const QString &pattern,
bool notEmptyPassport)
: _pattern(st::normalFont->elided(lng_signin_recover_hint(lt_recover_email, pattern), st::boxWidth - st::boxPadding.left() * 1.5))
, _notEmptyPassport(notEmptyPassport)
, _recoverCode(this, st::defaultInputField, langFactory(lng_signin_code)) {
}
@ -684,7 +679,27 @@ void RecoverBox::submit() {
return;
}
_submitRequest = MTP::send(MTPauth_RecoverPassword(MTP_string(code)), rpcDone(&RecoverBox::codeSubmitDone, true), rpcFail(&RecoverBox::codeSubmitFail));
const auto send = base::lambda_guarded(this, [=] {
_submitRequest = MTP::send(
MTPauth_RecoverPassword(MTP_string(code)),
rpcDone(&RecoverBox::codeSubmitDone, true),
rpcFail(&RecoverBox::codeSubmitFail));
});
if (_notEmptyPassport) {
const auto box = std::make_shared<QPointer<BoxContent>>();
const auto confirmed = [=] {
send();
if (*box) {
(*box)->closeBox();
}
};
*box = getDelegate()->show(Box<ConfirmBox>(
lang(lng_cloud_password_passport_losing),
lang(lng_continue),
confirmed));
} else {
send();
}
}
void RecoverBox::codeChanged() {

View File

@ -26,6 +26,7 @@ public:
const QByteArray &newSalt,
const QByteArray &curSalt,
bool hasRecovery,
bool notEmptyPassport,
const QString &hint,
const QByteArray &newSecureSecretSalt,
bool turningOff = false);
@ -73,8 +74,7 @@ private:
void resetSecretAndChangePassword(
const QByteArray &oldPasswordHash,
const QString &newPassword);
void sendClearCloudPassword(const QByteArray &oldPasswordHash);
void warnPassportLoss(const QByteArray &oldPasswordHash);
void sendClearCloudPassword(const QString &oldPassword);
QString _pattern;
@ -85,6 +85,7 @@ private:
QByteArray _newSalt, _curSalt, _newSecureSecretSalt;
bool _hasRecovery = false;
bool _notEmptyPassport = false;
bool _skipEmailWarning = false;
int _aboutHeight = 0;
@ -106,7 +107,7 @@ class RecoverBox : public BoxContent, public RPCSender {
Q_OBJECT
public:
RecoverBox(QWidget*, const QString &pattern);
RecoverBox(QWidget*, const QString &pattern, bool notEmptyPassport);
signals:
void reloadPassword();
@ -128,6 +129,7 @@ private:
mtpRequestId _submitRequest = 0;
QString _pattern;
bool _notEmptyPassport = false;
object_ptr<Ui::InputField> _recoverCode;

View File

@ -296,8 +296,9 @@ void CodeWidget::gotPassword(const MTPaccount_Password &result) {
case mtpc_account_password: {
auto &d = result.c_account_password();
getData()->pwdSalt = qba(d.vcurrent_salt);
getData()->hasRecovery = mtpIsTrue(d.vhas_recovery);
getData()->hasRecovery = d.is_has_recovery();
getData()->pwdHint = qs(d.vhint);
getData()->pwdNotEmptyPassport = d.is_has_secure_values();
goReplace(new Intro::PwdCheckWidget(parentWidget(), getData()));
} break;
}
@ -314,6 +315,7 @@ void CodeWidget::submit() {
getData()->pwdSalt = QByteArray();
getData()->hasRecovery = false;
getData()->pwdHint = QString();
getData()->pwdNotEmptyPassport = false;
_sentRequest = MTP::send(MTPauth_SignIn(MTP_string(getData()->phone), MTP_bytes(getData()->phoneHash), MTP_string(_sentCode)), rpcDone(&CodeWidget::codeSubmitDone), rpcFail(&CodeWidget::codeSubmitFail));
}

View File

@ -23,6 +23,7 @@ namespace Intro {
PwdCheckWidget::PwdCheckWidget(QWidget *parent, Widget::Data *data) : Step(parent, data)
, _salt(getData()->pwdSalt)
, _hasRecovery(getData()->hasRecovery)
, _notEmptyPassport(getData()->pwdNotEmptyPassport)
, _hint(getData()->pwdHint)
, _pwdField(this, st::introPassword, langFactory(lng_signin_password))
, _pwdHint(this, st::introPasswordHint)
@ -276,8 +277,28 @@ void PwdCheckWidget::submit() {
_codeField->showError();
return;
}
const auto send = base::lambda_guarded(this, [=] {
_sentRequest = MTP::send(
MTPauth_RecoverPassword(MTP_string(code)),
rpcDone(&PwdCheckWidget::pwdSubmitDone, true),
rpcFail(&PwdCheckWidget::codeSubmitFail));
});
_sentRequest = MTP::send(MTPauth_RecoverPassword(MTP_string(code)), rpcDone(&PwdCheckWidget::pwdSubmitDone, true), rpcFail(&PwdCheckWidget::codeSubmitFail));
if (_notEmptyPassport) {
const auto box = std::make_shared<QPointer<BoxContent>>();
const auto confirmed = [=] {
send();
if (*box) {
(*box)->closeBox();
}
};
*box = Ui::show(Box<ConfirmBox>(
lang(lng_cloud_password_passport_losing),
lang(lng_continue),
confirmed));
} else {
send();
}
} else {
hideError();

View File

@ -55,7 +55,8 @@ private:
void stopCheck();
QByteArray _salt;
bool _hasRecovery;
bool _hasRecovery = false;
bool _notEmptyPassport = false;
QString _hint, _emailPattern;
object_ptr<Ui::PasswordInput> _pwdField;

View File

@ -76,6 +76,7 @@ public:
QByteArray pwdSalt;
bool hasRecovery = false;
QString pwdHint;
bool pwdNotEmptyPassport = false;
TextWithEntities termsText;
bool termsPopup = false;

View File

@ -408,7 +408,9 @@ void FormController::recoverPassword() {
const auto &data = result.c_auth_passwordRecovery();
const auto pattern = qs(data.vemail_pattern);
const auto box = _view->show(Box<RecoverBox>(pattern));
const auto box = _view->show(Box<RecoverBox>(
pattern,
_password.notEmptyPassport));
box->connect(box, &RecoverBox::reloadPassword, [=] {
reloadPassword();
});
@ -1910,7 +1912,8 @@ bool FormController::applyPassword(const MTPDaccount_noPassword &result) {
bool FormController::applyPassword(const MTPDaccount_password &result) {
auto settings = PasswordSettings();
settings.hint = qs(result.vhint);
settings.hasRecovery = mtpIsTrue(result.vhas_recovery);
settings.hasRecovery = result.is_has_recovery();
settings.notEmptyPassport = result.is_has_secure_values();
settings.salt = bytes::make_vector(result.vcurrent_salt.v);
settings.unconfirmedPattern = qs(result.vemail_unconfirmed_pattern);
settings.newSalt = bytes::make_vector(result.vnew_salt.v);

View File

@ -182,6 +182,7 @@ struct PasswordSettings {
QString unconfirmedPattern;
QString confirmedEmail;
bool hasRecovery = false;
bool notEmptyPassport = false;
bool operator==(const PasswordSettings &other) const {
return (salt == other.salt)

View File

@ -446,11 +446,13 @@ void PanelController::setupPassword() {
newSecureSecretSalt).subspan(settings.newSecureSalt.size()));
const auto currentSalt = QByteArray();
const auto hasRecovery = false;
const auto notEmptyPassport = false;
const auto hint = QString();
auto box = show(Box<PasscodeBox>(
newPasswordSalt,
currentSalt,
hasRecovery,
notEmptyPassport,
hint,
newSecureSecretSalt));
box->connect(box, &PasscodeBox::reloadPassword, _panel.get(), [=] {
@ -697,7 +699,7 @@ void PanelController::suggestReset(base::lambda<void()> callback) {
Lang::Hard::PassportCorrupted(),
Lang::Hard::PassportCorruptedReset(),
[=] { resetPassport(callback); },
[=] { cancelReset(); })).data()); // #TODO passport no need for confirmation?
[=] { cancelReset(); })).data());
}
void PanelController::resetPassport(base::lambda<void()> callback) {

View File

@ -310,8 +310,12 @@ void CountryRow::errorAnimationCallback() {
void CountryRow::chooseCountry() {
const auto top = _value.current();
const auto name = CountrySelectBox::NameByISO(top);
const auto box = _controller->show(Box<CountrySelectBox>(
(name.isEmpty() ? Platform::SystemCountry() : top),
const auto isoByPhone = CountrySelectBox::ISOByPhone(App::self()->phone());
const auto box = _controller->show(Box<CountrySelectBox>(!name.isEmpty()
? top
: !isoByPhone.isEmpty()
? isoByPhone
: Platform::SystemCountry(),
CountrySelectBox::Type::Countries));
connect(box, &CountrySelectBox::countryChosen, this, [=](QString iso) {
_value = iso;

View File

@ -78,6 +78,7 @@ void CloudPasswordState::onEdit() {
_newPasswordSalt,
_curPasswordSalt,
_hasPasswordRecovery,
_notEmptyPassport,
_curPasswordHint,
_newSecureSecretSalt));
connect(box, SIGNAL(reloadPassword()), this, SLOT(onReloadPassword()));
@ -106,6 +107,7 @@ void CloudPasswordState::onTurnOff() {
_newPasswordSalt,
_curPasswordSalt,
_hasPasswordRecovery,
_notEmptyPassport,
_curPasswordHint,
_newSecureSecretSalt,
true));
@ -113,13 +115,21 @@ void CloudPasswordState::onTurnOff() {
}
}
void CloudPasswordState::onReloadPassword() {
if (_reloadRequestId) {
return;
}
_reloadRequestId = MTP::send(MTPaccount_GetPassword(), rpcDone(&CloudPasswordState::getPasswordDone), rpcFail(&CloudPasswordState::getPasswordFail));
}
void CloudPasswordState::onReloadPassword(Qt::ApplicationState state) {
if (state == Qt::ApplicationActive) {
MTP::send(MTPaccount_GetPassword(), rpcDone(&CloudPasswordState::getPasswordDone));
if (!_waitingConfirm.isEmpty() && state == Qt::ApplicationActive) {
onReloadPassword();
}
}
void CloudPasswordState::getPasswordDone(const MTPaccount_Password &result) {
_reloadRequestId = 0;
_waitingConfirm = QString();
switch (result.type()) {
@ -127,6 +137,7 @@ void CloudPasswordState::getPasswordDone(const MTPaccount_Password &result) {
auto &d = result.c_account_noPassword();
_curPasswordSalt = QByteArray();
_hasPasswordRecovery = false;
_notEmptyPassport = false;
_curPasswordHint = QString();
_newPasswordSalt = qba(d.vnew_salt);
_newSecureSecretSalt = qba(d.vnew_secure_salt);
@ -140,7 +151,8 @@ void CloudPasswordState::getPasswordDone(const MTPaccount_Password &result) {
case mtpc_account_password: {
auto &d = result.c_account_password();
_curPasswordSalt = qba(d.vcurrent_salt);
_hasPasswordRecovery = mtpIsTrue(d.vhas_recovery);
_hasPasswordRecovery = d.is_has_recovery();
_notEmptyPassport = d.is_has_secure_values();
_curPasswordHint = qs(d.vhint);
_newPasswordSalt = qba(d.vnew_salt);
_newSecureSecretSalt = qba(d.vnew_secure_salt);
@ -166,6 +178,14 @@ void CloudPasswordState::getPasswordDone(const MTPaccount_Password &result) {
8);
}
bool CloudPasswordState::getPasswordFail(const RPCError &error) {
if (MTP::isDefaultHandledError(error)) {
return false;
}
_reloadRequestId = 0;
return true;
}
void CloudPasswordState::paintEvent(QPaintEvent *e) {
Painter p(this);

View File

@ -50,10 +50,12 @@ protected:
private slots:
void onEdit();
void onTurnOff();
void onReloadPassword(Qt::ApplicationState state = Qt::ApplicationActive);
void onReloadPassword();
void onReloadPassword(Qt::ApplicationState state);
private:
void getPasswordDone(const MTPaccount_Password &result);
bool getPasswordFail(const RPCError &error);
void offPasswordDone(const MTPBool &result);
bool offPasswordFail(const RPCError &error);
@ -63,9 +65,11 @@ private:
QString _waitingConfirm;
QByteArray _curPasswordSalt;
bool _hasPasswordRecovery = false;
bool _notEmptyPassport = false;
QString _curPasswordHint;
QByteArray _newPasswordSalt;
QByteArray _newSecureSecretSalt;
mtpRequestId _reloadRequestId = 0;
};

View File

@ -219,6 +219,17 @@ QString CountrySelectBox::NameByISO(const QString &iso) {
: QString::fromUtf8((*i)->name);
}
QString CountrySelectBox::ISOByPhone(const QString &phone) {
if (_countriesByCode.isEmpty()) {
initCountries();
}
const auto code = findValidCode(phone);
const auto i = _countriesByCode.find(code);
return (i == _countriesByCode.cend())
? QString()
: QString::fromUtf8((*i)->iso2);
}
void CountrySelectBox::prepare() {
setTitle(langFactory(lng_country_select));

View File

@ -65,6 +65,7 @@ public:
CountrySelectBox(QWidget*, const QString &iso, Type type);
static QString NameByISO(const QString &iso);
static QString ISOByPhone(const QString &phone);
signals:
void countryChosen(const QString &iso);