mirror of
https://github.com/Readarr/Readarr.git
synced 2026-04-18 21:34:28 -04:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f354b3bc47 | |||
| 2d9e6788e6 | |||
| 0d121fe9c0 | |||
| 892c34fe35 | |||
| 24f6007594 |
@@ -54,7 +54,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
text-wrap: balance;
|
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-size: 50px;
|
font-size: 50px;
|
||||||
line-height: 60px;
|
line-height: 60px;
|
||||||
@@ -128,7 +127,6 @@
|
|||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
text-wrap: balance;
|
|
||||||
font-size: $intermediateFontSize;
|
font-size: $intermediateFontSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<PackageVersion Include="DryIoc.Microsoft.DependencyInjection" Version="6.2.0" />
|
<PackageVersion Include="DryIoc.Microsoft.DependencyInjection" Version="6.2.0" />
|
||||||
<PackageVersion Include="Equ" Version="2.3.0" />
|
<PackageVersion Include="Equ" Version="2.3.0" />
|
||||||
<PackageVersion Include="FluentAssertions" Version="5.10.3" />
|
<PackageVersion Include="FluentAssertions" Version="5.10.3" />
|
||||||
<PackageVersion Include="Polly" Version="8.4.2" />
|
<PackageVersion Include="Polly" Version="8.5.0" />
|
||||||
<PackageVersion Include="Servarr.FluentMigrator.Runner" Version="3.3.2.9" />
|
<PackageVersion Include="Servarr.FluentMigrator.Runner" Version="3.3.2.9" />
|
||||||
<PackageVersion Include="Servarr.FluentMigrator.Runner.SQLite" Version="3.3.2.9" />
|
<PackageVersion Include="Servarr.FluentMigrator.Runner.SQLite" Version="3.3.2.9" />
|
||||||
<PackageVersion Include="Servarr.FluentMigrator.Runner.Postgres" Version="3.3.2.9" />
|
<PackageVersion Include="Servarr.FluentMigrator.Runner.Postgres" Version="3.3.2.9" />
|
||||||
@@ -34,18 +34,18 @@
|
|||||||
<PackageVersion Include="NLog.Extensions.Logging" Version="5.2.3" />
|
<PackageVersion Include="NLog.Extensions.Logging" Version="5.2.3" />
|
||||||
<PackageVersion Include="NLog" Version="5.1.4" />
|
<PackageVersion Include="NLog" Version="5.1.4" />
|
||||||
<PackageVersion Include="NLog.Targets.Syslog" Version="7.0.0" />
|
<PackageVersion Include="NLog.Targets.Syslog" Version="7.0.0" />
|
||||||
<PackageVersion Include="Npgsql" Version="7.0.8" />
|
<PackageVersion Include="Npgsql" Version="7.0.9" />
|
||||||
<PackageVersion Include="NUnit3TestAdapter" Version="4.2.1" />
|
<PackageVersion Include="NUnit3TestAdapter" Version="4.2.1" />
|
||||||
<PackageVersion Include="NUnit" Version="3.14.0" />
|
<PackageVersion Include="NUnit" Version="3.14.0" />
|
||||||
<PackageVersion Include="NunitXml.TestLogger" Version="3.0.117" />
|
<PackageVersion Include="NunitXml.TestLogger" Version="3.0.117" />
|
||||||
<PackageVersion Include="PdfSharpCore" Version="1.3.32" />
|
<PackageVersion Include="PdfSharpCore" Version="1.3.65" />
|
||||||
<PackageVersion Include="RestSharp.Serializers.SystemTextJson" Version="106.15.0" />
|
<PackageVersion Include="RestSharp.Serializers.SystemTextJson" Version="106.15.0" />
|
||||||
<PackageVersion Include="RestSharp" Version="106.15.0" />
|
<PackageVersion Include="RestSharp" Version="106.15.0" />
|
||||||
<PackageVersion Include="Selenium.Support" Version="3.141.0" />
|
<PackageVersion Include="Selenium.Support" Version="3.141.0" />
|
||||||
<PackageVersion Include="Selenium.WebDriver.ChromeDriver" Version="91.0.4472.10100" />
|
<PackageVersion Include="Selenium.WebDriver.ChromeDriver" Version="91.0.4472.10100" />
|
||||||
<PackageVersion Include="Sentry" Version="3.31.0" />
|
<PackageVersion Include="Sentry" Version="3.31.0" />
|
||||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||||
<PackageVersion Include="SixLabors.ImageSharp" Version="3.1.5" />
|
<PackageVersion Include="SixLabors.ImageSharp" Version="3.1.6" />
|
||||||
<PackageVersion Include="StyleCop.Analyzers" Version="1.1.118" />
|
<PackageVersion Include="StyleCop.Analyzers" Version="1.1.118" />
|
||||||
<PackageVersion Include="Swashbuckle.AspNetCore.Annotations" Version="6.6.2" />
|
<PackageVersion Include="Swashbuckle.AspNetCore.Annotations" Version="6.6.2" />
|
||||||
<PackageVersion Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.6.2" />
|
<PackageVersion Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.6.2" />
|
||||||
|
|||||||
@@ -21,9 +21,28 @@ namespace NzbDrone.Common.Test.ExtensionTests
|
|||||||
[TestCase("1.2.3.4")]
|
[TestCase("1.2.3.4")]
|
||||||
[TestCase("172.55.0.1")]
|
[TestCase("172.55.0.1")]
|
||||||
[TestCase("192.55.0.1")]
|
[TestCase("192.55.0.1")]
|
||||||
|
[TestCase("100.64.0.1")]
|
||||||
|
[TestCase("100.127.255.254")]
|
||||||
public void should_return_false_for_public_ip_address(string ipAddress)
|
public void should_return_false_for_public_ip_address(string ipAddress)
|
||||||
{
|
{
|
||||||
IPAddress.Parse(ipAddress).IsLocalAddress().Should().BeFalse();
|
IPAddress.Parse(ipAddress).IsLocalAddress().Should().BeFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestCase("100.64.0.1")]
|
||||||
|
[TestCase("100.127.255.254")]
|
||||||
|
[TestCase("100.100.100.100")]
|
||||||
|
public void should_return_true_for_cgnat_ip_address(string ipAddress)
|
||||||
|
{
|
||||||
|
IPAddress.Parse(ipAddress).IsCgnatIpAddress().Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase("1.2.3.4")]
|
||||||
|
[TestCase("192.168.5.1")]
|
||||||
|
[TestCase("100.63.255.255")]
|
||||||
|
[TestCase("100.128.0.0")]
|
||||||
|
public void should_return_false_for_non_cgnat_ip_address(string ipAddress)
|
||||||
|
{
|
||||||
|
IPAddress.Parse(ipAddress).IsCgnatIpAddress().Should().BeFalse();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,18 +39,24 @@ namespace NzbDrone.Common.Extensions
|
|||||||
private static bool IsLocalIPv4(byte[] ipv4Bytes)
|
private static bool IsLocalIPv4(byte[] ipv4Bytes)
|
||||||
{
|
{
|
||||||
// Link local (no IP assigned by DHCP): 169.254.0.0 to 169.254.255.255 (169.254.0.0/16)
|
// Link local (no IP assigned by DHCP): 169.254.0.0 to 169.254.255.255 (169.254.0.0/16)
|
||||||
bool IsLinkLocal() => ipv4Bytes[0] == 169 && ipv4Bytes[1] == 254;
|
var isLinkLocal = ipv4Bytes[0] == 169 && ipv4Bytes[1] == 254;
|
||||||
|
|
||||||
// Class A private range: 10.0.0.0 – 10.255.255.255 (10.0.0.0/8)
|
// Class A private range: 10.0.0.0 – 10.255.255.255 (10.0.0.0/8)
|
||||||
bool IsClassA() => ipv4Bytes[0] == 10;
|
var isClassA = ipv4Bytes[0] == 10;
|
||||||
|
|
||||||
// Class B private range: 172.16.0.0 – 172.31.255.255 (172.16.0.0/12)
|
// Class B private range: 172.16.0.0 – 172.31.255.255 (172.16.0.0/12)
|
||||||
bool IsClassB() => ipv4Bytes[0] == 172 && ipv4Bytes[1] >= 16 && ipv4Bytes[1] <= 31;
|
var isClassB = ipv4Bytes[0] == 172 && ipv4Bytes[1] >= 16 && ipv4Bytes[1] <= 31;
|
||||||
|
|
||||||
// Class C private range: 192.168.0.0 – 192.168.255.255 (192.168.0.0/16)
|
// Class C private range: 192.168.0.0 – 192.168.255.255 (192.168.0.0/16)
|
||||||
bool IsClassC() => ipv4Bytes[0] == 192 && ipv4Bytes[1] == 168;
|
var isClassC = ipv4Bytes[0] == 192 && ipv4Bytes[1] == 168;
|
||||||
|
|
||||||
return IsLinkLocal() || IsClassA() || IsClassC() || IsClassB();
|
return isLinkLocal || isClassA || isClassC || isClassB;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsCgnatIpAddress(this IPAddress ipAddress)
|
||||||
|
{
|
||||||
|
var bytes = ipAddress.GetAddressBytes();
|
||||||
|
return bytes.Length == 4 && bytes[0] == 100 && bytes[1] >= 64 && bytes[1] <= 127;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,4 +6,5 @@ public class AuthOptions
|
|||||||
public bool? Enabled { get; set; }
|
public bool? Enabled { get; set; }
|
||||||
public string Method { get; set; }
|
public string Method { get; set; }
|
||||||
public string Required { get; set; }
|
public string Required { get; set; }
|
||||||
|
public bool? TrustCgnatIpAddresses { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -478,6 +478,37 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
|
|||||||
downloadClientInfo.RemovesCompletedDownloads.Should().BeTrue();
|
downloadClientInfo.RemovesCompletedDownloads.Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestCase("all", 0)]
|
||||||
|
[TestCase("days-archive", 15)]
|
||||||
|
[TestCase("days-delete", 15)]
|
||||||
|
public void should_set_history_removes_completed_downloads_false_for_separate_properties(string option, int number)
|
||||||
|
{
|
||||||
|
_config.Misc.history_retention_option = option;
|
||||||
|
_config.Misc.history_retention_number = number;
|
||||||
|
|
||||||
|
var downloadClientInfo = Subject.GetStatus();
|
||||||
|
|
||||||
|
downloadClientInfo.RemovesCompletedDownloads.Should().BeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase("number-archive", 10)]
|
||||||
|
[TestCase("number-delete", 10)]
|
||||||
|
[TestCase("number-archive", 0)]
|
||||||
|
[TestCase("number-delete", 0)]
|
||||||
|
[TestCase("days-archive", 3)]
|
||||||
|
[TestCase("days-delete", 3)]
|
||||||
|
[TestCase("all-archive", 0)]
|
||||||
|
[TestCase("all-delete", 0)]
|
||||||
|
public void should_set_history_removes_completed_downloads_true_for_separate_properties(string option, int number)
|
||||||
|
{
|
||||||
|
_config.Misc.history_retention_option = option;
|
||||||
|
_config.Misc.history_retention_number = number;
|
||||||
|
|
||||||
|
var downloadClientInfo = Subject.GetStatus();
|
||||||
|
|
||||||
|
downloadClientInfo.RemovesCompletedDownloads.Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
[TestCase(@"Y:\nzbget\root", @"completed\downloads", @"vv", @"Y:\nzbget\root\completed\downloads", @"Y:\nzbget\root\completed\downloads\vv")]
|
[TestCase(@"Y:\nzbget\root", @"completed\downloads", @"vv", @"Y:\nzbget\root\completed\downloads", @"Y:\nzbget\root\completed\downloads\vv")]
|
||||||
[TestCase(@"Y:\nzbget\root", @"completed", @"vv", @"Y:\nzbget\root\completed", @"Y:\nzbget\root\completed\vv")]
|
[TestCase(@"Y:\nzbget\root", @"completed", @"vv", @"Y:\nzbget\root\completed", @"Y:\nzbget\root\completed\vv")]
|
||||||
[TestCase(@"/nzbget/root", @"completed/downloads", @"vv", @"/nzbget/root/completed/downloads", @"/nzbget/root/completed/downloads/vv")]
|
[TestCase(@"/nzbget/root", @"completed/downloads", @"vv", @"/nzbget/root/completed/downloads", @"/nzbget/root/completed/downloads/vv")]
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ namespace NzbDrone.Core.Configuration
|
|||||||
string SyslogServer { get; }
|
string SyslogServer { get; }
|
||||||
int SyslogPort { get; }
|
int SyslogPort { get; }
|
||||||
string SyslogLevel { get; }
|
string SyslogLevel { get; }
|
||||||
|
string Theme { get; }
|
||||||
string PostgresHost { get; }
|
string PostgresHost { get; }
|
||||||
int PostgresPort { get; }
|
int PostgresPort { get; }
|
||||||
string PostgresUser { get; }
|
string PostgresUser { get; }
|
||||||
@@ -60,7 +61,7 @@ namespace NzbDrone.Core.Configuration
|
|||||||
string PostgresMainDb { get; }
|
string PostgresMainDb { get; }
|
||||||
string PostgresLogDb { get; }
|
string PostgresLogDb { get; }
|
||||||
string PostgresCacheDb { get; }
|
string PostgresCacheDb { get; }
|
||||||
string Theme { get; }
|
bool TrustCgnatIpAddresses { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ConfigFileProvider : IConfigFileProvider
|
public class ConfigFileProvider : IConfigFileProvider
|
||||||
@@ -462,5 +463,7 @@ namespace NzbDrone.Core.Configuration
|
|||||||
{
|
{
|
||||||
SetValue("ApiKey", GenerateApiKey());
|
SetValue("ApiKey", GenerateApiKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool TrustCgnatIpAddresses => _authOptions.TrustCgnatIpAddresses ?? GetValueBoolean("TrustCgnatIpAddresses", false, persist: false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -404,6 +404,12 @@ namespace NzbDrone.Core.Configuration
|
|||||||
|
|
||||||
public string ApplicationUrl => GetValue("ApplicationUrl", string.Empty);
|
public string ApplicationUrl => GetValue("ApplicationUrl", string.Empty);
|
||||||
|
|
||||||
|
public bool TrustCgnatIpAddresses
|
||||||
|
{
|
||||||
|
get { return GetValueBoolean("TrustCgnatIpAddresses", false); }
|
||||||
|
set { SetValue("TrustCgnatIpAddresses", value); }
|
||||||
|
}
|
||||||
|
|
||||||
private string GetValue(string key)
|
private string GetValue(string key)
|
||||||
{
|
{
|
||||||
return GetValue(key, string.Empty);
|
return GetValue(key, string.Empty);
|
||||||
|
|||||||
@@ -263,20 +263,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
|||||||
status.OutputRootFolders = new List<OsPath> { _remotePathMappingService.RemapRemoteToLocal(Settings.Host, category.FullPath) };
|
status.OutputRootFolders = new List<OsPath> { _remotePathMappingService.RemapRemoteToLocal(Settings.Host, category.FullPath) };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.Misc.history_retention.IsNullOrWhiteSpace())
|
status.RemovesCompletedDownloads = RemovesCompletedDownloads(config);
|
||||||
{
|
|
||||||
status.RemovesCompletedDownloads = false;
|
|
||||||
}
|
|
||||||
else if (config.Misc.history_retention.EndsWith("d"))
|
|
||||||
{
|
|
||||||
int.TryParse(config.Misc.history_retention.AsSpan(0, config.Misc.history_retention.Length - 1),
|
|
||||||
out var daysRetention);
|
|
||||||
status.RemovesCompletedDownloads = daysRetention < 14;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
status.RemovesCompletedDownloads = config.Misc.history_retention != "0";
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -518,6 +505,43 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
|||||||
return categories.Contains(category);
|
return categories.Contains(category);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool RemovesCompletedDownloads(SabnzbdConfig config)
|
||||||
|
{
|
||||||
|
var retention = config.Misc.history_retention;
|
||||||
|
var option = config.Misc.history_retention_option;
|
||||||
|
var number = config.Misc.history_retention_number;
|
||||||
|
|
||||||
|
switch (option)
|
||||||
|
{
|
||||||
|
case "all":
|
||||||
|
return false;
|
||||||
|
case "number-archive":
|
||||||
|
case "number-delete":
|
||||||
|
return true;
|
||||||
|
case "days-archive":
|
||||||
|
case "days-delete":
|
||||||
|
return number < 14;
|
||||||
|
case "all-archive":
|
||||||
|
case "all-delete":
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Remove these checks once support for SABnzbd < 4.3 is removed
|
||||||
|
if (retention.IsNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retention.EndsWith("d"))
|
||||||
|
{
|
||||||
|
int.TryParse(config.Misc.history_retention.AsSpan(0, config.Misc.history_retention.Length - 1),
|
||||||
|
out var daysRetention);
|
||||||
|
return daysRetention < 14;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retention != "0";
|
||||||
|
}
|
||||||
|
|
||||||
private bool ValidatePath(DownloadClientItem downloadClientItem)
|
private bool ValidatePath(DownloadClientItem downloadClientItem)
|
||||||
{
|
{
|
||||||
var downloadItemOutputPath = downloadClientItem.OutputPath;
|
var downloadItemOutputPath = downloadClientItem.OutputPath;
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
|||||||
public bool enable_date_sorting { get; set; }
|
public bool enable_date_sorting { get; set; }
|
||||||
public bool pre_check { get; set; }
|
public bool pre_check { get; set; }
|
||||||
public string history_retention { get; set; }
|
public string history_retention { get; set; }
|
||||||
|
public string history_retention_option { get; set; }
|
||||||
|
public int history_retention_number { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SabnzbdCategory
|
public class SabnzbdCategory
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ namespace NzbDrone.Host
|
|||||||
License = new OpenApiLicense
|
License = new OpenApiLicense
|
||||||
{
|
{
|
||||||
Name = "GPL-3.0",
|
Name = "GPL-3.0",
|
||||||
Url = new Uri("https://github.com/Readarr/Readarr/blob/develop/LICENSE")
|
Url = new Uri("https://github.com/Readarr/Readarr/blob/develop/LICENSE.md")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ namespace Readarr.Api.V1.Config
|
|||||||
public string BackupFolder { get; set; }
|
public string BackupFolder { get; set; }
|
||||||
public int BackupInterval { get; set; }
|
public int BackupInterval { get; set; }
|
||||||
public int BackupRetention { get; set; }
|
public int BackupRetention { get; set; }
|
||||||
|
public bool TrustCgnatIpAddresses { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class HostConfigResourceMapper
|
public static class HostConfigResourceMapper
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
"description": "Readarr API docs",
|
"description": "Readarr API docs",
|
||||||
"license": {
|
"license": {
|
||||||
"name": "GPL-3.0",
|
"name": "GPL-3.0",
|
||||||
"url": "https://github.com/Readarr/Readarr/blob/develop/LICENSE"
|
"url": "https://github.com/Readarr/Readarr/blob/develop/LICENSE.md"
|
||||||
},
|
},
|
||||||
"version": "1.0.0"
|
"version": "1.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -27,10 +27,13 @@ namespace NzbDrone.Http.Authentication
|
|||||||
if (_authenticationRequired == AuthenticationRequiredType.DisabledForLocalAddresses)
|
if (_authenticationRequired == AuthenticationRequiredType.DisabledForLocalAddresses)
|
||||||
{
|
{
|
||||||
if (context.Resource is HttpContext httpContext &&
|
if (context.Resource is HttpContext httpContext &&
|
||||||
IPAddress.TryParse(httpContext.GetRemoteIP(), out var ipAddress) &&
|
IPAddress.TryParse(httpContext.GetRemoteIP(), out var ipAddress))
|
||||||
ipAddress.IsLocalAddress())
|
|
||||||
{
|
{
|
||||||
context.Succeed(requirement);
|
if (ipAddress.IsLocalAddress() ||
|
||||||
|
(_configService.TrustCgnatIpAddresses && ipAddress.IsCgnatIpAddress()))
|
||||||
|
{
|
||||||
|
context.Succeed(requirement);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user