From 2417d4de8302f7682bb5703ead03936c336fd33d Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Sun, 24 Nov 2024 21:46:33 -0500 Subject: [PATCH 1/7] Add `OsuOnlineStore` for proxying external media lookups --- osu.Game/Audio/PreviewTrackManager.cs | 7 ++++--- osu.Game/Online/OsuOnlineStore.cs | 29 +++++++++++++++++++++++++++ osu.Game/OsuGame.cs | 3 +++ osu.Game/OsuGameBase.cs | 2 +- 4 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 osu.Game/Online/OsuOnlineStore.cs diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index 1d710e6395..81564cc2e8 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -6,9 +6,10 @@ using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.IO.Stores; using osu.Framework.Logging; using osu.Game.Beatmaps; +using osu.Game.Online; +using osu.Game.Online.API; namespace osu.Game.Audio { @@ -28,9 +29,9 @@ namespace osu.Game.Audio } [BackgroundDependencyLoader] - private void load(AudioManager audioManager) + private void load(AudioManager audioManager, IAPIProvider api) { - trackStore = audioManager.GetTrackStore(new OnlineStore()); + trackStore = audioManager.GetTrackStore(new OsuOnlineStore(api.APIEndpointUrl)); } /// diff --git a/osu.Game/Online/OsuOnlineStore.cs b/osu.Game/Online/OsuOnlineStore.cs new file mode 100644 index 0000000000..bb69338b01 --- /dev/null +++ b/osu.Game/Online/OsuOnlineStore.cs @@ -0,0 +1,29 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.IO.Stores; + +namespace osu.Game.Online +{ + /// + /// An which proxies external media lookups through osu-web. + /// + public class OsuOnlineStore : OnlineStore + { + private readonly string apiEndpointUrl; + + public OsuOnlineStore(string apiEndpointUrl) + { + this.apiEndpointUrl = apiEndpointUrl; + } + + protected override string GetLookupUrl(string url) + { + if (Uri.TryCreate(url, UriKind.Absolute, out Uri? uri) && uri.Host.EndsWith(@".ppy.sh", StringComparison.OrdinalIgnoreCase)) + return url; + + return $@"{apiEndpointUrl}/beatmapsets/discussions/media-url?url={url}"; + } + } +} diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index dce24c6ee7..1fe41baf2f 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -29,6 +29,7 @@ using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Input.Handlers.Tablet; +using osu.Framework.IO.Stores; using osu.Framework.Localisation; using osu.Framework.Logging; using osu.Framework.Platform; @@ -819,6 +820,8 @@ namespace osu.Game protected override Container CreateScalingContainer() => new ScalingContainer(ScalingMode.Everything); + protected override OnlineStore CreateOnlineStore() => new OsuOnlineStore(CreateEndpoints().APIEndpointUrl); + #region Beatmap progression private void beatmapChanged(ValueChangedEvent beatmap) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index dc13924b4f..d231238699 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -279,7 +279,7 @@ namespace osu.Game dependencies.CacheAs(Storage); var largeStore = new LargeTextureStore(Host.Renderer, Host.CreateTextureLoaderStore(new NamespacedResourceStore(Resources, @"Textures"))); - largeStore.AddTextureSource(Host.CreateTextureLoaderStore(new OnlineStore())); + largeStore.AddTextureSource(Host.CreateTextureLoaderStore(CreateOnlineStore())); dependencies.Cache(largeStore); dependencies.CacheAs(LocalConfig); From 2a7133d6d3dc3bdb5a2cafddde7fc2df834b23e1 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Sun, 24 Nov 2024 21:47:10 -0500 Subject: [PATCH 2/7] Add test scene using `OsuOnlineStore` to test lookups --- .../Visual/Online/TestSceneMediaProxying.cs | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneMediaProxying.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneMediaProxying.cs b/osu.Game.Tests/Visual/Online/TestSceneMediaProxying.cs new file mode 100644 index 0000000000..868bfa6cc4 --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneMediaProxying.cs @@ -0,0 +1,63 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Textures; +using osu.Framework.Platform; +using osu.Game.Graphics.Containers.Markdown; +using osu.Game.Online; + +namespace osu.Game.Tests.Visual.Online +{ + public partial class TestSceneMediaProxying : OsuTestScene + { + [Resolved] + private GameHost host { get; set; } = null!; + + [Test] + public void TestExternalImageLink() + { + AddStep("load image", () => setup(new OsuMarkdownContainer + { + RelativeSizeAxes = Axes.Both, + Text = "![](https://github.com/ppy/osu-wiki/blob/master/wiki/Announcement_messages/img/notification.png?raw=true)", + })); + } + + [Test] + public void TestLocalImageLink() + { + AddStep("load image", () => setup(new OsuMarkdownContainer + { + RelativeSizeAxes = Axes.Both, + Text = "![](https://osu.ppy.sh/help/wiki/shared/news/banners/monthly-beatmapping-contest.png)", + })); + } + + [Test] + public void TestInvalidImageLink() + { + AddStep("load image", () => setup(new OsuMarkdownContainer + { + RelativeSizeAxes = Axes.Both, + Text = "![](https://this-site-does-not-exist.com/img.png)", + })); + } + + private void setup(Drawable drawable) + { + var onlineStore = new OsuOnlineStore(@"https://osu.ppy.sh"); + var textureStore = new TextureStore(host.Renderer, host.CreateTextureLoaderStore(onlineStore)); + + Child = new DependencyProvidingContainer + { + RelativeSizeAxes = Axes.Both, + CachedDependencies = new (Type, object)[] { (typeof(TextureStore), textureStore) }, + Child = drawable, + }; + } + } +} From 9a89d402b9d6e5591a4c67668203ee0d53f27ba3 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Mon, 25 Nov 2024 00:39:32 -0500 Subject: [PATCH 3/7] Perform proxying only on osu! markdown images --- .../Graphics/Containers/Markdown/OsuMarkdownImage.cs | 3 +++ osu.Game/Online/OsuOnlineStore.cs | 11 ++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownImage.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownImage.cs index 10207dd389..a36bbf4f6f 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownImage.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownImage.cs @@ -17,5 +17,8 @@ namespace osu.Game.Graphics.Containers.Markdown { TooltipText = linkInline.Title; } + + protected override ImageContainer CreateImageContainer(string url) + => base.CreateImageContainer($@"https://osu.ppy.sh/beatmapsets/discussions/media-url?url={url}"); } } diff --git a/osu.Game/Online/OsuOnlineStore.cs b/osu.Game/Online/OsuOnlineStore.cs index bb69338b01..dddd453faf 100644 --- a/osu.Game/Online/OsuOnlineStore.cs +++ b/osu.Game/Online/OsuOnlineStore.cs @@ -3,12 +3,10 @@ using System; using osu.Framework.IO.Stores; +using osu.Framework.Logging; namespace osu.Game.Online { - /// - /// An which proxies external media lookups through osu-web. - /// public class OsuOnlineStore : OnlineStore { private readonly string apiEndpointUrl; @@ -20,8 +18,11 @@ namespace osu.Game.Online protected override string GetLookupUrl(string url) { - if (Uri.TryCreate(url, UriKind.Absolute, out Uri? uri) && uri.Host.EndsWith(@".ppy.sh", StringComparison.OrdinalIgnoreCase)) - return url; + if (!Uri.TryCreate(url, UriKind.Absolute, out Uri? uri) || !uri.Host.EndsWith(@".ppy.sh", StringComparison.OrdinalIgnoreCase)) + { + Logger.Log($@"Blocking resource lookup from external website: {url}", LoggingTarget.Network, LogLevel.Important); + return string.Empty; + } return $@"{apiEndpointUrl}/beatmapsets/discussions/media-url?url={url}"; } From 83f8fa7472175d053172459ac64ab9469832733d Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Mon, 25 Nov 2024 00:41:40 -0500 Subject: [PATCH 4/7] Update test scene --- ...aProxying.cs => TestSceneImageProxying.cs} | 27 +++++-------------- 1 file changed, 7 insertions(+), 20 deletions(-) rename osu.Game.Tests/Visual/Online/{TestSceneMediaProxying.cs => TestSceneImageProxying.cs} (59%) diff --git a/osu.Game.Tests/Visual/Online/TestSceneMediaProxying.cs b/osu.Game.Tests/Visual/Online/TestSceneImageProxying.cs similarity index 59% rename from osu.Game.Tests/Visual/Online/TestSceneMediaProxying.cs rename to osu.Game.Tests/Visual/Online/TestSceneImageProxying.cs index 868bfa6cc4..696073c10d 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMediaProxying.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneImageProxying.cs @@ -12,7 +12,7 @@ using osu.Game.Online; namespace osu.Game.Tests.Visual.Online { - public partial class TestSceneMediaProxying : OsuTestScene + public partial class TestSceneImageProxying : OsuTestScene { [Resolved] private GameHost host { get; set; } = null!; @@ -20,44 +20,31 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestExternalImageLink() { - AddStep("load image", () => setup(new OsuMarkdownContainer + AddStep("load image", () => Child = new OsuMarkdownContainer { RelativeSizeAxes = Axes.Both, Text = "![](https://github.com/ppy/osu-wiki/blob/master/wiki/Announcement_messages/img/notification.png?raw=true)", - })); + }); } [Test] public void TestLocalImageLink() { - AddStep("load image", () => setup(new OsuMarkdownContainer + AddStep("load image", () => Child = new OsuMarkdownContainer { RelativeSizeAxes = Axes.Both, Text = "![](https://osu.ppy.sh/help/wiki/shared/news/banners/monthly-beatmapping-contest.png)", - })); + }); } [Test] public void TestInvalidImageLink() { - AddStep("load image", () => setup(new OsuMarkdownContainer + AddStep("load image", () => Child = new OsuMarkdownContainer { RelativeSizeAxes = Axes.Both, Text = "![](https://this-site-does-not-exist.com/img.png)", - })); - } - - private void setup(Drawable drawable) - { - var onlineStore = new OsuOnlineStore(@"https://osu.ppy.sh"); - var textureStore = new TextureStore(host.Renderer, host.CreateTextureLoaderStore(onlineStore)); - - Child = new DependencyProvidingContainer - { - RelativeSizeAxes = Axes.Both, - CachedDependencies = new (Type, object)[] { (typeof(TextureStore), textureStore) }, - Child = drawable, - }; + }); } } } From dbe2741982ed3741ef527d79d7e37eea6ff7766b Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Thu, 28 Nov 2024 22:19:44 -0500 Subject: [PATCH 5/7] Update specified endpoint --- osu.Game/Graphics/Containers/Markdown/OsuMarkdownImage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownImage.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownImage.cs index a36bbf4f6f..ff7df18f00 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownImage.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownImage.cs @@ -19,6 +19,6 @@ namespace osu.Game.Graphics.Containers.Markdown } protected override ImageContainer CreateImageContainer(string url) - => base.CreateImageContainer($@"https://osu.ppy.sh/beatmapsets/discussions/media-url?url={url}"); + => base.CreateImageContainer($@"https://osu.ppy.sh/media-url?url={url}"); } } From 9a4c419c568764fabd2d7624d288966c84986f5c Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Sat, 30 Nov 2024 22:37:05 -0500 Subject: [PATCH 6/7] Remove unnecessary usage of link proxying in `OsuOnlineStore` Links are checked to be in the ppy.sh domain here. --- osu.Game/Online/OsuOnlineStore.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/OsuOnlineStore.cs b/osu.Game/Online/OsuOnlineStore.cs index dddd453faf..c3e81c503f 100644 --- a/osu.Game/Online/OsuOnlineStore.cs +++ b/osu.Game/Online/OsuOnlineStore.cs @@ -18,13 +18,14 @@ namespace osu.Game.Online protected override string GetLookupUrl(string url) { + // add leading dot to avoid matching hosts named "ppy.sh" if (!Uri.TryCreate(url, UriKind.Absolute, out Uri? uri) || !uri.Host.EndsWith(@".ppy.sh", StringComparison.OrdinalIgnoreCase)) { Logger.Log($@"Blocking resource lookup from external website: {url}", LoggingTarget.Network, LogLevel.Important); return string.Empty; } - return $@"{apiEndpointUrl}/beatmapsets/discussions/media-url?url={url}"; + return url; } } } From ee369ef86d54c6f1359742edc438237e01b718e3 Mon Sep 17 00:00:00 2001 From: Salman Alshamrani Date: Sat, 30 Nov 2024 22:38:43 -0500 Subject: [PATCH 7/7] Remove unused using directives --- osu.Game.Tests/Visual/Online/TestSceneImageProxying.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneImageProxying.cs b/osu.Game.Tests/Visual/Online/TestSceneImageProxying.cs index 696073c10d..0cf6fec6f0 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneImageProxying.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneImageProxying.cs @@ -1,14 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Textures; using osu.Framework.Platform; using osu.Game.Graphics.Containers.Markdown; -using osu.Game.Online; namespace osu.Game.Tests.Visual.Online {