From 90f4187ca9d139bcf328aa885b9ca3bff8689932 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 31 Jul 2018 22:51:06 +0300 Subject: [PATCH] Don't accept tg:// links in passport callbacks. Fixes #5021. --- Telegram/SourceFiles/base/qthelp_url.cpp | 37 +++++++++++++++++++ Telegram/SourceFiles/base/qthelp_url.h | 2 + .../chat_helpers/message_field.cpp | 37 +------------------ .../passport/passport_form_controller.cpp | 9 ++++- 4 files changed, 49 insertions(+), 36 deletions(-) diff --git a/Telegram/SourceFiles/base/qthelp_url.cpp b/Telegram/SourceFiles/base/qthelp_url.cpp index d7a741eaf1..14251a21fa 100644 --- a/Telegram/SourceFiles/base/qthelp_url.cpp +++ b/Telegram/SourceFiles/base/qthelp_url.cpp @@ -8,6 +8,23 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/qthelp_url.h" namespace qthelp { +namespace { + +QRegularExpression RegExpProtocol() { + static const auto result = QRegularExpression("^([a-zA-Z]+)://"); + return result; +} + +bool IsGoodProtocol(const QString &protocol) { + const auto equals = [&](QLatin1String string) { + return protocol.compare(string, Qt::CaseInsensitive) == 0; + }; + return equals(qstr("http")) + || equals(qstr("https")) + || equals(qstr("tg")); +} + +} // namespace QMap url_parse_params( const QString ¶ms, @@ -55,4 +72,24 @@ QString url_append_query_or_hash(const QString &url, const QString &add) { + add; } +QString validate_url(const QString &value) { + const auto trimmed = value.trimmed(); + if (trimmed.isEmpty()) { + return QString(); + } + const auto match = TextUtilities::RegExpDomainExplicit().match(trimmed); + if (!match.hasMatch()) { + const auto domain = TextUtilities::RegExpDomain().match(trimmed); + if (!domain.hasMatch() || domain.capturedStart() != 0) { + return QString(); + } + return qstr("http://") + trimmed; + } else if (match.capturedStart() != 0) { + return QString(); + } + const auto protocolMatch = RegExpProtocol().match(trimmed); + Assert(protocolMatch.hasMatch()); + return IsGoodProtocol(protocolMatch.captured(1)) ? trimmed : QString(); +} + } // namespace qthelp diff --git a/Telegram/SourceFiles/base/qthelp_url.h b/Telegram/SourceFiles/base/qthelp_url.h index 7f8e156cb0..5d3514f0cd 100644 --- a/Telegram/SourceFiles/base/qthelp_url.h +++ b/Telegram/SourceFiles/base/qthelp_url.h @@ -30,4 +30,6 @@ QString url_append_query_or_hash(const QString &url, const QString &add); bool is_ipv6(const QString &ip); +QString validate_url(const QString &value); + } // namespace qthelp diff --git a/Telegram/SourceFiles/chat_helpers/message_field.cpp b/Telegram/SourceFiles/chat_helpers/message_field.cpp index 77fc6908d4..34b715342f 100644 --- a/Telegram/SourceFiles/chat_helpers/message_field.cpp +++ b/Telegram/SourceFiles/chat_helpers/message_field.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_widget.h" #include "base/qthelp_regex.h" +#include "base/qthelp_url.h" #include "boxes/abstract_box.h" #include "ui/wrap/vertical_layout.h" #include "window/window_controller.h" @@ -72,40 +73,6 @@ private: }; -QRegularExpression RegExpProtocol() { - static const auto result = QRegularExpression("^([a-zA-Z]+)://"); - return result; -} - -bool IsGoodProtocol(const QString &protocol) { - const auto equals = [&](QLatin1String string) { - return protocol.compare(string, Qt::CaseInsensitive) == 0; - }; - return equals(qstr("http")) - || equals(qstr("https")) - || equals(qstr("tg")); -} - -QString NormalizeUrl(const QString &value) { - const auto trimmed = value.trimmed(); - if (trimmed.isEmpty()) { - return QString(); - } - const auto match = TextUtilities::RegExpDomainExplicit().match(trimmed); - if (!match.hasMatch()) { - const auto domain = TextUtilities::RegExpDomain().match(trimmed); - if (!domain.hasMatch() || domain.capturedStart() != 0) { - return QString(); - } - return qstr("http://") + trimmed; - } else if (match.capturedStart() != 0) { - return QString(); - } - const auto protocolMatch = RegExpProtocol().match(trimmed); - Assert(protocolMatch.hasMatch()); - return IsGoodProtocol(protocolMatch.captured(1)) ? trimmed : QString(); -} - //bool ValidateUrl(const QString &value) { // const auto match = TextUtilities::RegExpDomain().match(value); // if (!match.hasMatch() || match.capturedStart() != 0) { @@ -156,7 +123,7 @@ void EditLinkBox::prepare() { const auto submit = [=] { const auto linkText = text->getLastText(); - const auto linkUrl = NormalizeUrl(url->getLastText()); + const auto linkUrl = qthelp::validate_url(url->getLastText()); if (linkText.isEmpty()) { text->showError(); return; diff --git a/Telegram/SourceFiles/passport/passport_form_controller.cpp b/Telegram/SourceFiles/passport/passport_form_controller.cpp index d12aab3e81..10ad1762f8 100644 --- a/Telegram/SourceFiles/passport/passport_form_controller.cpp +++ b/Telegram/SourceFiles/passport/passport_form_controller.cpp @@ -188,6 +188,13 @@ QString SpecialScanCredentialsKey(SpecialFile type) { Unexpected("Type in SpecialScanCredentialsKey."); } +QString ValidateUrl(const QString &url) { + const auto result = qthelp::validate_url(url); + return result.startsWith("tg://", Qt::CaseInsensitive) + ? QString() + : result; +} + } // namespace FormRequest::FormRequest( @@ -199,7 +206,7 @@ FormRequest::FormRequest( const QString &errors) : botId(botId) , scope(scope) -, callbackUrl(callbackUrl) +, callbackUrl(ValidateUrl(callbackUrl)) , publicKey(publicKey) , payload(payload) , errors(errors) {