using Jellyfin.Plugin.Floatplane.Api; using Xunit; namespace Jellyfin.Plugin.Floatplane.Tests; public class ProxySignatureTests { [Fact] public void Create_Verify_roundtrip() { var sig = ProxySignature.Create("hls", "post1", "video1", "1080"); Assert.Equal(64, sig.Length); Assert.True(ProxySignature.Verify(sig, "hls", "post1", "video1", "1080")); Assert.Equal(sig, ProxySignature.Create("hls", "post1", "video1", "1080")); } [Fact] public void Tampered_parts_or_signature_fail() { var sig = ProxySignature.Create("hls", "post1", "video1", "1080"); Assert.False(ProxySignature.Verify(sig, "hls", "post1", "video1", "2160")); Assert.False(ProxySignature.Verify(sig, "mp4", "post1", "video1", "1080")); Assert.False(ProxySignature.Verify(sig[..^1] + (sig[^1] == 'a' ? 'b' : 'a'), "hls", "post1", "video1", "1080")); Assert.False(ProxySignature.Verify(null, "hls", "post1", "video1", "1080")); Assert.False(ProxySignature.Verify(string.Empty, "hls", "post1", "video1", "1080")); } [Theory] [InlineData("https://www.floatplane.com/api/video/watchKey?token=abc")] [InlineData("https://cdn-vod-drm2.floatplane.com/Videos/x/1080.mp4/chunk.m3u8?token=a.b.c&x=y%20z")] [InlineData("å ä ö")] public void EncodeUrl_DecodeUrl_roundtrip(string value) { var encoded = ProxySignature.EncodeUrl(value); Assert.DoesNotContain('+', encoded); Assert.DoesNotContain('/', encoded); Assert.DoesNotContain('=', encoded); Assert.Equal(value, ProxySignature.DecodeUrl(encoded)); } [Fact] public void DecodeUrl_rejects_garbage() { Assert.Null(ProxySignature.DecodeUrl(null)); Assert.Null(ProxySignature.DecodeUrl(string.Empty)); Assert.Null(ProxySignature.DecodeUrl("!!!not base64!!!")); } }