From e681b0d95ab435368601450db379364a2f385c73 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 11 Mar 2021 20:21:25 +0400 Subject: [PATCH] Support new url-auth auto-logins in links. --- Telegram/SourceFiles/boxes/url_auth_box.cpp | 85 ++++++++++++++++++- Telegram/SourceFiles/boxes/url_auth_box.h | 9 ++ .../SourceFiles/core/click_handler_types.h | 1 + Telegram/SourceFiles/core/ui_integration.cpp | 63 +++++++++++--- 4 files changed, 146 insertions(+), 12 deletions(-) diff --git a/Telegram/SourceFiles/boxes/url_auth_box.cpp b/Telegram/SourceFiles/boxes/url_auth_box.cpp index 8865193fa..0ecb7eddb 100644 --- a/Telegram/SourceFiles/boxes/url_auth_box.cpp +++ b/Telegram/SourceFiles/boxes/url_auth_box.cpp @@ -64,7 +64,9 @@ void UrlAuthBox::Activate( }, [&](const MTPDurlAuthResultDefault &data) { HiddenUrlClickHandler::Open(url); }, [&](const MTPDurlAuthResultRequest &data) { - Request(data, session->data().message(itemId), row, column); + if (const auto item = session->data().message(itemId)) { + Request(data, item, row, column); + } }); }).fail([=](const RPCError &error) { const auto button = HistoryMessageMarkupButton::Get( @@ -79,6 +81,36 @@ void UrlAuthBox::Activate( }).send(); } +void UrlAuthBox::Activate( + not_null session, + const QString &url, + QVariant context) { + context = QVariant::fromValue([&] { + auto result = context.value(); + result.skipBotAutoLogin = true; + return result; + }()); + + using Flag = MTPmessages_RequestUrlAuth::Flag; + session->api().request(MTPmessages_RequestUrlAuth( + MTP_flags(Flag::f_url), + MTPInputPeer(), + MTPint(), // msg_id + MTPint(), // button_id + MTP_string(url) + )).done([=](const MTPUrlAuthResult &result) { + result.match([&](const MTPDurlAuthResultAccepted &data) { + UrlClickHandler::Open(qs(data.vurl()), context); + }, [&](const MTPDurlAuthResultDefault &data) { + HiddenUrlClickHandler::Open(url, context); + }, [&](const MTPDurlAuthResultRequest &data) { + Request(data, session, url, context); + }); + }).fail([=](const RPCError &error) { + HiddenUrlClickHandler::Open(url, context); + }).send(); +} + void UrlAuthBox::Request( const MTPDurlAuthResultRequest &request, not_null message, @@ -144,6 +176,57 @@ void UrlAuthBox::Request( Ui::LayerOption::KeepOther); } +void UrlAuthBox::Request( + const MTPDurlAuthResultRequest &request, + not_null session, + const QString &url, + QVariant context) { + const auto bot = request.is_request_write_access() + ? session->data().processUser(request.vbot()).get() + : nullptr; + const auto box = std::make_shared>(); + const auto finishWithUrl = [=](const QString &url) { + if (*box) { + (*box)->closeBox(); + } + UrlClickHandler::Open(url, context); + }; + const auto callback = [=](Result result) { + if (result == Result::None) { + finishWithUrl(url); + } else { + const auto allowWrite = (result == Result::AuthAndAllowWrite); + using Flag = MTPmessages_AcceptUrlAuth::Flag; + const auto flags = (allowWrite ? Flag::f_write_allowed : Flag(0)) + | Flag::f_url; + session->api().request(MTPmessages_AcceptUrlAuth( + MTP_flags(flags), + MTPInputPeer(), + MTPint(), // msg_id + MTPint(), // button_id + MTP_string(url) + )).done([=](const MTPUrlAuthResult &result) { + const auto to = result.match( + [&](const MTPDurlAuthResultAccepted &data) { + return qs(data.vurl()); + }, [&](const MTPDurlAuthResultDefault &data) { + return url; + }, [&](const MTPDurlAuthResultRequest &data) { + LOG(("API Error: " + "got urlAuthResultRequest after acceptUrlAuth.")); + return url; + }); + finishWithUrl(to); + }).fail([=](const RPCError &error) { + finishWithUrl(url); + }).send(); + } + }; + *box = Ui::show( + Box(session, url, qs(request.vdomain()), bot, callback), + Ui::LayerOption::KeepOther); +} + UrlAuthBox::UrlAuthBox( QWidget*, not_null session, diff --git a/Telegram/SourceFiles/boxes/url_auth_box.h b/Telegram/SourceFiles/boxes/url_auth_box.h index 4ac461326..0c4f3f89d 100644 --- a/Telegram/SourceFiles/boxes/url_auth_box.h +++ b/Telegram/SourceFiles/boxes/url_auth_box.h @@ -22,6 +22,10 @@ public: not_null message, int row, int column); + static void Activate( + not_null session, + const QString &url, + QVariant context); protected: void prepare() override; @@ -32,6 +36,11 @@ private: not_null message, int row, int column); + static void Request( + const MTPDurlAuthResultRequest &request, + not_null session, + const QString &url, + QVariant context); enum class Result { None, diff --git a/Telegram/SourceFiles/core/click_handler_types.h b/Telegram/SourceFiles/core/click_handler_types.h index 5cfee2015..74ff76e51 100644 --- a/Telegram/SourceFiles/core/click_handler_types.h +++ b/Telegram/SourceFiles/core/click_handler_types.h @@ -27,6 +27,7 @@ struct ClickHandlerContext { FullMsgId itemId; Fn elementDelegate; base::weak_ptr sessionWindow; + bool skipBotAutoLogin = false; }; Q_DECLARE_METATYPE(ClickHandlerContext); diff --git a/Telegram/SourceFiles/core/ui_integration.cpp b/Telegram/SourceFiles/core/ui_integration.cpp index a5cad2d3b..fab5b1070 100644 --- a/Telegram/SourceFiles/core/ui_integration.cpp +++ b/Telegram/SourceFiles/core/ui_integration.cpp @@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/emoji_config.h" #include "lang/lang_keys.h" #include "platform/platform_specific.h" +#include "boxes/url_auth_box.h" #include "main/main_account.h" #include "main/main_session.h" #include "main/main_app_config.h" @@ -24,30 +25,65 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Core { namespace { -QString UrlWithAutoLoginToken(const QString &url) { +const auto kGoodPrefix = u"https://"_q; +const auto kBadPrefix = u"http://"_q; + +[[nodiscard]] QUrl UrlForAutoLogin(const QString &url) { + return (url.startsWith(kGoodPrefix, Qt::CaseInsensitive) + || url.startsWith(kBadPrefix, Qt::CaseInsensitive)) + ? QUrl(url) + : QUrl(); +} + +[[nodiscard]] QString DomainForAutoLogin(const QUrl &url) { + return url.isValid() ? url.host().toLower() : QString(); +} + +[[nodiscard]] QString UrlWithAutoLoginToken( + const QString &url, + QUrl parsed, + const QString &domain) { const auto &config = Core::App().activeAccount().appConfig(); const auto token = config.get("autologin_token", {}); const auto domains = config.get>( "autologin_domains", {}); - if (domains.empty() - || token.isEmpty() - || !url.startsWith("https://", Qt::CaseInsensitive)) { - return url; - } - auto parsed = QUrl(url); - if (!parsed.isValid()) { - return url; - } else if (!ranges::contains(domains, parsed.host().toLower())) { + if (token.isEmpty() + || domain.isEmpty() + || !ranges::contains(domains, domain)) { return url; } const auto added = "autologin_token=" + token; parsed.setQuery(parsed.hasQuery() ? (parsed.query() + '&' + added) : added); + if (url.startsWith(kBadPrefix, Qt::CaseInsensitive)) { + parsed.setScheme("https"); + } return QString::fromUtf8(parsed.toEncoded()); } +[[nodiscard]] bool BotAutoLogin( + const QString &url, + const QString &domain, + QVariant context) { + auto &account = Core::App().activeAccount(); + const auto &config = account.appConfig(); + const auto domains = config.get>( + "url_auth_domains", + {}); + if (!account.sessionExists() + || domain.isEmpty() + || !ranges::contains(domains, domain)) { + return false; + } + const auto good = url.startsWith(kBadPrefix, Qt::CaseInsensitive) + ? (kGoodPrefix + url.mid(kBadPrefix.size())) + : url; + UrlAuthBox::Activate(&account.session(), good, context); + return true; +} + } // namespace void UiIntegration::postponeCall(FnMut &&callable) { @@ -179,7 +215,12 @@ bool UiIntegration::handleUrlClick( return true; } - File::OpenUrl(UrlWithAutoLoginToken(url)); + auto parsed = UrlForAutoLogin(url); + const auto domain = DomainForAutoLogin(parsed); + const auto skip = context.value().skipBotAutoLogin; + if (skip || !BotAutoLogin(url, domain, context)) { + File::OpenUrl(UrlWithAutoLoginToken(url, std::move(parsed), domain)); + } return true; }