mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-08-13 06:53:30 +00:00
Support same_origin in webapps.
This commit is contained in:
@@ -79,6 +79,7 @@ enum class NativeMessageSource {
|
||||
|
||||
struct NativeMessage {
|
||||
NativeMessageSource source = NativeMessageSource::LegacyWebApp;
|
||||
QString origin;
|
||||
QString command;
|
||||
QJsonObject arguments;
|
||||
};
|
||||
@@ -115,6 +116,48 @@ struct NativeMessage {
|
||||
&& url.fragment().isEmpty();
|
||||
}
|
||||
|
||||
[[nodiscard]] int EffectivePort(const QUrl &url) {
|
||||
const auto explicitPort = url.port(-1);
|
||||
if (explicitPort >= 0) {
|
||||
return explicitPort;
|
||||
}
|
||||
const auto scheme = url.scheme().toLower();
|
||||
if (scheme == u"http"_q) {
|
||||
return 80;
|
||||
} else if (scheme == u"https"_q) {
|
||||
return 443;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
[[nodiscard]] QString OriginFromUrl(const QString &url) {
|
||||
const auto parsed = QUrl(url);
|
||||
if (!parsed.isValid()) {
|
||||
return {};
|
||||
}
|
||||
const auto scheme = parsed.scheme().toLower();
|
||||
auto host = parsed.host().toLower();
|
||||
const auto port = EffectivePort(parsed);
|
||||
if (scheme.isEmpty() || host.isEmpty() || port < 0) {
|
||||
return {};
|
||||
}
|
||||
if (host.contains(':') && !host.startsWith('[')) {
|
||||
host = u"["_q + host + u"]"_q;
|
||||
}
|
||||
return u"%1://%2:%3"_q.arg(scheme, host, QString::number(port));
|
||||
}
|
||||
|
||||
[[nodiscard]] bool OriginsMatch(const QString &a, const QString &b) {
|
||||
if (a.isEmpty() || b.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
const auto normalizedA = OriginFromUrl(a);
|
||||
const auto normalizedB = OriginFromUrl(b);
|
||||
return !normalizedA.isEmpty()
|
||||
&& !normalizedB.isEmpty()
|
||||
&& normalizedA == normalizedB;
|
||||
}
|
||||
|
||||
[[nodiscard]] RectPart ParsePosition(const QString &position) {
|
||||
if (position == u"left"_q) {
|
||||
return RectPart::Left;
|
||||
@@ -203,6 +246,7 @@ void LogNativeMessageRejected(
|
||||
|
||||
[[nodiscard]] std::optional<NativeMessage> ParseNativeMessage(
|
||||
const QByteArray &bytes,
|
||||
const QString &sourceUrl,
|
||||
bool externalShell,
|
||||
const QString &shellToken) {
|
||||
const auto byteCount = quint64(bytes.size());
|
||||
@@ -248,8 +292,8 @@ void LogNativeMessageRejected(
|
||||
|| token.toString() != shellToken) {
|
||||
return reject(u"bad external token"_q);
|
||||
}
|
||||
const auto origin = object.value(u"origin"_q);
|
||||
if (source == NativeMessageSource::ExternalShell) {
|
||||
const auto origin = object.value(u"origin"_q);
|
||||
if (!origin.isString()
|
||||
|| !IsExternalShellOrigin(origin.toString())) {
|
||||
return reject(u"bad shell origin"_q);
|
||||
@@ -273,6 +317,9 @@ void LogNativeMessageRejected(
|
||||
}
|
||||
return NativeMessage{
|
||||
.source = source,
|
||||
.origin = (source == NativeMessageSource::ExternalWebApp)
|
||||
? origin.toString()
|
||||
: QString(),
|
||||
.command = command,
|
||||
.arguments = arguments,
|
||||
};
|
||||
@@ -306,6 +353,7 @@ void LogNativeMessageRejected(
|
||||
}
|
||||
return NativeMessage{
|
||||
.source = NativeMessageSource::LegacyWebApp,
|
||||
.origin = OriginFromUrl(sourceUrl),
|
||||
.command = command,
|
||||
.arguments = arguments,
|
||||
};
|
||||
@@ -1137,7 +1185,8 @@ Panel::Panel(Args &&args)
|
||||
? std::make_unique<StandaloneLayerStack>()
|
||||
: nullptr)
|
||||
, _fullscreen(args.fullscreen)
|
||||
, _allowClipboardRead(args.allowClipboardRead) {
|
||||
, _allowClipboardRead(args.allowClipboardRead)
|
||||
, _sameOrigin(args.sameOrigin) {
|
||||
if (_externalShell) {
|
||||
_widget->setAttribute(Qt::WA_DontShowOnScreen);
|
||||
_externalLayer->boxAdded(
|
||||
@@ -1501,6 +1550,9 @@ void Panel::hideWebviewProgress() {
|
||||
bool Panel::showWebview(Args &&args, const Webview::ThemeParams ¶ms) {
|
||||
_bottomText = std::move(args.bottom);
|
||||
_externalUrl = args.url;
|
||||
_sameOrigin = args.sameOrigin;
|
||||
_initialOrigin = OriginFromUrl(args.url);
|
||||
_currentOrigin = _initialOrigin;
|
||||
if (_externalShell && !_webview) {
|
||||
resetExternalShellIdentity();
|
||||
}
|
||||
@@ -1661,6 +1713,8 @@ void Panel::sendExternalShellBootstrap() {
|
||||
const auto params = _delegate->botThemeParams();
|
||||
sendExternalShellMethod("bootstrap", {
|
||||
{ u"url"_q, _externalUrl },
|
||||
{ u"sameOrigin"_q, _sameOrigin },
|
||||
{ u"initialOrigin"_q, _initialOrigin },
|
||||
{ u"title"_q, _externalTitle },
|
||||
{ u"metrics"_q, LinuxShell::Metrics() },
|
||||
{ u"colors"_q, LinuxShell::ColorPayload(externalShellColors(params)) },
|
||||
@@ -2189,23 +2243,33 @@ bool Panel::createWebview(const Webview::ThemeParams ¶ms) {
|
||||
}, _webview->lifetime);
|
||||
}
|
||||
|
||||
raw->setMessageHandler([=](std::string text) {
|
||||
if (text.size() > size_t(kMaxNativeMessageBytes)) {
|
||||
raw->setMessageHandler([=](Webview::Message message) {
|
||||
if (message.text.size() > size_t(kMaxNativeMessageBytes)) {
|
||||
LogNativeMessageRejected(
|
||||
u"payload too large"_q,
|
||||
quint64(text.size()));
|
||||
quint64(message.text.size()));
|
||||
return;
|
||||
}
|
||||
const auto bytes = QByteArray::fromRawData(
|
||||
text.data(),
|
||||
int(text.size()));
|
||||
message.text.data(),
|
||||
int(message.text.size()));
|
||||
const auto parsed = ParseNativeMessage(
|
||||
bytes,
|
||||
QString::fromStdString(message.sourceUrl),
|
||||
_externalShell,
|
||||
_externalShellToken);
|
||||
if (!parsed) {
|
||||
return;
|
||||
}
|
||||
if (_sameOrigin
|
||||
&& parsed->source != NativeMessageSource::ExternalShell
|
||||
&& !OriginsMatch(parsed->origin, _initialOrigin)) {
|
||||
LogNativeMessageRejected(
|
||||
u"bad webapp origin"_q,
|
||||
quint64(message.text.size()),
|
||||
parsed->command);
|
||||
return;
|
||||
}
|
||||
const auto &command = parsed->command;
|
||||
const auto &arguments = parsed->arguments;
|
||||
if (parsed->source == NativeMessageSource::ExternalShell) {
|
||||
@@ -2372,6 +2436,7 @@ bool Panel::createWebview(const Webview::ThemeParams ¶ms) {
|
||||
} else if (newWindow) {
|
||||
return true;
|
||||
}
|
||||
_currentOrigin = OriginFromUrl(uri);
|
||||
showWebviewProgress();
|
||||
return true;
|
||||
});
|
||||
@@ -3644,6 +3709,9 @@ void Panel::postEvent(const QString &event, EventData data) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (_sameOrigin && !OriginsMatch(_currentOrigin, _initialOrigin)) {
|
||||
return;
|
||||
}
|
||||
auto written = v::is<QString>(data)
|
||||
? v::get<QString>(data).toUtf8()
|
||||
: QJsonDocument(
|
||||
|
||||
Reference in New Issue
Block a user