diff --git a/Source/MultiFunPlayer/Common/Extensions.cs b/Source/MultiFunPlayer/Common/Extensions.cs index 24c12495..bd9dacb1 100644 --- a/Source/MultiFunPlayer/Common/Extensions.cs +++ b/Source/MultiFunPlayer/Common/Extensions.cs @@ -412,6 +412,34 @@ public static bool IsLocalhost(this EndPoint endpoint) throw new NotSupportedException($"{endpoint.GetType()} in not supported."); } + public static IPAddress[] GetAddresses(this EndPoint endpoint) + { + try + { + if (endpoint is IPEndPoint ipEndPoint) + return [ipEndPoint.Address]; + if (endpoint is DnsEndPoint dnsEndPoint) + return Dns.GetHostAddresses(dnsEndPoint.Host, dnsEndPoint.AddressFamily); + } + catch { } + + return []; + } + + public static async ValueTask GetAddressesAsync(this EndPoint endpoint) + { + try + { + if (endpoint is IPEndPoint ipEndPoint) + return [ipEndPoint.Address]; + if (endpoint is DnsEndPoint dnsEndPoint) + return await Dns.GetHostAddressesAsync(dnsEndPoint.Host, dnsEndPoint.AddressFamily); + } + catch { } + + return []; + } + public static string ToUriString(this EndPoint endpoint) { if (endpoint is IPEndPoint ipEndPoint) diff --git a/Source/MultiFunPlayer/Common/Utils/NetUtils.cs b/Source/MultiFunPlayer/Common/Utils/NetUtils.cs index db501adb..d142d748 100644 --- a/Source/MultiFunPlayer/Common/Utils/NetUtils.cs +++ b/Source/MultiFunPlayer/Common/Utils/NetUtils.cs @@ -1,5 +1,6 @@ using System.Net; using System.Net.Http; +using System.Net.NetworkInformation; using System.Text.RegularExpressions; namespace MultiFunPlayer.Common; @@ -44,6 +45,25 @@ public static bool TryParseEndpoint(string endpointString, out EndPoint endpoint return endpoint != null; } + public static IEnumerable GetAllLocalAddresses() + => NetworkInterface.GetAllNetworkInterfaces() + .Where(i => i.OperationalStatus == OperationalStatus.Up) + .Select(i => i.GetIPProperties()) + .SelectMany(p => p.UnicastAddresses) + .Select(a => a.Address); + + public static bool IsLocalAddress(EndPoint endpoint) + { + var addresses = GetAllLocalAddresses().ToList(); + return endpoint.GetAddresses().Any(addresses.Contains); + } + + public static async ValueTask IsLocalAddressAsync(EndPoint endpoint) + { + var addresses = GetAllLocalAddresses().ToList(); + return (await endpoint.GetAddressesAsync()).Any(addresses.Contains); + } + [GeneratedRegex(@"^(?:(?InterNetwork|InterNetworkV6|Unspecified)\/)?(?.+):(?\d+)$")] private static partial Regex EndpointRegex(); } diff --git a/Source/MultiFunPlayer/Script/Repository/ViewModels/StashScriptRepository.cs b/Source/MultiFunPlayer/Script/Repository/ViewModels/StashScriptRepository.cs index 356eac4b..a64d3900 100644 --- a/Source/MultiFunPlayer/Script/Repository/ViewModels/StashScriptRepository.cs +++ b/Source/MultiFunPlayer/Script/Repository/ViewModels/StashScriptRepository.cs @@ -26,7 +26,8 @@ public override async ValueTask> SearchF if (ServerBaseUri == null) return []; - if (!TryGetSceneId(mediaResource, out var sceneId)) + var sceneId = await TryGetSceneId(mediaResource); + if (string.IsNullOrWhiteSpace(sceneId)) return []; Logger.Debug("Found Stash scene id [Id: {0}]", sceneId); @@ -52,44 +53,41 @@ public override async ValueTask> SearchF return result; } - private bool TryGetSceneId(MediaResourceInfo mediaResource, out int sceneId) + private async ValueTask TryGetSceneId(MediaResourceInfo mediaResource) { - sceneId = -1; if (mediaResource.IsFile) { var match = Regex.Match(mediaResource.Name, @"^(?\d+) - .+"); if (!match.Success) - return false; + return null; - sceneId = int.Parse(match.Groups["id"].Value); - return true; + return match.Groups["id"].Value; } else if (mediaResource.IsUrl) { var mediaResourceUri = new Uri(mediaResource.Path); if (!string.Equals(mediaResourceUri.Host, ServerBaseUri.Host, StringComparison.OrdinalIgnoreCase)) - return false; + { + if (!NetUtils.TryParseEndpoint(ServerBaseUri.Host, out var serverBaseEndoint) || !serverBaseEndoint.IsLocalhost()) + return null; + if (!NetUtils.TryParseEndpoint(mediaResourceUri.Host, out var mediaResourceEndpoint) || !await NetUtils.IsLocalAddressAsync(mediaResourceEndpoint)) + return null; + } var pathAndQuery = mediaResourceUri.GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped); // /res?scene= var match = Regex.Match(pathAndQuery, @"scene=(?\d+?)(?>$|&)"); if (match.Success) - { - sceneId = int.Parse(match.Groups["id"].Value); - return true; - } + return match.Groups["id"].Value; // /scene//stream match = Regex.Match(pathAndQuery, @"scene\/(?\d+)\/stream"); if (match.Success) - { - sceneId = int.Parse(match.Groups["id"].Value); - return true; - } + return match.Groups["id"].Value; } - return false; + return null; } private bool TryMatchLocal(QueryResponse queryRespone, IEnumerable axes, Dictionary result, ILocalScriptRepository localRepository) diff --git a/Source/MultiFunPlayer/Script/Repository/ViewModels/XBVRScriptRepository.cs b/Source/MultiFunPlayer/Script/Repository/ViewModels/XBVRScriptRepository.cs index c4e25f65..190a43b2 100644 --- a/Source/MultiFunPlayer/Script/Repository/ViewModels/XBVRScriptRepository.cs +++ b/Source/MultiFunPlayer/Script/Repository/ViewModels/XBVRScriptRepository.cs @@ -24,7 +24,8 @@ public override async ValueTask> SearchF if (ServerBaseUri == null) return []; - if (!TryGetSceneId(mediaResource, out var sceneId)) + var sceneId = await TryGetSceneId(mediaResource); + if (string.IsNullOrWhiteSpace(sceneId)) return []; Logger.Debug("Found XBVR scene id [Id: {0}]", sceneId); @@ -41,44 +42,41 @@ public override async ValueTask> SearchF return result; } - private bool TryGetSceneId(MediaResourceInfo mediaResource, out object sceneId) + private async ValueTask TryGetSceneId(MediaResourceInfo mediaResource) { - sceneId = null; if (mediaResource.IsFile) { var match = Regex.Match(mediaResource.Name, @"^(?\d+) - .+"); if (!match.Success) - return false; + return null; - sceneId = match.Groups["id"].Value; - return true; + return match.Groups["id"].Value; } else if (mediaResource.IsUrl) { var mediaResourceUri = new Uri(mediaResource.Path); if (!string.Equals(mediaResourceUri.Host, ServerBaseUri.Host, StringComparison.OrdinalIgnoreCase)) - return false; + { + if (!NetUtils.TryParseEndpoint(ServerBaseUri.Host, out var serverBaseEndoint) || !serverBaseEndoint.IsLocalhost()) + return null; + if (!NetUtils.TryParseEndpoint(mediaResourceUri.Host, out var mediaResourceEndpoint) || !await NetUtils.IsLocalAddressAsync(mediaResourceEndpoint)) + return null; + } var pathAndQuery = mediaResourceUri.GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped); // /res?scene= var match = Regex.Match(pathAndQuery, "scene=(?.+?)(?>$|&)"); if (match.Success) - { - sceneId = match.Groups["id"].Value; - return true; - } + return match.Groups["id"].Value; // /api/dms/file// - match = Regex.Match(pathAndQuery, @"api\/dms\/file\/\d+\/(?<id>\d+) - .+"); if (match.Success) - { - sceneId = match.Groups["id"].Value; - return true; - } + return match.Groups["id"].Value; } - return false; + return null; } private bool TryMatchLocal(SceneMetadata metadata, IEnumerable<DeviceAxis> axes, Dictionary<DeviceAxis, IScriptResource> result, ILocalScriptRepository localRepository)