From 2ff0ed50be10da0f96d530205d032aedffb57642 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Thu, 1 Aug 2024 16:35:55 +0200 Subject: [PATCH] Encode/Decode tonsite:// punycode correctly. --- Telegram/Resources/langs/lang.strings | 1 + Telegram/SourceFiles/iv/iv_controller.cpp | 78 ++++++++++++++--------- Telegram/SourceFiles/iv/iv_controller.h | 1 + Telegram/SourceFiles/iv/iv_instance.cpp | 6 +- Telegram/cmake/td_iv.cmake | 1 + 5 files changed, 57 insertions(+), 30 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 64bbb68d8..3924a85f6 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -5318,6 +5318,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_iv_join_channel" = "Join"; "lng_iv_window_title" = "Instant View"; "lng_iv_wrong_layout" = "Wrong layout?"; +"lng_iv_not_supported" = "This link appears to be invalid."; "lng_limit_download_title" = "Download speed limited"; "lng_limit_download_subscribe" = "Subscribe to {link} and increase download speed {increase}."; diff --git a/Telegram/SourceFiles/iv/iv_controller.cpp b/Telegram/SourceFiles/iv/iv_controller.cpp index 11df08527..759ef0db3 100644 --- a/Telegram/SourceFiles/iv/iv_controller.cpp +++ b/Telegram/SourceFiles/iv/iv_controller.cpp @@ -44,6 +44,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include <QtGui/QWindow> #include <charconv> +#include <ada.h> + namespace Iv { namespace { @@ -137,50 +139,62 @@ namespace { [[nodiscard]] QString TonsiteToHttps(QString value) { const auto ChangeHost = [](QString tonsite) { + const auto fake = "http://" + tonsite.toStdString(); + const auto parsed = ada::parse<ada::url>(fake); + if (!parsed) { + return QString(); + } + tonsite = QString::fromStdString(parsed->get_hostname()); tonsite = tonsite.replace('-', "-h"); tonsite = tonsite.replace('.', "-d"); return tonsite + ".magic.org"; }; - auto parsed = QUrl(value); - if (parsed.isValid()) { - parsed.setScheme("https"); - parsed.setHost(ChangeHost(parsed.host())); - if (parsed.path().isEmpty()) { - parsed.setPath(u"/"_q); - } - return parsed.toString(); + const auto prefix = u"tonsite://"_q; + if (!value.toLower().startsWith(prefix)) { + return QString(); } - const auto part = value.mid(u"tonsite://"_q.size()); + const auto part = value.mid(prefix.size()); const auto split = part.indexOf('/'); - return "https://" - + ChangeHost((split < 0) ? part : part.left(split)) - + ((split < 0) ? u"/"_q : part.mid(split)); + const auto host = ChangeHost((split < 0) ? part : part.left(split)); + if (host.isEmpty()) { + return QString(); + } + return "https://" + host + ((split < 0) ? u"/"_q : part.mid(split)); } [[nodiscard]] QString HttpsToTonsite(QString value) { const auto ChangeHost = [](QString https) { - https.replace(".magic.org", QString()); + const auto dot = https.indexOf('.'); + if (dot < 0 || https.mid(dot).toLower() != u".magic.org"_q) { + return QString(); + } + https = https.mid(0, dot); https = https.replace("-d", "."); https = https.replace("-h", "-"); - return https; + auto parts = https.split('.'); + for (auto &part : parts) { + if (part.startsWith(u"xn--"_q)) { + const auto utf8 = part.mid(4).toStdString(); + auto out = std::u32string(); + if (ada::idna::punycode_to_utf32(utf8, out)) { + part = QString::fromUcs4(out.data(), out.size()); + } + } + } + return parts.join('.'); }; - auto parsed = QUrl(value); - if (parsed.isValid()) { - const auto host = ChangeHost(parsed.host()); - const auto emptyPath = parsed.path().isEmpty(); - parsed.setScheme("tonsite"); - parsed.setHost(host); - if (emptyPath) { - parsed.setPath(u"/"_q); - } - if (parsed.isValid()) { - return parsed.toString(); - } + const auto prefix = u"https://"_q; + if (!value.toLower().startsWith(prefix)) { + return value; } - const auto part = value.mid(u"https://"_q.size()); + const auto part = value.mid(prefix.size()); const auto split = part.indexOf('/'); + const auto host = ChangeHost((split < 0) ? part : part.left(split)); + if (host.isEmpty()) { + return value; + } return "tonsite://" - + ChangeHost((split < 0) ? part : part.left(split)) + + host + ((split < 0) ? u"/"_q : part.mid(split)); } @@ -342,10 +356,16 @@ void Controller::update(Prepared page) { } } +bool Controller::IsGoodTonSiteUrl(const QString &uri) { + return !TonsiteToHttps(uri).isEmpty(); +} + void Controller::showTonSite( const Webview::StorageId &storageId, QString uri) { const auto url = TonsiteToHttps(uri); + Assert(!url.isEmpty()); + if (!_webview) { createWebview(storageId); } @@ -360,7 +380,7 @@ void Controller::showTonSite( }) | rpl::map([=](QString value) { return HttpsToTonsite(value); }); - _windowTitleText = _subtitleText; + _windowTitleText = _subtitleText.value(); _menuToggle->hide(); } diff --git a/Telegram/SourceFiles/iv/iv_controller.h b/Telegram/SourceFiles/iv/iv_controller.h index 30e975d02..9b5af4e6b 100644 --- a/Telegram/SourceFiles/iv/iv_controller.h +++ b/Telegram/SourceFiles/iv/iv_controller.h @@ -76,6 +76,7 @@ public: base::flat_map<QByteArray, rpl::producer<bool>> inChannelValues); void update(Prepared page); + [[nodiscard]] static bool IsGoodTonSiteUrl(const QString &uri); void showTonSite(const Webview::StorageId &storageId, QString uri); [[nodiscard]] bool active() const; diff --git a/Telegram/SourceFiles/iv/iv_instance.cpp b/Telegram/SourceFiles/iv/iv_instance.cpp index 3b327e5a6..8078828d6 100644 --- a/Telegram/SourceFiles/iv/iv_instance.cpp +++ b/Telegram/SourceFiles/iv/iv_instance.cpp @@ -42,6 +42,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/boxes/confirm_box.h" #include "ui/layers/layer_widget.h" #include "ui/text/text_utilities.h" +#include "ui/toast/toast.h" #include "ui/basic_click_handlers.h" #include "webview/webview_data_stream_memory.h" #include "webview/webview_interface.h" @@ -1074,7 +1075,10 @@ void Instance::openWithIvPreferred( void Instance::showTonSite( const QString &uri, QVariant context) { - if (Platform::IsMac()) { + if (!Controller::IsGoodTonSiteUrl(uri)) { + Ui::Toast::Show(tr::lng_iv_not_supported(tr::now)); + return; + } else if (Platform::IsMac()) { // Otherwise IV is not visible under the media viewer. Core::App().hideMediaView(); } diff --git a/Telegram/cmake/td_iv.cmake b/Telegram/cmake/td_iv.cmake index 602abf41c..1d4edf9f5 100644 --- a/Telegram/cmake/td_iv.cmake +++ b/Telegram/cmake/td_iv.cmake @@ -38,6 +38,7 @@ PUBLIC tdesktop::td_scheme PRIVATE desktop-app::lib_webview + desktop-app::external_ada tdesktop::td_lang tdesktop::td_ui )