From 0d53f7e5fc1924557425b7d8449863d35f96e495 Mon Sep 17 00:00:00 2001
From: ze0s <43699394+zze0s@users.noreply.github.com>
Date: Wed, 28 Aug 2024 12:21:56 +0200
Subject: [PATCH] feat(download-clients): rtorrent support Digest Auth (#1596)
* feat(download-clients): rtorrent support basic auth
* feat(download-client): implement new auth logic
* fix(download-client): tests store
* chore(deps): update go-rtorrent to v1.11.0
---
go.mod | 3 +-
go.sum | 6 ++
internal/database/download_client.go | 2 +
internal/database/download_client_test.go | 6 ++
internal/domain/client.go | 65 ++++++++++++-
internal/download_client/cache.go | 3 +
internal/download_client/connection.go | 94 ++++++++++++-------
internal/download_client/service.go | 83 ++++++++++------
web/src/components/tooltips/Tooltip.tsx | 2 +-
web/src/domain/constants.ts | 15 +++
.../forms/settings/DownloadClientForms.tsx | 23 ++++-
11 files changed, 231 insertions(+), 71 deletions(-)
diff --git a/go.mod b/go.mod
index ab1b548..ce348e2 100644
--- a/go.mod
+++ b/go.mod
@@ -11,7 +11,7 @@ require (
github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef
github.com/autobrr/go-deluge v1.2.0
github.com/autobrr/go-qbittorrent v1.9.0
- github.com/autobrr/go-rtorrent v1.10.0
+ github.com/autobrr/go-rtorrent v1.11.0
github.com/avast/retry-go v3.0.0+incompatible
github.com/avast/retry-go/v4 v4.6.0
github.com/containrrr/shoutrrr v0.8.0
@@ -72,6 +72,7 @@ require (
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hekmon/cunits/v2 v2.1.0 // indirect
github.com/huandu/xstrings v1.4.0 // indirect
+ github.com/icholy/digest v0.1.23 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
diff --git a/go.sum b/go.sum
index 853a75c..e4f45ec 100644
--- a/go.sum
+++ b/go.sum
@@ -64,6 +64,10 @@ github.com/autobrr/go-qbittorrent v1.9.0 h1:HaLueJ99D3G1cQ2r5ADVbtfwyEhekt2eQoEZ
github.com/autobrr/go-qbittorrent v1.9.0/go.mod h1:z88B3+O/1/3doQABErvIOOxE4hjpmIpulu6XzDG/q78=
github.com/autobrr/go-rtorrent v1.10.0 h1:SCs7Rdi1BZ3MxNoVIdWK0qTUHQyhSj9rEU8KUTRi4Ug=
github.com/autobrr/go-rtorrent v1.10.0/go.mod h1:1CyQ2tcLOGP+p9drOqFiVPb/+QvfExMPCHnEGQd0BmM=
+github.com/autobrr/go-rtorrent v1.10.1-0.20240718115807-9f53e3443272 h1:qna9uyozEZbLS2HE7FP6qaXbnJzBOClQ+49mEUI51nM=
+github.com/autobrr/go-rtorrent v1.10.1-0.20240718115807-9f53e3443272/go.mod h1:1CyQ2tcLOGP+p9drOqFiVPb/+QvfExMPCHnEGQd0BmM=
+github.com/autobrr/go-rtorrent v1.11.0 h1:T1NRPgFLooFFMX0kfvewftLk4hFQUsMlDNB8WMynBSw=
+github.com/autobrr/go-rtorrent v1.11.0/go.mod h1:1CyQ2tcLOGP+p9drOqFiVPb/+QvfExMPCHnEGQd0BmM=
github.com/autobrr/sse/v2 v2.0.0-20230520125637-530e06346d7d h1:9EGCYgeugAVWLBAtjHC7AFnXSwUdYfCB98WaOgdDREE=
github.com/autobrr/sse/v2 v2.0.0-20230520125637-530e06346d7d/go.mod h1:zCozZ9lp4DE340T2+wfMPL/eoQwLVIGDOCKCDEFwTQU=
github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0=
@@ -200,6 +204,8 @@ github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
+github.com/icholy/digest v0.1.23 h1:4hX2pIloP0aDx7RJW0JewhPPy3R8kU+vWKdxPsCCGtY=
+github.com/icholy/digest v0.1.23/go.mod h1:QNrsSGQ5v7v9cReDI0+eyjsXGUoRSUZQHeQ5C4XLa0Y=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
diff --git a/internal/database/download_client.go b/internal/database/download_client.go
index 5609689..e0724b4 100644
--- a/internal/database/download_client.go
+++ b/internal/database/download_client.go
@@ -142,6 +142,7 @@ func (r *DownloadClientRepo) Store(ctx context.Context, client *domain.DownloadC
Rules: client.Settings.Rules,
ExternalDownloadClientId: client.Settings.ExternalDownloadClientId,
ExternalDownloadClient: client.Settings.ExternalDownloadClient,
+ Auth: client.Settings.Auth,
}
settingsJson, err := json.Marshal(&settings)
@@ -177,6 +178,7 @@ func (r *DownloadClientRepo) Update(ctx context.Context, client *domain.Download
Rules: client.Settings.Rules,
ExternalDownloadClientId: client.Settings.ExternalDownloadClientId,
ExternalDownloadClient: client.Settings.ExternalDownloadClient,
+ Auth: client.Settings.Auth,
}
settingsJson, err := json.Marshal(&settings)
diff --git a/internal/database/download_client_test.go b/internal/database/download_client_test.go
index 309f50c..f9fb1d2 100644
--- a/internal/database/download_client_test.go
+++ b/internal/database/download_client_test.go
@@ -44,6 +44,12 @@ func getMockDownloadClient() domain.DownloadClient {
},
ExternalDownloadClientId: 0,
ExternalDownloadClient: "",
+ Auth: domain.DownloadClientAuth{
+ Enabled: true,
+ Type: domain.DownloadClientAuthTypeBasic,
+ Username: "username",
+ Password: "password",
+ },
},
}
}
diff --git a/internal/domain/client.go b/internal/domain/client.go
index f9d667e..d543f94 100644
--- a/internal/domain/client.go
+++ b/internal/domain/client.go
@@ -5,6 +5,7 @@ package domain
import (
"context"
+ "encoding/json"
"fmt"
"net/url"
@@ -38,10 +39,72 @@ type DownloadClient struct {
type DownloadClientSettings struct {
APIKey string `json:"apikey,omitempty"`
- Basic BasicAuth `json:"basic,omitempty"`
+ Basic BasicAuth `json:"basic,omitempty"` // Deprecated: Use Auth instead
Rules DownloadClientRules `json:"rules,omitempty"`
ExternalDownloadClientId int `json:"external_download_client_id,omitempty"`
ExternalDownloadClient string `json:"external_download_client,omitempty"`
+ Auth DownloadClientAuth `json:"auth,omitempty"`
+}
+
+// MarshalJSON Custom method to translate Basic into Auth without including Basic in JSON output
+func (dcs *DownloadClientSettings) MarshalJSON() ([]byte, error) {
+ // Ensuring Auth is updated with Basic info before marshaling if Basic is set
+ if dcs.Basic.Username != "" || dcs.Basic.Password != "" {
+ dcs.Auth = DownloadClientAuth{
+ Enabled: dcs.Basic.Auth,
+ Type: DownloadClientAuthTypeBasic,
+ Username: dcs.Basic.Username,
+ Password: dcs.Basic.Password,
+ }
+ }
+
+ type Alias DownloadClientSettings
+ return json.Marshal(&struct {
+ *Alias
+ }{
+ Alias: (*Alias)(dcs),
+ })
+}
+
+// UnmarshalJSON Custom method to translate Basic into Auth
+func (dcs *DownloadClientSettings) UnmarshalJSON(data []byte) error {
+ type Alias DownloadClientSettings
+ aux := &struct {
+ *Alias
+ }{
+ Alias: (*Alias)(dcs),
+ }
+
+ if err := json.Unmarshal(data, &aux); err != nil {
+ return err
+ }
+
+ // If Basic fields are not empty, populate Auth fields accordingly
+ if aux.Basic.Username != "" || aux.Basic.Password != "" {
+ dcs.Auth = DownloadClientAuth{
+ Enabled: aux.Basic.Auth,
+ Type: DownloadClientAuthTypeBasic,
+ Username: aux.Basic.Username,
+ Password: aux.Basic.Password,
+ }
+ }
+
+ return nil
+}
+
+type DownloadClientAuthType string
+
+const (
+ DownloadClientAuthTypeNone = "NONE"
+ DownloadClientAuthTypeBasic = "BASIC_AUTH"
+ DownloadClientAuthTypeDigest = "DIGEST_AUTH"
+)
+
+type DownloadClientAuth struct {
+ Enabled bool `json:"enabled,omitempty"`
+ Type DownloadClientAuthType `json:"type,omitempty"`
+ Username string `json:"username,omitempty"`
+ Password string `json:"password,omitempty"`
}
type DownloadClientRules struct {
diff --git a/internal/download_client/cache.go b/internal/download_client/cache.go
index dd2784e..81a9ffa 100644
--- a/internal/download_client/cache.go
+++ b/internal/download_client/cache.go
@@ -1,3 +1,6 @@
+// Copyright (c) 2021 - 2024, Ludvig Lundgren and the autobrr contributors.
+// SPDX-License-Identifier: GPL-2.0-or-later
+
package download_client
import (
diff --git a/internal/download_client/connection.go b/internal/download_client/connection.go
index b30e063..faa53f4 100644
--- a/internal/download_client/connection.go
+++ b/internal/download_client/connection.go
@@ -5,7 +5,9 @@ package download_client
import (
"context"
+ "crypto/tls"
"fmt"
+ "net/http"
"net/url"
"time"
@@ -24,6 +26,7 @@ import (
"github.com/autobrr/go-qbittorrent"
"github.com/autobrr/go-rtorrent"
"github.com/dcarbone/zadapters/zstdlog"
+ "github.com/icholy/digest"
"github.com/rs/zerolog"
)
@@ -70,16 +73,16 @@ func (s *service) testConnection(ctx context.Context, client domain.DownloadClie
func (s *service) testQbittorrentConnection(ctx context.Context, client domain.DownloadClient) error {
qbtSettings := qbittorrent.Config{
Host: client.BuildLegacyHost(),
+ TLSSkipVerify: client.TLSSkipVerify,
Username: client.Username,
Password: client.Password,
- TLSSkipVerify: client.TLSSkipVerify,
Log: s.subLogger,
}
// only set basic auth if enabled
- if client.Settings.Basic.Auth {
- qbtSettings.BasicUser = client.Settings.Basic.Username
- qbtSettings.BasicPass = client.Settings.Basic.Password
+ if client.Settings.Auth.Enabled {
+ qbtSettings.BasicUser = client.Settings.Auth.Username
+ qbtSettings.BasicPass = client.Settings.Auth.Password
}
qbt := qbittorrent.NewClient(qbtSettings)
@@ -155,14 +158,31 @@ func (s *service) testDelugeConnection(ctx context.Context, client domain.Downlo
}
func (s *service) testRTorrentConnection(ctx context.Context, client domain.DownloadClient) error {
- // create client
- rt := rtorrent.NewClient(rtorrent.Config{
+ cfg := rtorrent.Config{
Addr: client.Host,
TLSSkipVerify: client.TLSSkipVerify,
- BasicUser: client.Settings.Basic.Username,
- BasicPass: client.Settings.Basic.Password,
- Log: nil,
- })
+ BasicUser: client.Settings.Auth.Username,
+ BasicPass: client.Settings.Auth.Password,
+ Log: s.subLogger,
+ }
+
+ // create client
+ rt := rtorrent.NewClient(cfg)
+
+ if client.Settings.Auth.Type == domain.DownloadClientAuthTypeDigest {
+ httpClient := &http.Client{
+ Transport: &digest.Transport{
+ Username: client.Settings.Auth.Username,
+ Password: client.Settings.Auth.Password,
+ Transport: &http.Transport{
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: client.TLSSkipVerify},
+ },
+ },
+ }
+
+ // override client
+ rt = rtorrent.NewClientWithOpts(cfg, rtorrent.WithCustomClient(httpClient))
+ }
name, err := rt.Name(ctx)
if err != nil {
@@ -206,7 +226,7 @@ func (s *service) testTransmissionConnection(ctx context.Context, client domain.
return errors.Wrap(err, "error getting rpc info: %v", client.Host)
}
- s.log.Debug().Msgf("test client connection for Transmission: got version: %v", version)
+ s.log.Trace().Msgf("test client connection for Transmission: got version: %v", version)
s.log.Debug().Msgf("test client connection for Transmission: success")
@@ -217,9 +237,9 @@ func (s *service) testRadarrConnection(ctx context.Context, client domain.Downlo
r := radarr.New(radarr.Config{
Hostname: client.Host,
APIKey: client.Settings.APIKey,
- BasicAuth: client.Settings.Basic.Auth,
- Username: client.Settings.Basic.Username,
- Password: client.Settings.Basic.Password,
+ BasicAuth: client.Settings.Auth.Enabled,
+ Username: client.Settings.Auth.Username,
+ Password: client.Settings.Auth.Password,
Log: s.subLogger,
})
@@ -236,9 +256,9 @@ func (s *service) testSonarrConnection(ctx context.Context, client domain.Downlo
r := sonarr.New(sonarr.Config{
Hostname: client.Host,
APIKey: client.Settings.APIKey,
- BasicAuth: client.Settings.Basic.Auth,
- Username: client.Settings.Basic.Username,
- Password: client.Settings.Basic.Password,
+ BasicAuth: client.Settings.Auth.Enabled,
+ Username: client.Settings.Auth.Username,
+ Password: client.Settings.Auth.Password,
Log: s.subLogger,
})
@@ -255,9 +275,9 @@ func (s *service) testLidarrConnection(ctx context.Context, client domain.Downlo
r := lidarr.New(lidarr.Config{
Hostname: client.Host,
APIKey: client.Settings.APIKey,
- BasicAuth: client.Settings.Basic.Auth,
- Username: client.Settings.Basic.Username,
- Password: client.Settings.Basic.Password,
+ BasicAuth: client.Settings.Auth.Enabled,
+ Username: client.Settings.Auth.Username,
+ Password: client.Settings.Auth.Password,
Log: s.subLogger,
})
@@ -274,9 +294,9 @@ func (s *service) testWhisparrConnection(ctx context.Context, client domain.Down
r := whisparr.New(whisparr.Config{
Hostname: client.Host,
APIKey: client.Settings.APIKey,
- BasicAuth: client.Settings.Basic.Auth,
- Username: client.Settings.Basic.Username,
- Password: client.Settings.Basic.Password,
+ BasicAuth: client.Settings.Auth.Enabled,
+ Username: client.Settings.Auth.Username,
+ Password: client.Settings.Auth.Password,
Log: s.subLogger,
})
@@ -293,9 +313,9 @@ func (s *service) testReadarrConnection(ctx context.Context, client domain.Downl
r := readarr.New(readarr.Config{
Hostname: client.Host,
APIKey: client.Settings.APIKey,
- BasicAuth: client.Settings.Basic.Auth,
- Username: client.Settings.Basic.Username,
- Password: client.Settings.Basic.Password,
+ BasicAuth: client.Settings.Auth.Enabled,
+ Username: client.Settings.Auth.Username,
+ Password: client.Settings.Auth.Password,
Log: s.subLogger,
})
@@ -310,8 +330,12 @@ func (s *service) testReadarrConnection(ctx context.Context, client domain.Downl
func (s *service) testPorlaConnection(client domain.DownloadClient) error {
p := porla.NewClient(porla.Config{
- Hostname: client.Host,
- AuthToken: client.Settings.APIKey,
+ Hostname: client.Host,
+ TLSSkipVerify: client.TLSSkipVerify,
+ AuthToken: client.Settings.APIKey,
+ BasicUser: client.Settings.Auth.Username,
+ BasicPass: client.Settings.Auth.Password,
+ Log: s.subLogger,
})
version, err := p.Version()
@@ -320,13 +344,13 @@ func (s *service) testPorlaConnection(client domain.DownloadClient) error {
return errors.Wrap(err, "porla: failed to get version: %v", client.Host)
}
- commitish := version.Commitish
+ commitHash := version.Commitish
- if len(commitish) > 8 {
- commitish = commitish[:8]
+ if len(commitHash) > 8 {
+ commitHash = commitHash[:8]
}
- s.log.Debug().Msgf("test client connection for porla: found version %s (commit %s)", version.Version, commitish)
+ s.log.Debug().Msgf("test client connection for porla: found version %s (commit %s)", version.Version, commitHash)
return nil
}
@@ -335,9 +359,9 @@ func (s *service) testSabnzbdConnection(ctx context.Context, client domain.Downl
opts := sabnzbd.Options{
Addr: client.Host,
ApiKey: client.Settings.APIKey,
- BasicUser: client.Settings.Basic.Username,
- BasicPass: client.Settings.Basic.Password,
- Log: nil,
+ BasicUser: client.Settings.Auth.Username,
+ BasicPass: client.Settings.Auth.Password,
+ Log: s.subLogger,
}
sab := sabnzbd.New(opts)
diff --git a/internal/download_client/service.go b/internal/download_client/service.go
index 9c58865..57a277d 100644
--- a/internal/download_client/service.go
+++ b/internal/download_client/service.go
@@ -5,8 +5,10 @@ package download_client
import (
"context"
+ "crypto/tls"
"fmt"
"log"
+ "net/http"
"net/url"
"sync"
"time"
@@ -27,6 +29,7 @@ import (
"github.com/autobrr/go-qbittorrent"
"github.com/autobrr/go-rtorrent"
"github.com/dcarbone/zadapters/zstdlog"
+ "github.com/icholy/digest"
"github.com/rs/zerolog"
)
@@ -184,8 +187,8 @@ func (s *service) GetClient(ctx context.Context, clientId int32) (*domain.Downlo
Password: client.Password,
TLSSkipVerify: client.TLSSkipVerify,
Log: zstdlog.NewStdLoggerWithLevel(s.log.With().Str("type", "qBittorrent").Str("client", client.Name).Logger(), zerolog.TraceLevel),
- BasicUser: client.Settings.Basic.Username,
- BasicPass: client.Settings.Basic.Password,
+ BasicUser: client.Settings.Auth.Username,
+ BasicPass: client.Settings.Auth.Password,
})
case domain.DownloadClientTypePorla:
@@ -193,8 +196,8 @@ func (s *service) GetClient(ctx context.Context, clientId int32) (*domain.Downlo
Hostname: client.Host,
AuthToken: client.Settings.APIKey,
TLSSkipVerify: client.TLSSkipVerify,
- BasicUser: client.Settings.Basic.Username,
- BasicPass: client.Settings.Basic.Password,
+ BasicUser: client.Settings.Auth.Username,
+ BasicPass: client.Settings.Auth.Password,
Log: zstdlog.NewStdLoggerWithLevel(s.log.With().Str("type", "Porla").Str("client", client.Name).Logger(), zerolog.TraceLevel),
})
@@ -241,22 +244,46 @@ func (s *service) GetClient(ctx context.Context, clientId int32) (*domain.Downlo
client.Client = tbt
case domain.DownloadClientTypeRTorrent:
- client.Client = rtorrent.NewClient(rtorrent.Config{
- Addr: client.Host,
- TLSSkipVerify: client.TLSSkipVerify,
- BasicUser: client.Settings.Basic.Username,
- BasicPass: client.Settings.Basic.Password,
- Log: zstdlog.NewStdLoggerWithLevel(s.log.With().Str("type", "rTorrent").Str("client", client.Name).Logger(), zerolog.TraceLevel),
- })
+ if client.Settings.Auth.Type == domain.DownloadClientAuthTypeDigest {
+ cfg := rtorrent.Config{
+ Addr: client.Host,
+ TLSSkipVerify: client.TLSSkipVerify,
+ BasicUser: client.Settings.Auth.Username,
+ BasicPass: client.Settings.Auth.Password,
+ Log: zstdlog.NewStdLoggerWithLevel(s.log.With().Str("type", "rTorrent").Str("client", client.Name).Logger(), zerolog.TraceLevel),
+ }
+
+ httpClient := &http.Client{
+ Transport: &digest.Transport{
+ Username: client.Settings.Auth.Username,
+ Password: client.Settings.Auth.Password,
+ Transport: &http.Transport{
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: client.TLSSkipVerify},
+ },
+ },
+ }
+
+ // override client
+ client.Client = rtorrent.NewClientWithOpts(cfg, rtorrent.WithCustomClient(httpClient))
+
+ } else {
+ client.Client = rtorrent.NewClient(rtorrent.Config{
+ Addr: client.Host,
+ TLSSkipVerify: client.TLSSkipVerify,
+ BasicUser: client.Settings.Auth.Username,
+ BasicPass: client.Settings.Auth.Password,
+ Log: zstdlog.NewStdLoggerWithLevel(s.log.With().Str("type", "rTorrent").Str("client", client.Name).Logger(), zerolog.TraceLevel),
+ })
+ }
case domain.DownloadClientTypeLidarr:
client.Client = lidarr.New(lidarr.Config{
Hostname: client.Host,
APIKey: client.Settings.APIKey,
Log: zstdlog.NewStdLoggerWithLevel(s.log.With().Str("type", "Lidarr").Str("client", client.Name).Logger(), zerolog.TraceLevel),
- BasicAuth: client.Settings.Basic.Auth,
- Username: client.Settings.Basic.Username,
- Password: client.Settings.Basic.Password,
+ BasicAuth: client.Settings.Auth.Enabled,
+ Username: client.Settings.Auth.Username,
+ Password: client.Settings.Auth.Password,
})
case domain.DownloadClientTypeRadarr:
@@ -264,9 +291,9 @@ func (s *service) GetClient(ctx context.Context, clientId int32) (*domain.Downlo
Hostname: client.Host,
APIKey: client.Settings.APIKey,
Log: zstdlog.NewStdLoggerWithLevel(s.log.With().Str("type", "Radarr").Str("client", client.Name).Logger(), zerolog.TraceLevel),
- BasicAuth: client.Settings.Basic.Auth,
- Username: client.Settings.Basic.Username,
- Password: client.Settings.Basic.Password,
+ BasicAuth: client.Settings.Auth.Enabled,
+ Username: client.Settings.Auth.Username,
+ Password: client.Settings.Auth.Password,
})
case domain.DownloadClientTypeReadarr:
@@ -274,9 +301,9 @@ func (s *service) GetClient(ctx context.Context, clientId int32) (*domain.Downlo
Hostname: client.Host,
APIKey: client.Settings.APIKey,
Log: zstdlog.NewStdLoggerWithLevel(s.log.With().Str("type", "Readarr").Str("client", client.Name).Logger(), zerolog.TraceLevel),
- BasicAuth: client.Settings.Basic.Auth,
- Username: client.Settings.Basic.Username,
- Password: client.Settings.Basic.Password,
+ BasicAuth: client.Settings.Auth.Enabled,
+ Username: client.Settings.Auth.Username,
+ Password: client.Settings.Auth.Password,
})
case domain.DownloadClientTypeSonarr:
@@ -284,9 +311,9 @@ func (s *service) GetClient(ctx context.Context, clientId int32) (*domain.Downlo
Hostname: client.Host,
APIKey: client.Settings.APIKey,
Log: zstdlog.NewStdLoggerWithLevel(s.log.With().Str("type", "Sonarr").Str("client", client.Name).Logger(), zerolog.TraceLevel),
- BasicAuth: client.Settings.Basic.Auth,
- Username: client.Settings.Basic.Username,
- Password: client.Settings.Basic.Password,
+ BasicAuth: client.Settings.Auth.Enabled,
+ Username: client.Settings.Auth.Username,
+ Password: client.Settings.Auth.Password,
})
case domain.DownloadClientTypeWhisparr:
@@ -294,9 +321,9 @@ func (s *service) GetClient(ctx context.Context, clientId int32) (*domain.Downlo
Hostname: client.Host,
APIKey: client.Settings.APIKey,
Log: zstdlog.NewStdLoggerWithLevel(s.log.With().Str("type", "Whisparr").Str("client", client.Name).Logger(), zerolog.TraceLevel),
- BasicAuth: client.Settings.Basic.Auth,
- Username: client.Settings.Basic.Username,
- Password: client.Settings.Basic.Password,
+ BasicAuth: client.Settings.Auth.Enabled,
+ Username: client.Settings.Auth.Username,
+ Password: client.Settings.Auth.Password,
})
case domain.DownloadClientTypeSabnzbd:
@@ -304,8 +331,8 @@ func (s *service) GetClient(ctx context.Context, clientId int32) (*domain.Downlo
Addr: client.Host,
ApiKey: client.Settings.APIKey,
Log: nil,
- BasicUser: client.Settings.Basic.Username,
- BasicPass: client.Settings.Basic.Password,
+ BasicUser: client.Settings.Auth.Username,
+ BasicPass: client.Settings.Auth.Password,
})
}
diff --git a/web/src/components/tooltips/Tooltip.tsx b/web/src/components/tooltips/Tooltip.tsx
index 8041819..5491eca 100644
--- a/web/src/components/tooltips/Tooltip.tsx
+++ b/web/src/components/tooltips/Tooltip.tsx
@@ -129,7 +129,7 @@ export const Tooltip = ({
{...getTooltipProps({
className: classNames(
maxWidth,
- "rounded-md border border-gray-300 text-black text-xs normal-case tracking-normal font-normal shadow-lg dark:text-white dark:border-gray-700 dark:shadow-2xl"
+ "z-10 rounded-md border border-gray-300 text-black text-xs normal-case tracking-normal font-normal shadow-lg dark:text-white dark:border-gray-700 dark:shadow-2xl"
),
onClick: (e: React.MouseEvent) => e.stopPropagation()
})}
diff --git a/web/src/domain/constants.ts b/web/src/domain/constants.ts
index 1628cb8..3e705ac 100644
--- a/web/src/domain/constants.ts
+++ b/web/src/domain/constants.ts
@@ -474,6 +474,21 @@ export const DownloadRuleConditionOptions: OptionBasic[] = [
}
];
+export const DownloadClientAuthType: OptionBasic[] = [
+ {
+ label: "None",
+ value: "NONE"
+ },
+ {
+ label: "Basic Auth",
+ value: "BASIC_AUTH"
+ },
+ {
+ label: "Digest Auth",
+ value: "DIGEST_AUTH"
+ }
+];
+
const logLevel = ["DEBUG", "INFO", "WARN", "ERROR", "TRACE"] as const;
export const LogLevelOptions = logLevel.map(v => ({ value: v, label: v, key: v }));
diff --git a/web/src/forms/settings/DownloadClientForms.tsx b/web/src/forms/settings/DownloadClientForms.tsx
index b9ff5d3..d72311d 100644
--- a/web/src/forms/settings/DownloadClientForms.tsx
+++ b/web/src/forms/settings/DownloadClientForms.tsx
@@ -14,7 +14,7 @@ import { classNames, sleep } from "@utils";
import { DEBUG } from "@components/debug";
import { APIClient } from "@api/APIClient";
import { DownloadClientKeys } from "@api/query_keys";
-import { DownloadClientTypeOptions, DownloadRuleConditionOptions } from "@domain/constants";
+import { DownloadClientAuthType, DownloadClientTypeOptions, DownloadRuleConditionOptions } from "@domain/constants";
import Toast from "@components/notifications/Toast";
import { useToggle } from "@hooks/hooks";
import { DeleteModal } from "@components/modals";
@@ -34,6 +34,12 @@ interface InitialValuesSettings {
username: string;
password: string;
};
+ auth?: {
+ enabled: boolean;
+ type: string;
+ username: string;
+ password: string;
+ };
rules?: {
enabled?: boolean;
ignore_slow_torrents?: boolean;
@@ -267,12 +273,19 @@ function FormFieldsRTorrent() {
/>
)}
-