Encode/Decode tonsite:// punycode correctly.

This commit is contained in:
John Preston 2024-08-01 16:35:55 +02:00
parent 281ad01b85
commit 2ff0ed50be
5 changed files with 57 additions and 30 deletions

View file

@ -5318,6 +5318,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_iv_join_channel" = "Join"; "lng_iv_join_channel" = "Join";
"lng_iv_window_title" = "Instant View"; "lng_iv_window_title" = "Instant View";
"lng_iv_wrong_layout" = "Wrong layout?"; "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_title" = "Download speed limited";
"lng_limit_download_subscribe" = "Subscribe to {link} and increase download speed {increase}."; "lng_limit_download_subscribe" = "Subscribe to {link} and increase download speed {increase}.";

View file

@ -44,6 +44,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtGui/QWindow> #include <QtGui/QWindow>
#include <charconv> #include <charconv>
#include <ada.h>
namespace Iv { namespace Iv {
namespace { namespace {
@ -137,50 +139,62 @@ namespace {
[[nodiscard]] QString TonsiteToHttps(QString value) { [[nodiscard]] QString TonsiteToHttps(QString value) {
const auto ChangeHost = [](QString tonsite) { 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('-', "-h");
tonsite = tonsite.replace('.', "-d"); tonsite = tonsite.replace('.', "-d");
return tonsite + ".magic.org"; return tonsite + ".magic.org";
}; };
auto parsed = QUrl(value); const auto prefix = u"tonsite://"_q;
if (parsed.isValid()) { if (!value.toLower().startsWith(prefix)) {
parsed.setScheme("https"); return QString();
parsed.setHost(ChangeHost(parsed.host()));
if (parsed.path().isEmpty()) {
parsed.setPath(u"/"_q);
}
return parsed.toString();
} }
const auto part = value.mid(u"tonsite://"_q.size()); const auto part = value.mid(prefix.size());
const auto split = part.indexOf('/'); const auto split = part.indexOf('/');
return "https://" const auto host = ChangeHost((split < 0) ? part : part.left(split));
+ ChangeHost((split < 0) ? part : part.left(split)) if (host.isEmpty()) {
+ ((split < 0) ? u"/"_q : part.mid(split)); return QString();
}
return "https://" + host + ((split < 0) ? u"/"_q : part.mid(split));
} }
[[nodiscard]] QString HttpsToTonsite(QString value) { [[nodiscard]] QString HttpsToTonsite(QString value) {
const auto ChangeHost = [](QString https) { 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("-d", ".");
https = https.replace("-h", "-"); 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); const auto prefix = u"https://"_q;
if (parsed.isValid()) { if (!value.toLower().startsWith(prefix)) {
const auto host = ChangeHost(parsed.host()); return value;
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 part = value.mid(u"https://"_q.size()); const auto part = value.mid(prefix.size());
const auto split = part.indexOf('/'); const auto split = part.indexOf('/');
const auto host = ChangeHost((split < 0) ? part : part.left(split));
if (host.isEmpty()) {
return value;
}
return "tonsite://" return "tonsite://"
+ ChangeHost((split < 0) ? part : part.left(split)) + host
+ ((split < 0) ? u"/"_q : part.mid(split)); + ((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( void Controller::showTonSite(
const Webview::StorageId &storageId, const Webview::StorageId &storageId,
QString uri) { QString uri) {
const auto url = TonsiteToHttps(uri); const auto url = TonsiteToHttps(uri);
Assert(!url.isEmpty());
if (!_webview) { if (!_webview) {
createWebview(storageId); createWebview(storageId);
} }
@ -360,7 +380,7 @@ void Controller::showTonSite(
}) | rpl::map([=](QString value) { }) | rpl::map([=](QString value) {
return HttpsToTonsite(value); return HttpsToTonsite(value);
}); });
_windowTitleText = _subtitleText; _windowTitleText = _subtitleText.value();
_menuToggle->hide(); _menuToggle->hide();
} }

View file

@ -76,6 +76,7 @@ public:
base::flat_map<QByteArray, rpl::producer<bool>> inChannelValues); base::flat_map<QByteArray, rpl::producer<bool>> inChannelValues);
void update(Prepared page); void update(Prepared page);
[[nodiscard]] static bool IsGoodTonSiteUrl(const QString &uri);
void showTonSite(const Webview::StorageId &storageId, QString uri); void showTonSite(const Webview::StorageId &storageId, QString uri);
[[nodiscard]] bool active() const; [[nodiscard]] bool active() const;

View file

@ -42,6 +42,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/boxes/confirm_box.h" #include "ui/boxes/confirm_box.h"
#include "ui/layers/layer_widget.h" #include "ui/layers/layer_widget.h"
#include "ui/text/text_utilities.h" #include "ui/text/text_utilities.h"
#include "ui/toast/toast.h"
#include "ui/basic_click_handlers.h" #include "ui/basic_click_handlers.h"
#include "webview/webview_data_stream_memory.h" #include "webview/webview_data_stream_memory.h"
#include "webview/webview_interface.h" #include "webview/webview_interface.h"
@ -1074,7 +1075,10 @@ void Instance::openWithIvPreferred(
void Instance::showTonSite( void Instance::showTonSite(
const QString &uri, const QString &uri,
QVariant context) { 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. // Otherwise IV is not visible under the media viewer.
Core::App().hideMediaView(); Core::App().hideMediaView();
} }

View file

@ -38,6 +38,7 @@ PUBLIC
tdesktop::td_scheme tdesktop::td_scheme
PRIVATE PRIVATE
desktop-app::lib_webview desktop-app::lib_webview
desktop-app::external_ada
tdesktop::td_lang tdesktop::td_lang
tdesktop::td_ui tdesktop::td_ui
) )