mediawire: qBittorrent 5 answers a good login with 204 — accept it (found on Tester 1, Part G1); fake answers 204 like the app
gates / gates (push) Successful in 41s
gates / gates (push) Successful in 41s
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -31,6 +31,8 @@ Not released yet (bake → vouch → floor, `09` §3 decision 247). Design: felh
|
|||||||
with the API key named „felhom" read at use from Jellyfin's own database (no key → one household step, said on the
|
with the API key named „felhom" read at use from Jellyfin's own database (no key → one household step, said on the
|
||||||
page). Keys read at use, never stored or logged; links never undone when an app stops. Idempotent:
|
page). Keys read at use, never stored or logged; links never undone when an app stops. Idempotent:
|
||||||
`TestRun_SecondRunWritesNothing` (red-proved: the measured repeated qBittorrent writes).
|
`TestRun_SecondRunWritesNothing` (red-proved: the measured repeated qBittorrent writes).
|
||||||
|
- **Fixed on Tester 1 (Part G1):** qBittorrent 5 answers a good login with HTTP 204, not 200 — the wiring refused it
|
||||||
|
(`login: HTTP 204`). Both logins accept 204; the test fake now answers 204 as the real app does (red-proved).
|
||||||
- **Old Sonarr/Radarr installs repaired by themselves (R-1047)** — only when /media is no longer bound: same-path root
|
- **Old Sonarr/Radarr installs repaired by themselves (R-1047)** — only when /media is no longer bound: same-path root
|
||||||
folder, `moveFiles:false` editor, rescan, old root removed, Radarr's collections too. `TestRepairOldRoot_K7`
|
folder, `moveFiles:false` editor, rescan, old root removed, Radarr's collections too. `TestRepairOldRoot_K7`
|
||||||
(red-proved: moveFiles=true is caught).
|
(red-proved: moveFiles=true is caught).
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ func (w *Wirer) qbittorrent(drives []Drive, pw string) Result {
|
|||||||
form := url.Values{"username": {"admin"}, "password": {pw}}
|
form := url.Values{"username": {"admin"}, "password": {pw}}
|
||||||
code, _, hd, err := w.do("POST", base+"/api/v2/auth/login", map[string]string{"Referer": base}, strings.NewReader(form.Encode()), "application/x-www-form-urlencoded")
|
code, _, hd, err := w.do("POST", base+"/api/v2/auth/login", map[string]string{"Referer": base}, strings.NewReader(form.Encode()), "application/x-www-form-urlencoded")
|
||||||
m := regexp.MustCompile(`((?:QBT_)?SID[A-Za-z0-9_]*)=([^;]+)`).FindStringSubmatch(strings.Join(hd.Values("Set-Cookie"), "; "))
|
m := regexp.MustCompile(`((?:QBT_)?SID[A-Za-z0-9_]*)=([^;]+)`).FindStringSubmatch(strings.Join(hd.Values("Set-Cookie"), "; "))
|
||||||
if err != nil || code != 200 || m == nil {
|
if err != nil || (code != 200 && code != 204) || m == nil { // qBittorrent 5 answers a good login 204 (measured on Tester 1)
|
||||||
r.State, r.Detail = "error", fmt.Sprintf("login: HTTP %d %v", code, err)
|
r.State, r.Detail = "error", fmt.Sprintf("login: HTTP %d %v", code, err)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
@@ -834,7 +834,7 @@ func (w *Wirer) qbLogin(pw string) (string, map[string]string, error) {
|
|||||||
form := url.Values{"username": {"admin"}, "password": {pw}}
|
form := url.Values{"username": {"admin"}, "password": {pw}}
|
||||||
code, _, hd, err := w.do("POST", base+"/api/v2/auth/login", map[string]string{"Referer": base}, strings.NewReader(form.Encode()), "application/x-www-form-urlencoded")
|
code, _, hd, err := w.do("POST", base+"/api/v2/auth/login", map[string]string{"Referer": base}, strings.NewReader(form.Encode()), "application/x-www-form-urlencoded")
|
||||||
m := regexp.MustCompile(`((?:QBT_)?SID[A-Za-z0-9_]*)=([^;]+)`).FindStringSubmatch(strings.Join(hd.Values("Set-Cookie"), "; "))
|
m := regexp.MustCompile(`((?:QBT_)?SID[A-Za-z0-9_]*)=([^;]+)`).FindStringSubmatch(strings.Join(hd.Values("Set-Cookie"), "; "))
|
||||||
if err != nil || code != 200 || m == nil {
|
if err != nil || (code != 200 && code != 204) || m == nil { // qBittorrent 5 answers a good login 204 (measured on Tester 1)
|
||||||
return "", nil, fmt.Errorf("qBittorrent login: HTTP %d %v", code, err)
|
return "", nil, fmt.Errorf("qBittorrent login: HTTP %d %v", code, err)
|
||||||
}
|
}
|
||||||
return base, map[string]string{"Referer": base, "Cookie": m[1] + "=" + m[2]}, nil
|
return base, map[string]string{"Referer": base, "Cookie": m[1] + "=" + m[2]}, nil
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ func (w *world) server(t *testing.T) *httptest.Server {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
http.SetCookie(rw, &http.Cookie{Name: "QBT_SID_8080", Value: "sid"})
|
http.SetCookie(rw, &http.Cookie{Name: "QBT_SID_8080", Value: "sid"})
|
||||||
|
rw.WriteHeader(204) // qBittorrent 5.x: a good login is 204 No Content (measured on Tester 1, 2026-10-15)
|
||||||
case p == "/api/v2/app/preferences":
|
case p == "/api/v2/app/preferences":
|
||||||
j(map[string]interface{}{"auto_tmm_enabled": w.autoTMM})
|
j(map[string]interface{}{"auto_tmm_enabled": w.autoTMM})
|
||||||
case p == "/api/v2/app/setPreferences":
|
case p == "/api/v2/app/setPreferences":
|
||||||
|
|||||||
Reference in New Issue
Block a user