v0.332.0: one sign-in for the file manager — a dashboard pass, a host-only files cookie, a per-box secret header (R-1100, operator D16)
gates / gates (push) Successful in 47s
gates / gates (push) Successful in 47s
This commit is contained in:
@@ -2,10 +2,12 @@ package web
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"html"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
@@ -181,6 +183,34 @@ func lfGet(t *testing.T, s *Server, path string) (int, string, string) {
|
||||
var lfAnswerRe = regexp.MustCompile(`data-login-answer="([a-z_]+)"`)
|
||||
var lfFilesRe = regexp.MustCompile(`href="([^"]+)"[^>]*data-app-files="1"`)
|
||||
|
||||
// lfOpenTo is the FileBrowser path a rendered „Fájlok" href opens since R-1100: the href is the dashboard's
|
||||
// /__files/open, the folder rides `to`. "" = not such a link.
|
||||
func lfOpenTo(href string) string {
|
||||
u, err := url.Parse(html.UnescapeString(href))
|
||||
if err != nil || u.Host != "felhom.example.hu" || u.Path != "/__files/open" {
|
||||
return ""
|
||||
}
|
||||
return u.Query().Get("to")
|
||||
}
|
||||
|
||||
// lfOpenHrefs are the FileBrowser paths of every dashboard pass link on a page.
|
||||
func lfOpenHrefs(page string) []string {
|
||||
var out []string
|
||||
for _, m := range regexp.MustCompile(`href="(https://felhom\.example\.hu/__files/open\?[^"]+)"`).FindAllStringSubmatch(page, -1) {
|
||||
out = append(out, lfOpenTo(m[1]))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func lfHasOpen(page, path string) bool {
|
||||
for _, p := range lfOpenHrefs(page) {
|
||||
if p == path {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ── Part 1: FileBrowser is part of the box ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
// RED-PROOF (2026-10-16, REPORT): with appPageHandler reading `installed := found.Deployed` again (the v0.315.0
|
||||
@@ -277,32 +307,38 @@ func TestAppPage_EveryInstalledAppHasOneLoginAnswer(t *testing.T) {
|
||||
// calibre-web — the button opened the import drop-zone, the first declared folder.
|
||||
func TestAppPage_FilesButtonTarget(t *testing.T) {
|
||||
s := lfHarness(t, settings.FileBrowserAdminGenerated, lfDriveA, lfDriveB)
|
||||
const srcA = "https://files.example.hu/files/M%C3%A9dia%20&%20k%C3%B6nyvt%C3%A1r"
|
||||
// R-1100: the button goes through the dashboard's pass (/__files/open); the FileBrowser path rides `to`.
|
||||
const srcA = "/files/M%C3%A9dia%20&%20k%C3%B6nyvt%C3%A1r"
|
||||
for _, c := range []struct{ slug, want string }{
|
||||
{"romm", srcA + "/roms"},
|
||||
{"calibre-web", srcA + "/media/books"},
|
||||
{"plex", srcA + "/media"}, // the first drive's media folder
|
||||
{"immich", ""},
|
||||
} {
|
||||
_, html, _ := lfGet(t, s, "/apps/"+c.slug)
|
||||
m := lfFilesRe.FindStringSubmatch(html)
|
||||
_, page, _ := lfGet(t, s, "/apps/"+c.slug)
|
||||
m := lfFilesRe.FindStringSubmatch(page)
|
||||
switch {
|
||||
case c.want == "" && m != nil:
|
||||
t.Errorf("%s: a Files button (%s) for an app with no folder", c.slug, m[1])
|
||||
case c.want != "" && m == nil:
|
||||
t.Errorf("%s: no Files button, want %s", c.slug, c.want)
|
||||
case c.want != "" && m[1] != c.want:
|
||||
t.Errorf("%s: Files → %s, want %s", c.slug, m[1], c.want)
|
||||
case c.want != "" && lfOpenTo(m[1]) != c.want:
|
||||
t.Errorf("%s: Files → %s (to=%q), want to=%s", c.slug, m[1], lfOpenTo(m[1]), c.want)
|
||||
}
|
||||
if strings.Contains(html, "M%C3%A9dia+") || strings.Contains(html, "%26") {
|
||||
t.Errorf("%s: a link built with QueryEscape (+ for a space, %%26 for &)", c.slug)
|
||||
for _, p := range lfOpenHrefs(page) {
|
||||
if strings.Contains(p, "M%C3%A9dia+") || strings.Contains(p, "%26") {
|
||||
t.Errorf("%s: a FileBrowser path built with QueryEscape (+ for a space, %%26 for &): %s", c.slug, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
// The data tab lists each drive's media folders for Plex, and points at the file manager's login.
|
||||
_, data, _ := lfGet(t, s, "/apps/plex/data")
|
||||
for _, want := range []string{srcA + "/media/movies", srcA + "/media/tv",
|
||||
"https://files.example.hu/files/HDD%202/media/movies", "https://files.example.hu/files/HDD%202/media/tv",
|
||||
`data-fb-login-note="1"`, `href="/apps/filebrowser"`} {
|
||||
for _, want := range []string{srcA + "/media/movies", srcA + "/media/tv", "/files/HDD%202/media/movies", "/files/HDD%202/media/tv"} {
|
||||
if !lfHasOpen(data, want) {
|
||||
t.Errorf("plex data tab lacks a link to %s (has %v)", want, lfOpenHrefs(data))
|
||||
}
|
||||
}
|
||||
for _, want := range []string{`data-fb-login-note="1"`, `href="/apps/filebrowser"`} {
|
||||
if !strings.Contains(data, want) {
|
||||
t.Errorf("plex data tab lacks %s", want)
|
||||
}
|
||||
@@ -313,25 +349,30 @@ func TestAppPage_FilesButtonTarget(t *testing.T) {
|
||||
// „romm links a folder on a drive that is not on the box".
|
||||
func TestAppPage_UnknownSourceIsTextNotLink(t *testing.T) {
|
||||
s := lfHarness(t, settings.FileBrowserAdminGenerated, lfDriveB) // drive A (romm's, plex's first) is away
|
||||
_, html, _ := lfGet(t, s, "/apps/romm/data")
|
||||
if strings.Contains(html, "/roms") && strings.Contains(html, "files.example.hu/files/M%C3%A9dia") {
|
||||
t.Fatal("romm links a folder on a drive that is not on the box")
|
||||
_, page, _ := lfGet(t, s, "/apps/romm/data")
|
||||
for _, p := range lfOpenHrefs(page) {
|
||||
if strings.HasPrefix(p, "/files/M%C3%A9dia") {
|
||||
t.Fatal("romm links a folder on a drive that is not on the box")
|
||||
}
|
||||
}
|
||||
if !strings.Contains(html, `data-folder-unavailable="1"`) {
|
||||
if !strings.Contains(page, `data-folder-unavailable="1"`) {
|
||||
t.Fatal("romm's folder is not shown as text when its source is absent")
|
||||
}
|
||||
if _, page, _ := lfGet(t, s, "/apps/romm"); lfFilesRe.MatchString(page) {
|
||||
if _, p, _ := lfGet(t, s, "/apps/romm"); lfFilesRe.MatchString(p) {
|
||||
t.Error("romm has a Files button although no folder of it is on the box")
|
||||
}
|
||||
// Plex: drive A text, drive B links; the button goes to the first PRESENT drive.
|
||||
_, plex, _ := lfGet(t, s, "/apps/plex/data")
|
||||
if !strings.Contains(plex, `data-folder-unavailable="1"`) || !strings.Contains(plex, "HDD%202/media/movies") {
|
||||
if !strings.Contains(plex, `data-folder-unavailable="1"`) || !lfHasOpen(plex, "/files/HDD%202/media/movies") {
|
||||
t.Error("plex: absent drive not text, or present drive not linked")
|
||||
}
|
||||
if strings.Contains(plex, "files.example.hu/files/M%C3%A9dia") {
|
||||
t.Error("plex links the absent drive")
|
||||
for _, p := range lfOpenHrefs(plex) {
|
||||
if strings.HasPrefix(p, "/files/M%C3%A9dia") {
|
||||
t.Error("plex links the absent drive")
|
||||
}
|
||||
}
|
||||
if _, page, _ := lfGet(t, s, "/apps/plex"); !strings.Contains(page, `href="https://files.example.hu/files/HDD%202/media"`) {
|
||||
_, pp, _ := lfGet(t, s, "/apps/plex")
|
||||
if m := lfFilesRe.FindStringSubmatch(pp); m == nil || lfOpenTo(m[1]) != "/files/HDD%202/media" {
|
||||
t.Error("plex Files button does not go to the first present drive")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user