diff options
20 files changed, 120 insertions, 123 deletions
diff --git a/Jellyfin.Api/Attributes/AcceptsFileAttribute.cs b/Jellyfin.Api/Attributes/AcceptsFileAttribute.cs index 58552d847..fbe68b6b9 100644 --- a/Jellyfin.Api/Attributes/AcceptsFileAttribute.cs +++ b/Jellyfin.Api/Attributes/AcceptsFileAttribute.cs @@ -25,6 +25,6 @@ namespace Jellyfin.Api.Attributes /// Gets the configured content types. /// </summary> /// <returns>the configured content types.</returns> - public string[] GetContentTypes() => _contentTypes; + public string[] ContentTypes => _contentTypes; } } diff --git a/Jellyfin.Api/Attributes/ProducesFileAttribute.cs b/Jellyfin.Api/Attributes/ProducesFileAttribute.cs index 2bf77d729..d8e4141ac 100644 --- a/Jellyfin.Api/Attributes/ProducesFileAttribute.cs +++ b/Jellyfin.Api/Attributes/ProducesFileAttribute.cs @@ -25,6 +25,6 @@ namespace Jellyfin.Api.Attributes /// Gets the configured content types. /// </summary> /// <returns>the configured content types.</returns> - public string[] GetContentTypes() => _contentTypes; + public string[] ContentTypes => _contentTypes; } } diff --git a/Jellyfin.Api/BaseJellyfinApiController.cs b/Jellyfin.Api/BaseJellyfinApiController.cs index 0c63d24b7..e327831fe 100644 --- a/Jellyfin.Api/BaseJellyfinApiController.cs +++ b/Jellyfin.Api/BaseJellyfinApiController.cs @@ -23,24 +23,6 @@ namespace Jellyfin.Api /// <param name="value">The value to return.</param> /// <typeparam name="T">The type to return.</typeparam> /// <returns>The <see cref="ActionResult{T}"/>.</returns> - protected ActionResult<IEnumerable<T>> Ok<T>(List<T> value) - => new OkResult<IEnumerable<T>>(value); - - /// <summary> - /// Create a new <see cref="OkResult{T}"/>. - /// </summary> - /// <param name="value">The value to return.</param> - /// <typeparam name="T">The type to return.</typeparam> - /// <returns>The <see cref="ActionResult{T}"/>.</returns> - protected ActionResult<IEnumerable<T>> Ok<T>(IReadOnlyList<T> value) - => new OkResult<IEnumerable<T>>(value); - - /// <summary> - /// Create a new <see cref="OkResult{T}"/>. - /// </summary> - /// <param name="value">The value to return.</param> - /// <typeparam name="T">The type to return.</typeparam> - /// <returns>The <see cref="ActionResult{T}"/>.</returns> protected ActionResult<IEnumerable<T>> Ok<T>(IEnumerable<T>? value) => new OkResult<IEnumerable<T>?>(value); diff --git a/Jellyfin.Api/Controllers/ApiKeyController.cs b/Jellyfin.Api/Controllers/ApiKeyController.cs index 593846adc..024a15349 100644 --- a/Jellyfin.Api/Controllers/ApiKeyController.cs +++ b/Jellyfin.Api/Controllers/ApiKeyController.cs @@ -36,7 +36,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public async Task<ActionResult<QueryResult<AuthenticationInfo>>> GetKeys() { - var keys = await _authenticationManager.GetApiKeys(); + var keys = await _authenticationManager.GetApiKeys().ConfigureAwait(false); return new QueryResult<AuthenticationInfo>(keys); } diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 49342ad5c..534667c8c 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -106,24 +106,26 @@ namespace Jellyfin.Api.Controllers } var user = _userManager.GetUserById(userId); - await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); - - // Handle image/png; charset=utf-8 - var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); - var userDataPath = Path.Combine(_serverConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username); - if (user.ProfileImage is not null) + var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); + await using (memoryStream.ConfigureAwait(false)) { - await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false); - } + // Handle image/png; charset=utf-8 + var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); + var userDataPath = Path.Combine(_serverConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username); + if (user.ProfileImage is not null) + { + await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false); + } - user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType ?? string.Empty))); + user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType ?? string.Empty))); - await _providerManager - .SaveImage(memoryStream, mimeType, user.ProfileImage.Path) - .ConfigureAwait(false); - await _userManager.UpdateUserAsync(user).ConfigureAwait(false); + await _providerManager + .SaveImage(memoryStream, mimeType, user.ProfileImage.Path) + .ConfigureAwait(false); + await _userManager.UpdateUserAsync(user).ConfigureAwait(false); - return NoContent(); + return NoContent(); + } } /// <summary> @@ -153,24 +155,26 @@ namespace Jellyfin.Api.Controllers } var user = _userManager.GetUserById(userId); - await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); - - // Handle image/png; charset=utf-8 - var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); - var userDataPath = Path.Combine(_serverConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username); - if (user.ProfileImage is not null) + var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); + await using (memoryStream.ConfigureAwait(false)) { - await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false); - } + // Handle image/png; charset=utf-8 + var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); + var userDataPath = Path.Combine(_serverConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username); + if (user.ProfileImage is not null) + { + await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false); + } - user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType ?? string.Empty))); + user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType ?? string.Empty))); - await _providerManager - .SaveImage(memoryStream, mimeType, user.ProfileImage.Path) - .ConfigureAwait(false); - await _userManager.UpdateUserAsync(user).ConfigureAwait(false); + await _providerManager + .SaveImage(memoryStream, mimeType, user.ProfileImage.Path) + .ConfigureAwait(false); + await _userManager.UpdateUserAsync(user).ConfigureAwait(false); - return NoContent(); + return NoContent(); + } } /// <summary> @@ -341,14 +345,16 @@ namespace Jellyfin.Api.Controllers return NotFound(); } - await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); - - // Handle image/png; charset=utf-8 - var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); - await _providerManager.SaveImage(item, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false); - await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); + var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); + await using (memoryStream.ConfigureAwait(false)) + { + // Handle image/png; charset=utf-8 + var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); + await _providerManager.SaveImage(item, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false); + await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); - return NoContent(); + return NoContent(); + } } /// <summary> @@ -377,14 +383,16 @@ namespace Jellyfin.Api.Controllers return NotFound(); } - await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); - - // Handle image/png; charset=utf-8 - var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); - await _providerManager.SaveImage(item, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false); - await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); + var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); + await using (memoryStream.ConfigureAwait(false)) + { + // Handle image/png; charset=utf-8 + var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); + await _providerManager.SaveImage(item, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false); + await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); - return NoContent(); + return NoContent(); + } } /// <summary> @@ -1788,32 +1796,35 @@ namespace Jellyfin.Api.Controllers [AcceptsImageFile] public async Task<ActionResult> UploadCustomSplashscreen() { - await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); + var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); + await using (memoryStream.ConfigureAwait(false)) + { + var mimeType = MediaTypeHeaderValue.Parse(Request.ContentType).MediaType; - var mimeType = MediaTypeHeaderValue.Parse(Request.ContentType).MediaType; + if (!mimeType.HasValue) + { + return BadRequest("Error reading mimetype from uploaded image"); + } - if (!mimeType.HasValue) - { - return BadRequest("Error reading mimetype from uploaded image"); - } + var extension = MimeTypes.ToExtension(mimeType.Value); + if (string.IsNullOrEmpty(extension)) + { + return BadRequest("Error converting mimetype to an image extension"); + } - var extension = MimeTypes.ToExtension(mimeType.Value); - if (string.IsNullOrEmpty(extension)) - { - return BadRequest("Error converting mimetype to an image extension"); - } + var filePath = Path.Combine(_appPaths.DataPath, "splashscreen-upload" + extension); + var brandingOptions = _serverConfigurationManager.GetConfiguration<BrandingOptions>("branding"); + brandingOptions.SplashscreenLocation = filePath; + _serverConfigurationManager.SaveConfiguration("branding", brandingOptions); - var filePath = Path.Combine(_appPaths.DataPath, "splashscreen-upload" + extension); - var brandingOptions = _serverConfigurationManager.GetConfiguration<BrandingOptions>("branding"); - brandingOptions.SplashscreenLocation = filePath; - _serverConfigurationManager.SaveConfiguration("branding", brandingOptions); + var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); + await using (fs.ConfigureAwait(false)) + { + await memoryStream.CopyToAsync(fs, CancellationToken.None).ConfigureAwait(false); + } - await using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) - { - await memoryStream.CopyToAsync(fs, CancellationToken.None).ConfigureAwait(false); + return NoContent(); } - - return NoContent(); } /// <summary> diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs index 94710d78f..5228e0bab 100644 --- a/Jellyfin.Api/Controllers/LiveTvController.cs +++ b/Jellyfin.Api/Controllers/LiveTvController.cs @@ -1011,10 +1011,9 @@ namespace Jellyfin.Api.Controllers { if (!string.IsNullOrEmpty(pw)) { - using var sha = SHA1.Create(); // TODO: remove ToLower when Convert.ToHexString supports lowercase // Schedules Direct requires the hex to be lowercase - listingsProviderInfo.Password = Convert.ToHexString(sha.ComputeHash(Encoding.UTF8.GetBytes(pw))).ToLowerInvariant(); + listingsProviderInfo.Password = Convert.ToHexString(SHA1.HashData(Encoding.UTF8.GetBytes(pw))).ToLowerInvariant(); } return await _liveTvManager.SaveListingProvider(listingsProviderInfo, validateLogin, validateListings).ConfigureAwait(false); diff --git a/Jellyfin.Api/Controllers/PackageController.cs b/Jellyfin.Api/Controllers/PackageController.cs index 0aa7c2ac9..10f967dcd 100644 --- a/Jellyfin.Api/Controllers/PackageController.cs +++ b/Jellyfin.Api/Controllers/PackageController.cs @@ -145,7 +145,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult<IEnumerable<RepositoryInfo>> GetRepositories() { - return _serverConfigurationManager.Configuration.PluginRepositories; + return Ok(_serverConfigurationManager.Configuration.PluginRepositories.AsEnumerable()); } /// <summary> @@ -157,7 +157,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("Repositories")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] - public ActionResult SetRepositories([FromBody, Required] List<RepositoryInfo> repositoryInfos) + public ActionResult SetRepositories([FromBody, Required] RepositoryInfo[] repositoryInfos) { _serverConfigurationManager.Configuration.PluginRepositories = repositoryInfos; _serverConfigurationManager.SaveConfiguration(); diff --git a/Jellyfin.Api/Controllers/PluginsController.cs b/Jellyfin.Api/Controllers/PluginsController.cs index 6a729b237..b8a09990a 100644 --- a/Jellyfin.Api/Controllers/PluginsController.cs +++ b/Jellyfin.Api/Controllers/PluginsController.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Text.Json; @@ -143,7 +144,7 @@ namespace Jellyfin.Api.Controllers public ActionResult UninstallPlugin([FromRoute, Required] Guid pluginId) { // If no version is given, return the current instance. - var plugins = _pluginManager.Plugins.Where(p => p.Id.Equals(pluginId)); + var plugins = _pluginManager.Plugins.Where(p => p.Id.Equals(pluginId)).ToList(); // Select the un-instanced one first. var plugin = plugins.FirstOrDefault(p => p.Instance is null) ?? plugins.OrderBy(p => p.Manifest.Status).FirstOrDefault(); diff --git a/Jellyfin.Api/Controllers/SubtitleController.cs b/Jellyfin.Api/Controllers/SubtitleController.cs index ff9bd095b..c3ce1868e 100644 --- a/Jellyfin.Api/Controllers/SubtitleController.cs +++ b/Jellyfin.Api/Controllers/SubtitleController.cs @@ -236,14 +236,17 @@ namespace Jellyfin.Api.Controllers if (string.Equals(format, "vtt", StringComparison.OrdinalIgnoreCase) && addVttTimeMap) { - await using Stream stream = await EncodeSubtitles(itemId.Value, mediaSourceId, index.Value, format, startPositionTicks, endPositionTicks, copyTimestamps).ConfigureAwait(false); - using var reader = new StreamReader(stream); + Stream stream = await EncodeSubtitles(itemId.Value, mediaSourceId, index.Value, format, startPositionTicks, endPositionTicks, copyTimestamps).ConfigureAwait(false); + await using (stream.ConfigureAwait(false)) + { + using var reader = new StreamReader(stream); - var text = await reader.ReadToEndAsync().ConfigureAwait(false); + var text = await reader.ReadToEndAsync().ConfigureAwait(false); - text = text.Replace("WEBVTT", "WEBVTT\nX-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000", StringComparison.Ordinal); + text = text.Replace("WEBVTT", "WEBVTT\nX-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000", StringComparison.Ordinal); - return File(Encoding.UTF8.GetBytes(text), MimeTypes.GetMimeType("file." + format)); + return File(Encoding.UTF8.GetBytes(text), MimeTypes.GetMimeType("file." + format)); + } } return File( @@ -403,19 +406,22 @@ namespace Jellyfin.Api.Controllers { var video = (Video)_libraryManager.GetItemById(itemId); var data = Convert.FromBase64String(body.Data); - await using var memoryStream = new MemoryStream(data); - await _subtitleManager.UploadSubtitle( - video, - new SubtitleResponse - { - Format = body.Format, - Language = body.Language, - IsForced = body.IsForced, - Stream = memoryStream - }).ConfigureAwait(false); - _providerManager.QueueRefresh(video.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), RefreshPriority.High); + var memoryStream = new MemoryStream(data, 0, data.Length, false, true); + await using (memoryStream.ConfigureAwait(false)) + { + await _subtitleManager.UploadSubtitle( + video, + new SubtitleResponse + { + Format = body.Format, + Language = body.Language, + IsForced = body.IsForced, + Stream = memoryStream + }).ConfigureAwait(false); + _providerManager.QueueRefresh(video.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), RefreshPriority.High); - return NoContent(); + return NoContent(); + } } /// <summary> diff --git a/Jellyfin.Api/Controllers/SyncPlayController.cs b/Jellyfin.Api/Controllers/SyncPlayController.cs index e194fc556..99347246e 100644 --- a/Jellyfin.Api/Controllers/SyncPlayController.cs +++ b/Jellyfin.Api/Controllers/SyncPlayController.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Constants; @@ -107,7 +108,7 @@ namespace Jellyfin.Api.Controllers { var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(false); var syncPlayRequest = new ListGroupsRequest(); - return Ok(_syncPlayManager.ListGroups(currentSession, syncPlayRequest)); + return Ok(_syncPlayManager.ListGroups(currentSession, syncPlayRequest).AsEnumerable()); } /// <summary> diff --git a/Jellyfin.Api/Controllers/SystemController.cs b/Jellyfin.Api/Controllers/SystemController.cs index 411c987f3..2d594293e 100644 --- a/Jellyfin.Api/Controllers/SystemController.cs +++ b/Jellyfin.Api/Controllers/SystemController.cs @@ -216,8 +216,7 @@ namespace Jellyfin.Api.Controllers public ActionResult<IEnumerable<WakeOnLanInfo>> GetWakeOnLanInfo() { var result = _network.GetMacAddresses() - .Select(i => new WakeOnLanInfo(i)) - .ToList(); + .Select(i => new WakeOnLanInfo(i)); return Ok(result); } } diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs index c18fa29af..cd21c5f6f 100644 --- a/Jellyfin.Api/Controllers/UserLibraryController.cs +++ b/Jellyfin.Api/Controllers/UserLibraryController.cs @@ -211,7 +211,7 @@ namespace Jellyfin.Api.Controllers if (item is IHasTrailers hasTrailers) { var trailers = hasTrailers.LocalTrailers; - return Ok(_dtoService.GetBaseItemDtos(trailers, dtoOptions, user, item)); + return Ok(_dtoService.GetBaseItemDtos(trailers, dtoOptions, user, item).AsEnumerable()); } return Ok(item.GetExtras() diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index 889f7dc9a..eca68c6df 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -12,10 +12,6 @@ <NoWarn>AD0001</NoWarn> </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> - <CodeAnalysisTreatWarningsAsErrors>false</CodeAnalysisTreatWarningsAsErrors> - </PropertyGroup> - <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="7.0.1" /> <PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" /> diff --git a/Jellyfin.Api/Models/LiveTvDtos/ChannelMappingOptionsDto.cs b/Jellyfin.Api/Models/LiveTvDtos/ChannelMappingOptionsDto.cs index f43822da7..e293c461c 100644 --- a/Jellyfin.Api/Models/LiveTvDtos/ChannelMappingOptionsDto.cs +++ b/Jellyfin.Api/Models/LiveTvDtos/ChannelMappingOptionsDto.cs @@ -14,14 +14,12 @@ namespace Jellyfin.Api.Models.LiveTvDtos /// <summary> /// Gets or sets list of tuner channels. /// </summary> - [SuppressMessage("Microsoft.Performance", "CA2227:ReadOnlyRemoveSetter", MessageId = "TunerChannels", Justification = "Imported from ServiceStack")] - public List<TunerChannelMapping> TunerChannels { get; set; } = null!; + required public IReadOnlyList<TunerChannelMapping> TunerChannels { get; set; } /// <summary> /// Gets or sets list of provider channels. /// </summary> - [SuppressMessage("Microsoft.Performance", "CA2227:ReadOnlyRemoveSetter", MessageId = "ProviderChannels", Justification = "Imported from ServiceStack")] - public List<NameIdPair> ProviderChannels { get; set; } = null!; + required public IReadOnlyList<NameIdPair> ProviderChannels { get; set; } /// <summary> /// Gets or sets list of mappings. diff --git a/Jellyfin.Server/Filters/FileRequestFilter.cs b/Jellyfin.Server/Filters/FileRequestFilter.cs index 69e10994f..bb5d6a412 100644 --- a/Jellyfin.Server/Filters/FileRequestFilter.cs +++ b/Jellyfin.Server/Filters/FileRequestFilter.cs @@ -15,7 +15,7 @@ namespace Jellyfin.Server.Filters { if (attribute is AcceptsFileAttribute acceptsFileAttribute) { - operation.RequestBody = GetRequestBody(acceptsFileAttribute.GetContentTypes()); + operation.RequestBody = GetRequestBody(acceptsFileAttribute.ContentTypes); break; } } diff --git a/Jellyfin.Server/Filters/FileResponseFilter.cs b/Jellyfin.Server/Filters/FileResponseFilter.cs index 544fdbfd6..1a4559d26 100644 --- a/Jellyfin.Server/Filters/FileResponseFilter.cs +++ b/Jellyfin.Server/Filters/FileResponseFilter.cs @@ -40,7 +40,7 @@ namespace Jellyfin.Server.Filters response.Value.Content.Clear(); // Add all content-types as file. - foreach (var contentType in producesFileAttribute.GetContentTypes()) + foreach (var contentType in producesFileAttribute.ContentTypes) { response.Value.Content.Add(contentType, _openApiMediaType); } diff --git a/Jellyfin.Server/Migrations/Routines/AddDefaultPluginRepository.cs b/Jellyfin.Server/Migrations/Routines/AddDefaultPluginRepository.cs index f6d8c9cc0..9e12c2e6b 100644 --- a/Jellyfin.Server/Migrations/Routines/AddDefaultPluginRepository.cs +++ b/Jellyfin.Server/Migrations/Routines/AddDefaultPluginRepository.cs @@ -38,7 +38,7 @@ namespace Jellyfin.Server.Migrations.Routines /// <inheritdoc/> public void Perform() { - _serverConfigurationManager.Configuration.PluginRepositories.Add(_defaultRepositoryInfo); + _serverConfigurationManager.Configuration.PluginRepositories = new[] { _defaultRepositoryInfo }; _serverConfigurationManager.SaveConfiguration(); } } diff --git a/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs b/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs index 394f14d63..9cfaec46f 100644 --- a/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs +++ b/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs @@ -39,9 +39,9 @@ namespace Jellyfin.Server.Migrations.Routines public void Perform() { // Only add if repository list is empty - if (_serverConfigurationManager.Configuration.PluginRepositories.Count == 0) + if (_serverConfigurationManager.Configuration.PluginRepositories.Length == 0) { - _serverConfigurationManager.Configuration.PluginRepositories.Add(_defaultRepositoryInfo); + _serverConfigurationManager.Configuration.PluginRepositories = new[] { _defaultRepositoryInfo }; _serverConfigurationManager.SaveConfiguration(); } } diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index a07ab7121..d3e042aba 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -194,7 +194,7 @@ namespace MediaBrowser.Model.Configuration public string[] CodecsUsed { get; set; } = Array.Empty<string>(); - public List<RepositoryInfo> PluginRepositories { get; set; } = new List<RepositoryInfo>(); + public RepositoryInfo[] PluginRepositories { get; set; } = Array.Empty<RepositoryInfo>(); public bool EnableExternalContentInSuggestions { get; set; } = true; diff --git a/jellyfin.ruleset b/jellyfin.ruleset index 71385cee2..3fda774b8 100644 --- a/jellyfin.ruleset +++ b/jellyfin.ruleset @@ -138,6 +138,10 @@ <Rule Id="CA2253" Action="Info" /> <!-- disable warning CA5394: Do not use insecure randomness --> <Rule Id="CA5394" Action="Info" /> + <!-- error on CA3003: Review code for file path injection vulnerabilities --> + <Rule Id="CA3003" Action="Info" /> + <!-- error on CA3006: Review code for process command injection vulnerabilities --> + <Rule Id="CA3006" Action="Info" /> <!-- disable warning CA1054: Change the type of parameter url from string to System.Uri --> <Rule Id="CA1054" Action="None" /> |
