From 395f22063bae6b7663ddcde1d9313f1371868d4b Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Tue, 17 Apr 2018 15:26:11 +0400
Subject: [PATCH] Short poll email confirmation in passport.

---
 .../passport/passport_form_controller.cpp     | 67 ++++++++++++-------
 .../passport/passport_form_controller.h       | 20 +++++-
 2 files changed, 62 insertions(+), 25 deletions(-)

diff --git a/Telegram/SourceFiles/passport/passport_form_controller.cpp b/Telegram/SourceFiles/passport/passport_form_controller.cpp
index b5f8c7df5..8b35518e7 100644
--- a/Telegram/SourceFiles/passport/passport_form_controller.cpp
+++ b/Telegram/SourceFiles/passport/passport_form_controller.cpp
@@ -28,6 +28,7 @@ namespace Passport {
 namespace {
 
 constexpr auto kDocumentScansLimit = 20;
+constexpr auto kShortPollTimeout = TimeMs(3000);
 
 bool ForwardServiceErrorRequired(const QString &error) {
 	return (error == qstr("BOT_INVALID"))
@@ -216,6 +217,7 @@ FormController::FormController(
 	const FormRequest &request)
 : _controller(controller)
 , _request(PreprocessRequest(request))
+, _shortPollTimer([=] { reloadPassword(); })
 , _view(std::make_unique<PanelController>(this)) {
 }
 
@@ -1743,18 +1745,27 @@ void FormController::requestPassword() {
 }
 
 void FormController::passwordDone(const MTPaccount_Password &result) {
-	switch (result.type()) {
-	case mtpc_account_noPassword:
-		parsePassword(result.c_account_noPassword());
-		break;
-
-	case mtpc_account_password:
-		parsePassword(result.c_account_password());
-		break;
-	}
-	if (!_formRequestId) {
+	const auto changed = [&] {
+		switch (result.type()) {
+		case mtpc_account_noPassword:
+			return applyPassword(result.c_account_noPassword());
+		case mtpc_account_password:
+			return applyPassword(result.c_account_password());
+		}
+		Unexpected("Type in FormController::passwordDone.");
+	}();
+	if (changed && !_formRequestId) {
 		showForm();
 	}
+	shortPollEmailConfirmation();
+}
+
+void FormController::shortPollEmailConfirmation() {
+	if (_password.unconfirmedPattern.isEmpty()) {
+		_shortPollTimer.cancel();
+		return;
+	}
+	_shortPollTimer.callOnce(kShortPollTimeout);
 }
 
 void FormController::showForm() {
@@ -1769,23 +1780,33 @@ void FormController::showForm() {
 	}
 }
 
-void FormController::parsePassword(const MTPDaccount_noPassword &result) {
-	_password = PasswordSettings();
-	_password.unconfirmedPattern = qs(result.vemail_unconfirmed_pattern);
-	_password.newSalt = bytes::make_vector(result.vnew_salt.v);
-	_password.newSecureSalt = bytes::make_vector(result.vnew_secure_salt.v);
+bool FormController::applyPassword(const MTPDaccount_noPassword &result) {
+	auto settings = PasswordSettings();
+	settings.unconfirmedPattern = qs(result.vemail_unconfirmed_pattern);
+	settings.newSalt = bytes::make_vector(result.vnew_salt.v);
+	settings.newSecureSalt = bytes::make_vector(result.vnew_secure_salt.v);
 	openssl::AddRandomSeed(bytes::make_span(result.vsecure_random.v));
+	return applyPassword(std::move(settings));
 }
 
-void FormController::parsePassword(const MTPDaccount_password &result) {
-	_password = PasswordSettings();
-	_password.hint = qs(result.vhint);
-	_password.hasRecovery = mtpIsTrue(result.vhas_recovery);
-	_password.salt = bytes::make_vector(result.vcurrent_salt.v);
-	_password.unconfirmedPattern = qs(result.vemail_unconfirmed_pattern);
-	_password.newSalt = bytes::make_vector(result.vnew_salt.v);
-	_password.newSecureSalt = bytes::make_vector(result.vnew_secure_salt.v);
+bool FormController::applyPassword(const MTPDaccount_password &result) {
+	auto settings = PasswordSettings();
+	settings.hint = qs(result.vhint);
+	settings.hasRecovery = mtpIsTrue(result.vhas_recovery);
+	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);
+	settings.newSecureSalt = bytes::make_vector(result.vnew_secure_salt.v);
 	openssl::AddRandomSeed(bytes::make_span(result.vsecure_random.v));
+	return applyPassword(std::move(settings));
+}
+
+bool FormController::applyPassword(PasswordSettings &&settings) {
+	if (_password != settings) {
+		_password = std::move(settings);
+		return true;
+	}
+	return false;
 }
 
 void FormController::cancel() {
diff --git a/Telegram/SourceFiles/passport/passport_form_controller.h b/Telegram/SourceFiles/passport/passport_form_controller.h
index 215d7e503..ad88bcaf6 100644
--- a/Telegram/SourceFiles/passport/passport_form_controller.h
+++ b/Telegram/SourceFiles/passport/passport_form_controller.h
@@ -178,6 +178,19 @@ struct PasswordSettings {
 	QString unconfirmedPattern;
 	QString confirmedEmail;
 	bool hasRecovery = false;
+
+	bool operator==(const PasswordSettings &other) const {
+		return (salt == other.salt)
+			&& (newSalt == other.newSalt)
+			&& (newSecureSalt == other.newSecureSalt)
+			&& (hint == other.hint)
+			&& (unconfirmedPattern == other.unconfirmedPattern)
+			&& (confirmedEmail == other.confirmedEmail)
+			&& (hasRecovery == other.hasRecovery);
+	}
+	bool operator!=(const PasswordSettings &other) const {
+		return !(*this == other);
+	}
 };
 
 struct FileKey {
@@ -290,8 +303,9 @@ private:
 		const std::vector<EditFile> &source) const;
 
 	void passwordDone(const MTPaccount_Password &result);
-	void parsePassword(const MTPDaccount_noPassword &settings);
-	void parsePassword(const MTPDaccount_password &settings);
+	bool applyPassword(const MTPDaccount_noPassword &settings);
+	bool applyPassword(const MTPDaccount_password &settings);
+	bool applyPassword(PasswordSettings &&settings);
 	bytes::vector passwordHashForAuth(bytes::const_span password) const;
 	void validateSecureSecret(
 		bytes::const_span salt,
@@ -358,6 +372,7 @@ private:
 	void suggestReset(bytes::vector password);
 	void suggestRestart();
 	void cancelAbort();
+	void shortPollEmailConfirmation();
 
 	not_null<Window::Controller*> _controller;
 	FormRequest _request;
@@ -387,6 +402,7 @@ private:
 	bool _submitSuccess = false;
 	bool _suggestingRestart = false;
 	QString _serviceErrorText;
+	base::Timer _shortPollTimer;
 
 	rpl::lifetime _uploaderSubscriptions;
 	rpl::lifetime _lifetime;