Auth: Refactor cluster configuration and provisioning API endpoints #98

Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
Michael Mayer
2025-09-24 08:28:38 +02:00
parent 3baabebf50
commit 61ced7119c
242 changed files with 4477 additions and 1789 deletions

View File

@@ -26,7 +26,6 @@ func TestClusterGetTheme(t *testing.T) {
r := PerformRequest(app, http.MethodGet, "/api/v1/cluster/theme")
assert.Equal(t, http.StatusForbidden, r.Code)
})
t.Run("NotFound", func(t *testing.T) {
app, router, conf := NewApiTest()
// Enable portal feature flag for this endpoint.
@@ -44,7 +43,6 @@ func TestClusterGetTheme(t *testing.T) {
app.ServeHTTP(w, req)
assert.Equal(t, http.StatusNotFound, w.Code)
})
t.Run("Success", func(t *testing.T) {
app, router, conf := NewApiTest()
// Enable portal feature flag for this endpoint.
@@ -56,19 +54,19 @@ func TestClusterGetTheme(t *testing.T) {
defer func() { _ = os.RemoveAll(tempTheme) }()
conf.SetThemePath(tempTheme)
assert.NoError(t, os.MkdirAll(filepath.Join(tempTheme, "sub"), 0o755))
assert.NoError(t, os.MkdirAll(filepath.Join(tempTheme, "sub"), fs.ModeDir))
// Visible files
assert.NoError(t, os.WriteFile(filepath.Join(tempTheme, "app.js"), []byte("console.log('ok')\n"), 0o644))
assert.NoError(t, os.WriteFile(filepath.Join(tempTheme, "style.css"), []byte("body{}\n"), 0o644))
assert.NoError(t, os.WriteFile(filepath.Join(tempTheme, "sub", "visible.txt"), []byte("ok\n"), 0o644))
assert.NoError(t, os.WriteFile(filepath.Join(tempTheme, "app.js"), []byte("console.log('ok')\n"), fs.ModeFile))
assert.NoError(t, os.WriteFile(filepath.Join(tempTheme, "style.css"), []byte("body{}\n"), fs.ModeFile))
assert.NoError(t, os.WriteFile(filepath.Join(tempTheme, "sub", "visible.txt"), []byte("ok\n"), fs.ModeFile))
// Hidden file
assert.NoError(t, os.WriteFile(filepath.Join(tempTheme, ".hidden.txt"), []byte("secret\n"), 0o644))
assert.NoError(t, os.WriteFile(filepath.Join(tempTheme, ".hidden.txt"), []byte("secret\n"), fs.ModeFile))
// Hidden directory
assert.NoError(t, os.MkdirAll(filepath.Join(tempTheme, ".git"), 0o755))
assert.NoError(t, os.WriteFile(filepath.Join(tempTheme, ".git", "HEAD"), []byte("ref: refs/heads/main\n"), 0o644))
assert.NoError(t, os.MkdirAll(filepath.Join(tempTheme, ".git"), fs.ModeDir))
assert.NoError(t, os.WriteFile(filepath.Join(tempTheme, ".git", "HEAD"), []byte("ref: refs/heads/main\n"), fs.ModeFile))
// Hidden directory pattern "_.folder"
assert.NoError(t, os.MkdirAll(filepath.Join(tempTheme, "_.folder"), 0o755))
assert.NoError(t, os.WriteFile(filepath.Join(tempTheme, "_.folder", "secret.txt"), []byte("hidden\n"), 0o644))
assert.NoError(t, os.MkdirAll(filepath.Join(tempTheme, "_.folder"), fs.ModeDir))
assert.NoError(t, os.WriteFile(filepath.Join(tempTheme, "_.folder", "secret.txt"), []byte("hidden\n"), fs.ModeFile))
// Symlink (should be skipped); best-effort
_ = os.Symlink(filepath.Join(tempTheme, "style.css"), filepath.Join(tempTheme, "link.css"))
@@ -100,7 +98,6 @@ func TestClusterGetTheme(t *testing.T) {
assert.NotContains(t, names, "_.folder/secret.txt")
assert.NotContains(t, names, "link.css")
})
t.Run("Empty", func(t *testing.T) {
app, router, conf := NewApiTest()
// Enable portal feature flag for this endpoint.
@@ -114,9 +111,9 @@ func TestClusterGetTheme(t *testing.T) {
conf.SetThemePath(tempTheme)
// Hidden-only content and no app.js should yield 404.
assert.NoError(t, os.MkdirAll(filepath.Join(tempTheme, ".hidden-dir"), 0o755))
assert.NoError(t, os.WriteFile(filepath.Join(tempTheme, ".hidden-dir", "file.txt"), []byte("secret\n"), 0o644))
assert.NoError(t, os.WriteFile(filepath.Join(tempTheme, ".hidden"), []byte("secret\n"), 0o644))
assert.NoError(t, os.MkdirAll(filepath.Join(tempTheme, ".hidden-dir"), fs.ModeDir))
assert.NoError(t, os.WriteFile(filepath.Join(tempTheme, ".hidden-dir", "file.txt"), []byte("secret\n"), fs.ModeFile))
assert.NoError(t, os.WriteFile(filepath.Join(tempTheme, ".hidden"), []byte("secret\n"), fs.ModeFile))
req := httptest.NewRequest(http.MethodGet, "/api/v1/cluster/theme", nil)
req.Header.Set("Accept", "application/json")
@@ -124,4 +121,26 @@ func TestClusterGetTheme(t *testing.T) {
app.ServeHTTP(w, req)
assert.Equal(t, http.StatusNotFound, w.Code)
})
t.Run("CIDRAllowWithoutAuth", func(t *testing.T) {
app, router, conf := NewApiTest()
// Enable portal role and set CIDR to loopback/10.0.0.0/8 for test.
conf.Options().NodeRole = cluster.RolePortal
conf.Options().ClusterCIDR = "10.0.0.0/8"
ClusterGetTheme(router)
tempTheme, err := os.MkdirTemp("", "pp-theme-cidr-*")
assert.NoError(t, err)
defer func() { _ = os.RemoveAll(tempTheme) }()
conf.SetThemePath(tempTheme)
assert.NoError(t, os.WriteFile(filepath.Join(tempTheme, "app.js"), []byte("console.log('ok')\n"), fs.ModeFile))
assert.NoError(t, os.WriteFile(filepath.Join(tempTheme, "style.css"), []byte("body{}\n"), fs.ModeFile))
req := httptest.NewRequest(http.MethodGet, "/api/v1/cluster/theme", nil)
// Simulate request from 10.1.2.3
req.RemoteAddr = "10.1.2.3:12345"
w := httptest.NewRecorder()
app.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, header.ContentTypeZip, w.Header().Get(header.ContentType))
})
}