Files
MeBox/internal/service/qbittorrent_login.go
T
2026-05-29 04:15:44 +08:00

81 lines
2.3 KiB
Go

package service
import (
"context"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"strings"
)
type qbitLoginVariant struct {
name string
referer bool
origin bool
}
func qbitLogin(ctx context.Context, client *http.Client, baseURL, username, password string) error {
baseURL = strings.TrimRight(strings.TrimSpace(baseURL), "/")
if baseURL == "" {
return errors.New("qbittorrent host not configured")
}
var lastErr error
for _, variant := range []qbitLoginVariant{
{name: "minimal"},
{name: "referer", referer: true},
{name: "referer-origin", referer: true, origin: true},
} {
err := qbitLoginOnce(ctx, client, baseURL, username, password, variant)
if err == nil {
return nil
}
lastErr = err
if errors.Is(err, errQbitBadCredentials) {
return err
}
}
return lastErr
}
var errQbitBadCredentials = errors.New("qbittorrent: 用户名/密码错误")
func qbitLoginOnce(ctx context.Context, client *http.Client, baseURL, username, password string, variant qbitLoginVariant) error {
form := url.Values{}
form.Set("username", username)
form.Set("password", password)
req, err := http.NewRequestWithContext(ctx, http.MethodPost,
baseURL+"/api/v2/auth/login", strings.NewReader(form.Encode()))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
if variant.referer {
req.Header.Set("Referer", baseURL)
}
if variant.origin {
req.Header.Set("Origin", baseURL)
}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
raw, _ := io.ReadAll(io.LimitReader(resp.Body, 1024))
text := strings.TrimSpace(string(raw))
switch {
case resp.StatusCode == http.StatusOK && text == "Ok.":
return nil
case resp.StatusCode == http.StatusOK && text == "Fails.":
return errQbitBadCredentials
case resp.StatusCode == http.StatusForbidden:
return fmt.Errorf("qbittorrent: 403 forbidden during %s login, body=%q; check qBittorrent WebUI bypass/auth settings for the container IP and host %s", variant.name, text, baseURL)
case resp.StatusCode >= 400:
return fmt.Errorf("qbittorrent login failed during %s login: status=%d body=%q", variant.name, resp.StatusCode, text)
default:
return fmt.Errorf("qbittorrent login unexpected response during %s login: status=%d body=%q", variant.name, resp.StatusCode, text)
}
}