From 6de3112c8a7a9f24581fa874dd1830847a2cc7e1 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 13 Apr 2018 22:14:14 +0400 Subject: [PATCH] Stop passport authorization with confirm. --- Telegram/Resources/langs/lang.strings | 3 + .../passport/passport_encryption.cpp | 2 +- .../passport/passport_encryption.h | 2 +- .../passport/passport_form_controller.cpp | 95 +++++++++++++------ .../passport/passport_form_controller.h | 6 +- .../passport_form_view_controller.cpp | 11 ++- .../passport/passport_form_view_controller.h | 2 + .../SourceFiles/passport/passport_panel.cpp | 6 +- .../SourceFiles/passport/passport_panel.h | 2 +- .../passport/passport_panel_controller.cpp | 7 ++ .../passport/passport_panel_controller.h | 2 + 11 files changed, 100 insertions(+), 38 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 419edd575..913d29f5d 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1594,6 +1594,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_passport_delete_email_sure" = "Are you sure you want to delete your email?"; "lng_passport_delete_phone" = "Delete phone number"; "lng_passport_delete_phone_sure" = "Are you sure you want to delete your phone number?"; +"lng_passport_success" = "Authorization successfull!"; +"lng_passport_stop_sure" = "Are you sure you want to stop this authorization?"; +"lng_passport_stop" = "Stop"; // Wnd specific diff --git a/Telegram/SourceFiles/passport/passport_encryption.cpp b/Telegram/SourceFiles/passport/passport_encryption.cpp index f614440c4..8dc17cade 100644 --- a/Telegram/SourceFiles/passport/passport_encryption.cpp +++ b/Telegram/SourceFiles/passport/passport_encryption.cpp @@ -335,7 +335,7 @@ bytes::vector DecryptValueSecret( return DecryptSecretBytes(encrypted, bytesForEncryptionKey); } -uint64 CountSecureSecretHash(bytes::const_span secret) { +uint64 CountSecureSecretId(bytes::const_span secret) { const auto full = openssl::Sha256(secret); return *reinterpret_cast(full.data()); } diff --git a/Telegram/SourceFiles/passport/passport_encryption.h b/Telegram/SourceFiles/passport/passport_encryption.h index d03041e7b..ee758a029 100644 --- a/Telegram/SourceFiles/passport/passport_encryption.h +++ b/Telegram/SourceFiles/passport/passport_encryption.h @@ -54,7 +54,7 @@ bytes::vector DecryptValueSecret( bytes::const_span secret, bytes::const_span valueHash); -uint64 CountSecureSecretHash(bytes::const_span secret); +uint64 CountSecureSecretId(bytes::const_span secret); bytes::vector EncryptCredentialsSecret( bytes::const_span secret, diff --git a/Telegram/SourceFiles/passport/passport_form_controller.cpp b/Telegram/SourceFiles/passport/passport_form_controller.cpp index 04fbddad4..c5baf2c88 100644 --- a/Telegram/SourceFiles/passport/passport_form_controller.cpp +++ b/Telegram/SourceFiles/passport/passport_form_controller.cpp @@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mainwindow.h" #include "window/window_controller.h" #include "core/click_handler_types.h" +#include "ui/toast/toast.h" #include "auth_session.h" #include "storage/localimageloader.h" #include "storage/localstorage.h" @@ -77,7 +78,7 @@ MTPSecureValueType ConvertType(Value::Type type) { }; QJsonObject GetJSONFromMap( - const std::map &map) { + const std::map &map) { auto result = QJsonObject(); for (const auto &[key, value] : map) { const auto raw = QByteArray::fromRawData( @@ -92,7 +93,7 @@ QJsonObject GetJSONFromFile(const File &file) { return GetJSONFromMap({ { "file_hash", file.hash }, { "secret", file.secret } - }); + }); } FormRequest PreprocessRequest(const FormRequest &request) { @@ -125,26 +126,26 @@ FormRequest::FormRequest( const QString &callbackUrl, const QString &publicKey, const QString &payload) -: botId(botId) -, scope(scope) -, callbackUrl(callbackUrl) -, publicKey(publicKey) -, payload(payload) { + : botId(botId) + , scope(scope) + , callbackUrl(callbackUrl) + , publicKey(publicKey) + , payload(payload) { } EditFile::EditFile( not_null value, const File &fields, std::unique_ptr &&uploadData) -: value(value) -, fields(std::move(fields)) -, uploadData(std::move(uploadData)) -, guard(std::make_shared(true)) { + : value(value) + , fields(std::move(fields)) + , uploadData(std::move(uploadData)) + , guard(std::make_shared(true)) { } UploadScanDataPointer::UploadScanDataPointer( std::unique_ptr &&value) -: _value(std::move(value)) { + : _value(std::move(value)) { } UploadScanDataPointer::UploadScanDataPointer( @@ -183,9 +184,9 @@ Value::Value(Type type) : type(type) { FormController::FormController( not_null controller, const FormRequest &request) -: _controller(controller) -, _request(PreprocessRequest(request)) -, _view(std::make_unique(this)) { + : _controller(controller) + , _request(PreprocessRequest(request)) + , _view(std::make_unique(this)) { } void FormController::show() { @@ -202,7 +203,7 @@ QString FormController::privacyPolicyUrl() const { } bytes::vector FormController::passwordHashForAuth( - bytes::const_span password) const { + bytes::const_span password) const { return openssl::Sha256(bytes::concatenate( _password.salt, password, @@ -213,14 +214,14 @@ auto FormController::prepareFinalData() -> FinalData { auto hashes = QVector(); auto secureData = QJsonObject(); const auto addValueToJSON = [&]( - const QString &key, - not_null value) { + const QString &key, + not_null value) { auto object = QJsonObject(); if (!value->data.parsed.fields.empty()) { object.insert("data", GetJSONFromMap({ { "data_hash", value->data.hash }, { "secret", value->data.secret } - })); + })); } if (!value->scans.empty()) { auto files = QJsonArray(); @@ -277,7 +278,7 @@ auto FormController::prepareFinalData() -> FinalData { } bool FormController::submit() { - if (_submitRequestId) { + if (_submitRequestId || _submitSuccess|| _cancelled) { return true; } @@ -301,11 +302,17 @@ bool FormController::submit() { MTP_bytes(credentialsEncryptedData.hash), MTP_bytes(credentialsEncryptedSecret)) )).done([=](const MTPBool &result) { - const auto url = qthelp::url_append_query( - _request.callbackUrl, - "tg_passport=success"); - UrlClickHandler::doOpen(url); + _submitRequestId = 0; + _submitSuccess = true; + + _view->showToast(lang(lng_passport_success)); + + App::CallDelayed( + Ui::Toast::DefaultDuration + st::toastFadeOutDuration, + this, + [=] { cancel(); }); }).fail([=](const RPCError &error) { + _submitRequestId = 0; _view->show(Box( "Failed sending data :(\n" + error.type())); }).send(); @@ -333,7 +340,8 @@ void FormController::submitPassword(const QString &password) { validateSecureSecret( bytes::make_span(data.vsecure_salt.v), bytes::make_span(data.vsecure_secret.v), - bytes::make_span(passwordBytes)); + bytes::make_span(passwordBytes), + data.vsecure_secret_id.v); }).fail([=](const RPCError &error) { _passwordCheckRequestId = 0; if (MTP::isFloodError(error)) { @@ -349,7 +357,8 @@ void FormController::submitPassword(const QString &password) { void FormController::validateSecureSecret( bytes::const_span salt, bytes::const_span encryptedSecret, - bytes::const_span password) { + bytes::const_span password, + uint64 serverSecretId) { if (!salt.empty() && !encryptedSecret.empty()) { _secret = DecryptSecureSecret(salt, encryptedSecret, password); if (_secret.empty()) { @@ -361,8 +370,18 @@ void FormController::validateSecureSecret( resetValue(value); } } + } else if (CountSecureSecretId(_secret) != serverSecretId) { + _secret.clear(); + _secretId = 0; + LOG(("API Error: Wrong secure secret id. " + "Forgetting all files and data :(")); + for (auto &[type, value] : _form.values) { + if (!value.data.original.isEmpty()) { + resetValue(value); + } + } } else { - _secretId = CountSecureSecretHash(_secret); + _secretId = serverSecretId; decryptValues(); } } @@ -1327,7 +1346,7 @@ void FormController::generateSecret(bytes::const_span password) { _password.newSecureSalt, randomSaltPart); - auto secureSecretId = CountSecureSecretHash(secret); + auto secureSecretId = CountSecureSecretId(secret); auto encryptedSecret = EncryptSecureSecret( newSecureSaltFull, secret, @@ -1642,9 +1661,27 @@ void FormController::parsePassword(const MTPDaccount_password &result) { } void FormController::cancel() { + if (!_submitSuccess) { + _view->show(Box( + lang(lng_passport_stop_sure), + lang(lng_passport_stop), + [=] { cancelSure(); })); + } else { + cancelSure(); + } +} + +void FormController::cancelSure() { if (!_cancelled) { _cancelled = true; - crl::on_main(this, [=] { + + const auto url = qthelp::url_append_query( + _request.callbackUrl, + _submitSuccess ? "tg_passport=success" : "tg_passport=cancel"); + UrlClickHandler::doOpen(url); + + const auto timeout = _view->closeGetDuration(); + App::CallDelayed(timeout, this, [=] { _controller->clearPassportForm(); }); } diff --git a/Telegram/SourceFiles/passport/passport_form_controller.h b/Telegram/SourceFiles/passport/passport_form_controller.h index cb53ba904..d3cb49812 100644 --- a/Telegram/SourceFiles/passport/passport_form_controller.h +++ b/Telegram/SourceFiles/passport/passport_form_controller.h @@ -287,7 +287,8 @@ private: void validateSecureSecret( bytes::const_span salt, bytes::const_span encryptedSecret, - bytes::const_span password); + bytes::const_span password, + uint64 serverSecretId); void decryptValues(); void decryptValue(Value &value); bool validateValueSecrets(Value &value); @@ -344,6 +345,8 @@ private: const MTPInputSecureValue &data); FinalData prepareFinalData(); + void cancelSure(); + not_null _controller; FormRequest _request; UserData *_bot = nullptr; @@ -369,6 +372,7 @@ private: rpl::event_stream<> _secretReady; rpl::event_stream _passwordError; mtpRequestId _submitRequestId = 0; + bool _submitSuccess = false; rpl::lifetime _uploaderSubscriptions; rpl::lifetime _lifetime; diff --git a/Telegram/SourceFiles/passport/passport_form_view_controller.cpp b/Telegram/SourceFiles/passport/passport_form_view_controller.cpp index 4004ce92c..95df8af0e 100644 --- a/Telegram/SourceFiles/passport/passport_form_view_controller.cpp +++ b/Telegram/SourceFiles/passport/passport_form_view_controller.cpp @@ -103,6 +103,11 @@ QString ComputeScopeRowReadyString(const Scope &scope) { case Scope::Type::Identity: case Scope::Type::Address: { auto list = QStringList(); + const auto pushListValue = [&](const QString &value) { + if (const auto trimmed = value.trimmed(); !trimmed.isEmpty()) { + list.push_back(trimmed); + } + }; const auto &fields = scope.fields->data.parsed.fields; const auto document = [&]() -> const Value* { for (const auto &document : scope.documents) { @@ -113,7 +118,7 @@ QString ComputeScopeRowReadyString(const Scope &scope) { return nullptr; }(); if (document && scope.documents.size() > 1) { - list.push_back([&] { + pushListValue([&] { switch (document->type) { case Value::Type::Passport: return lang(lng_passport_identity_passport); @@ -145,7 +150,7 @@ QString ComputeScopeRowReadyString(const Scope &scope) { } else if (row.validate && !row.validate(i->second)) { return QString(); } - list.push_back(format ? format(i->second) : i->second); + pushListValue(format ? format(i->second) : i->second); } else if (!document) { return QString(); } else { @@ -155,7 +160,7 @@ QString ComputeScopeRowReadyString(const Scope &scope) { } else if (row.validate && !row.validate(i->second)) { return QString(); } - list.push_back(i->second); + pushListValue(i->second); } } return list.join(", "); diff --git a/Telegram/SourceFiles/passport/passport_form_view_controller.h b/Telegram/SourceFiles/passport/passport_form_view_controller.h index 6edff2074..e951c9071 100644 --- a/Telegram/SourceFiles/passport/passport_form_view_controller.h +++ b/Telegram/SourceFiles/passport/passport_form_view_controller.h @@ -48,6 +48,8 @@ public: virtual void showBox(object_ptr box) = 0; virtual void showToast(const QString &text) = 0; + virtual int closeGetDuration() = 0; + virtual ~ViewController() { } diff --git a/Telegram/SourceFiles/passport/passport_panel.cpp b/Telegram/SourceFiles/passport/passport_panel.cpp index 5dc9effe9..5c7599652 100644 --- a/Telegram/SourceFiles/passport/passport_panel.cpp +++ b/Telegram/SourceFiles/passport/passport_panel.cpp @@ -53,7 +53,7 @@ void Panel::initControls() { }, lifetime()); _close->addClickHandler([=] { - hideAndDestroy(); + _controller->cancelAuth(); }); _back->toggledValue( @@ -206,11 +206,13 @@ void Panel::destroyDelayed() { _controller->cancelAuth(); } -void Panel::hideAndDestroy() { +int Panel::hideAndDestroyGetDuration() { toggleOpacityAnimation(false); if (_animationCache.isNull()) { destroyDelayed(); + return 0; } + return st::callPanelDuration; } void Panel::showAskPassword() { diff --git a/Telegram/SourceFiles/passport/passport_panel.h b/Telegram/SourceFiles/passport/passport_panel.h index 6691463af..953b0ece5 100644 --- a/Telegram/SourceFiles/passport/passport_panel.h +++ b/Telegram/SourceFiles/passport/passport_panel.h @@ -33,7 +33,7 @@ public: Panel(not_null controller); void showAndActivate(); - void hideAndDestroy(); + int hideAndDestroyGetDuration(); void showAskPassword(); void showNoPassword(); diff --git a/Telegram/SourceFiles/passport/passport_panel_controller.cpp b/Telegram/SourceFiles/passport/passport_panel_controller.cpp index 8a0033d14..425c282a0 100644 --- a/Telegram/SourceFiles/passport/passport_panel_controller.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_controller.cpp @@ -975,6 +975,13 @@ void PanelController::cancelEditScope() { } } +int PanelController::closeGetDuration() { + if (_panel) { + return _panel->hideAndDestroyGetDuration(); + } + return 0; +} + void PanelController::cancelAuth() { _form->cancel(); } diff --git a/Telegram/SourceFiles/passport/passport_panel_controller.h b/Telegram/SourceFiles/passport/passport_panel_controller.h index b1b87664a..42eeeab97 100644 --- a/Telegram/SourceFiles/passport/passport_panel_controller.h +++ b/Telegram/SourceFiles/passport/passport_panel_controller.h @@ -97,6 +97,8 @@ public: void showBox(object_ptr box) override; void showToast(const QString &text) override; + int closeGetDuration() override; + void cancelAuth(); rpl::lifetime &lifetime();