diff options
5 files changed, 98 insertions, 86 deletions
diff --git a/Jellyfin.Server.Implementations/Properties/AssemblyInfo.cs b/Jellyfin.Server.Implementations/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..6528d4fdc --- /dev/null +++ b/Jellyfin.Server.Implementations/Properties/AssemblyInfo.cs @@ -0,0 +1,23 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Jellyfin.Server.Implementations")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Jellyfin Project")] +[assembly: AssemblyProduct("Jellyfin Server")] +[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] +[assembly: InternalsVisibleTo("Jellyfin.Server.Implementations.Tests")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index a3a9e90d4..76d1389ca 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -137,10 +137,7 @@ namespace Jellyfin.Server.Implementations.Users throw new ArgumentNullException(nameof(user)); } - if (string.IsNullOrWhiteSpace(newName)) - { - throw new ArgumentException("Invalid username", nameof(newName)); - } + ThrowIfInvalidUsername(newName); if (user.Username.Equals(newName, StringComparison.Ordinal)) { @@ -201,10 +198,7 @@ namespace Jellyfin.Server.Implementations.Users /// <inheritdoc/> public async Task<User> CreateUserAsync(string name) { - if (!IsValidUsername(name)) - { - throw new ArgumentException("Usernames can contain unicode symbols, numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"); - } + ThrowIfInvalidUsername(name); if (Users.Any(u => u.Username.Equals(name, StringComparison.OrdinalIgnoreCase))) { @@ -733,12 +727,22 @@ namespace Jellyfin.Server.Implementations.Users _users[user.Id] = user; } + internal static void ThrowIfInvalidUsername(string name) + { + if (!string.IsNullOrWhiteSpace(name) && IsValidUsername(name)) + { + return; + } + + throw new ArgumentException("Usernames can contain unicode symbols, numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)", nameof(name)); + } + private static bool IsValidUsername(string name) { // This is some regex that matches only on unicode "word" characters, as well as -, _ and @ // In theory this will cut out most if not all 'control' characters which should help minimize any weirdness // Usernames can contain letters (a-z + whatever else unicode is cool with), numbers (0-9), at-signs (@), dashes (-), underscores (_), apostrophes ('), periods (.) and spaces ( ) - return Regex.IsMatch(name, @"^[\w\ \-'._@]*$"); + return Regex.IsMatch(name, @"^[\w\ \-'._@]+$"); } private IAuthenticationProvider GetAuthenticationProvider(User user) diff --git a/tests/Jellyfin.Naming.Tests/Video/VideoListResolverTests.cs b/tests/Jellyfin.Naming.Tests/Video/VideoListResolverTests.cs index 215c7e540..08af76669 100644 --- a/tests/Jellyfin.Naming.Tests/Video/VideoListResolverTests.cs +++ b/tests/Jellyfin.Naming.Tests/Video/VideoListResolverTests.cs @@ -1,3 +1,4 @@ +using System; using System.Linq; using Emby.Naming.Common; using Emby.Naming.Video; @@ -8,11 +9,10 @@ namespace Jellyfin.Naming.Tests.Video { public class VideoListResolverTests { - private readonly NamingOptions _namingOptions = new NamingOptions(); + private readonly VideoListResolver _videoListResolver = new VideoListResolver(new NamingOptions()); - // FIXME - // [Fact] - private void TestStackAndExtras() + [Fact] + public void TestStackAndExtras() { // No stacking here because there is no part/disc/etc var files = new[] @@ -40,23 +40,22 @@ namespace Jellyfin.Naming.Tests.Video "WillyWonka-trailer.mkv" }; - var resolver = GetResolver(); - - var result = resolver.Resolve(files.Select(i => new FileSystemMetadata + var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata { IsDirectory = false, FullName = i }).ToList()).ToList(); Assert.Equal(5, result.Count); - - Assert.Equal(3, result[1].Files.Count); - Assert.Equal(3, result[1].Extras.Count); - Assert.Equal("Batman", result[1].Name); - - Assert.Equal(4, result[2].Files.Count); - Assert.Equal(2, result[2].Extras.Count); - Assert.Equal("Harry Potter and the Deathly Hallows", result[2].Name); + var batman = result.FirstOrDefault(x => string.Equals(x.Name, "Batman", StringComparison.Ordinal)); + Assert.NotNull(batman); + Assert.Equal(3, batman!.Files.Count); + Assert.Equal(3, batman!.Extras.Count); + + var harry = result.FirstOrDefault(x => string.Equals(x.Name, "Harry Potter and the Deathly Hallows", StringComparison.Ordinal)); + Assert.NotNull(harry); + Assert.Equal(4, harry!.Files.Count); + Assert.Equal(2, harry!.Extras.Count); } [Fact] @@ -68,9 +67,7 @@ namespace Jellyfin.Naming.Tests.Video "300.nfo" }; - var resolver = GetResolver(); - - var result = resolver.Resolve(files.Select(i => new FileSystemMetadata + var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata { IsDirectory = false, FullName = i @@ -88,9 +85,7 @@ namespace Jellyfin.Naming.Tests.Video "300 trailer.mkv" }; - var resolver = GetResolver(); - - var result = resolver.Resolve(files.Select(i => new FileSystemMetadata + var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata { IsDirectory = false, FullName = i @@ -108,9 +103,7 @@ namespace Jellyfin.Naming.Tests.Video "X-Men Days of Future Past-trailer.mp4" }; - var resolver = GetResolver(); - - var result = resolver.Resolve(files.Select(i => new FileSystemMetadata + var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata { IsDirectory = false, FullName = i @@ -129,9 +122,7 @@ namespace Jellyfin.Naming.Tests.Video "X-Men Days of Future Past-trailer2.mp4" }; - var resolver = GetResolver(); - - var result = resolver.Resolve(files.Select(i => new FileSystemMetadata + var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata { IsDirectory = false, FullName = i @@ -149,9 +140,7 @@ namespace Jellyfin.Naming.Tests.Video "Looper.2012.bluray.720p.x264.mkv" }; - var resolver = GetResolver(); - - var result = resolver.Resolve(files.Select(i => new FileSystemMetadata + var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata { IsDirectory = false, FullName = i @@ -173,9 +162,7 @@ namespace Jellyfin.Naming.Tests.Video "My video 5.mkv" }; - var resolver = GetResolver(); - - var result = resolver.Resolve(files.Select(i => new FileSystemMetadata + var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata { IsDirectory = false, FullName = i @@ -193,9 +180,7 @@ namespace Jellyfin.Naming.Tests.Video @"M:/Movies (DVD)/Movies (Musical)/Sound of Music (1965)/Sound of Music Disc 2" }; - var resolver = GetResolver(); - - var result = resolver.Resolve(files.Select(i => new FileSystemMetadata + var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata { IsDirectory = true, FullName = i @@ -214,9 +199,7 @@ namespace Jellyfin.Naming.Tests.Video @"My movie #2.mp4" }; - var resolver = GetResolver(); - - var result = resolver.Resolve(files.Select(i => new FileSystemMetadata + var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata { IsDirectory = true, FullName = i @@ -235,9 +218,7 @@ namespace Jellyfin.Naming.Tests.Video @"No (2012) part1-trailer.mp4" }; - var resolver = GetResolver(); - - var result = resolver.Resolve(files.Select(i => new FileSystemMetadata + var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata { IsDirectory = false, FullName = i @@ -256,9 +237,7 @@ namespace Jellyfin.Naming.Tests.Video @"No (2012)-trailer.mp4" }; - var resolver = GetResolver(); - - var result = resolver.Resolve(files.Select(i => new FileSystemMetadata + var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata { IsDirectory = false, FullName = i @@ -278,9 +257,7 @@ namespace Jellyfin.Naming.Tests.Video @"trailer.mp4" }; - var resolver = GetResolver(); - - var result = resolver.Resolve(files.Select(i => new FileSystemMetadata + var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata { IsDirectory = false, FullName = i @@ -300,9 +277,7 @@ namespace Jellyfin.Naming.Tests.Video @"/MCFAMILY-PC/Private3$/Heterosexual/Breast In Class 2 Counterfeit Racks (2011)/Breast In Class 2 Disc 2 cd2.avi" }; - var resolver = GetResolver(); - - var result = resolver.Resolve(files.Select(i => new FileSystemMetadata + var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata { IsDirectory = false, FullName = i @@ -319,9 +294,7 @@ namespace Jellyfin.Naming.Tests.Video @"/nas-markrobbo78/Videos/INDEX HTPC/Movies/Watched/3 - ACTION/Argo (2012)/movie.mkv" }; - var resolver = GetResolver(); - - var result = resolver.Resolve(files.Select(i => new FileSystemMetadata + var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata { IsDirectory = false, FullName = i @@ -338,9 +311,7 @@ namespace Jellyfin.Naming.Tests.Video @"The Colony.mkv" }; - var resolver = GetResolver(); - - var result = resolver.Resolve(files.Select(i => new FileSystemMetadata + var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata { IsDirectory = false, FullName = i @@ -358,9 +329,7 @@ namespace Jellyfin.Naming.Tests.Video @"Four Sisters and a Wedding - B.avi" }; - var resolver = GetResolver(); - - var result = resolver.Resolve(files.Select(i => new FileSystemMetadata + var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata { IsDirectory = false, FullName = i @@ -378,9 +347,7 @@ namespace Jellyfin.Naming.Tests.Video @"Four Rooms - A.mp4" }; - var resolver = GetResolver(); - - var result = resolver.Resolve(files.Select(i => new FileSystemMetadata + var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata { IsDirectory = false, FullName = i @@ -398,9 +365,7 @@ namespace Jellyfin.Naming.Tests.Video @"/Server/Despicable Me/movie-trailer.mkv" }; - var resolver = GetResolver(); - - var result = resolver.Resolve(files.Select(i => new FileSystemMetadata + var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata { IsDirectory = false, FullName = i @@ -420,9 +385,7 @@ namespace Jellyfin.Naming.Tests.Video @"/Server/Despicable Me/Baywatch (2017) - Trailer.mkv" }; - var resolver = GetResolver(); - - var result = resolver.Resolve(files.Select(i => new FileSystemMetadata + var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata { IsDirectory = false, FullName = i @@ -440,9 +403,7 @@ namespace Jellyfin.Naming.Tests.Video @"/Movies/Despicable Me/trailers/trailer.mkv" }; - var resolver = GetResolver(); - - var result = resolver.Resolve(files.Select(i => new FileSystemMetadata + var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata { IsDirectory = false, FullName = i @@ -457,10 +418,5 @@ namespace Jellyfin.Naming.Tests.Video var stack = new FileStack(); Assert.False(stack.ContainsFile("XX", true)); } - - private VideoListResolver GetResolver() - { - return new VideoListResolver(_namingOptions); - } } } diff --git a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj index 174f29b09..c3b3155fe 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj +++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj @@ -39,6 +39,7 @@ <ItemGroup> <ProjectReference Include="..\..\Emby.Server.Implementations\Emby.Server.Implementations.csproj" /> + <ProjectReference Include="..\..\Jellyfin.Server.Implementations\Jellyfin.Server.Implementations.csproj" /> </ItemGroup> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> diff --git a/tests/Jellyfin.Server.Implementations.Tests/Users/UserManagerTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Users/UserManagerTests.cs new file mode 100644 index 000000000..867dda29d --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Users/UserManagerTests.cs @@ -0,0 +1,28 @@ +using System; +using Jellyfin.Server.Implementations.Users; +using Xunit; + +namespace Jellyfin.Server.Implementations.Tests.Users +{ + public class UserManagerTests + { + [Theory] + [InlineData("this_is_valid")] + [InlineData("this is also valid")] + [InlineData("0@_-' .")] + public void ThrowIfInvalidUsername_WhenValidUsername_DoesNotThrowArgumentException(string username) + { + var ex = Record.Exception(() => UserManager.ThrowIfInvalidUsername(username)); + Assert.Null(ex); + } + + [Theory] + [InlineData(" ")] + [InlineData("")] + [InlineData("special characters like & $ ? are not allowed")] + public void ThrowIfInvalidUsername_WhenInvalidUsername_ThrowsArgumentException(string username) + { + Assert.Throws<ArgumentException>(() => UserManager.ThrowIfInvalidUsername(username)); + } + } +} |
