Add auth to qbittorent middleware

This commit is contained in:
Mukhtar Akere
2025-08-09 20:25:16 +01:00
parent 0dd1efb07c
commit 6c8949b831

View File

@@ -5,8 +5,10 @@ import (
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/sirrobot01/decypharr/internal/config"
"github.com/sirrobot01/decypharr/pkg/arr" "github.com/sirrobot01/decypharr/pkg/arr"
"github.com/sirrobot01/decypharr/pkg/store" "github.com/sirrobot01/decypharr/pkg/store"
"golang.org/x/crypto/bcrypt"
"net/http" "net/http"
"net/url" "net/url"
"strings" "strings"
@@ -125,6 +127,7 @@ func (q *QBit) categoryContext(next http.Handler) http.Handler {
// Only a valid host and token will be added to the context/config. The rest are manual // Only a valid host and token will be added to the context/config. The rest are manual
func (q *QBit) authContext(next http.Handler) http.Handler { func (q *QBit) authContext(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
cfg := config.Get()
host, token, err := decodeAuthHeader(r.Header.Get("Authorization")) host, token, err := decodeAuthHeader(r.Header.Get("Authorization"))
category := getCategory(r.Context()) category := getCategory(r.Context())
arrs := store.Get().Arr() arrs := store.Get().Arr()
@@ -145,12 +148,22 @@ func (q *QBit) authContext(next http.Handler) http.Handler {
a.Token = token a.Token = token
} }
} }
a.Source = "auto" if cfg.NeedsAuth() {
if err := validateServiceURL(a.Host); err != nil { if a.Host == "" || a.Token == "" {
// Return silently, no need to raise a problem. Just do not add the Arr to the context/config.json http.Error(w, "Unauthorized: Host and token are required for authentication", http.StatusUnauthorized)
next.ServeHTTP(w, r) return
return }
// try to use either Arr validate, or user auth validation
if err := a.Validate(); err != nil {
// If this failed, try to use user auth validation
if !verifyAuth(host, token) {
http.Error(w, "Unauthorized: Invalid host or token", http.StatusUnauthorized)
return
}
}
} }
a.Source = "auto"
arrs.AddOrUpdate(a) arrs.AddOrUpdate(a)
ctx := context.WithValue(r.Context(), arrKey, a) ctx := context.WithValue(r.Context(), arrKey, a)
next.ServeHTTP(w, r.WithContext(ctx)) next.ServeHTTP(w, r.WithContext(ctx))
@@ -176,3 +189,19 @@ func hashesContext(next http.Handler) http.Handler {
next.ServeHTTP(w, r.WithContext(ctx)) next.ServeHTTP(w, r.WithContext(ctx))
}) })
} }
func verifyAuth(username, password string) bool {
// If you're storing hashed password, use bcrypt to compare
if username == "" {
return false
}
auth := config.Get().GetAuth()
if auth == nil {
return false
}
if username != auth.Username {
return false
}
err := bcrypt.CompareHashAndPassword([]byte(auth.Password), []byte(password))
return err == nil
}