mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 04:14:39 +03:00
Improve caching, HTTP headers and URL handling (#3594)
* Fix relative URLs * Improve login base URL and redirects * Prevent duplicate customlocales requests * Improve UI base URL handling * Improve UI embedding * Improve CSP header * Add Cache-Control headers to all responses * Improve CORS responses * Improve authentication handler * Add back media timestamp suffixes * Fix default image handling * Add default param to other image URLs
This commit is contained in:
@@ -1,23 +1,25 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/stashapp/stash/internal/manager"
|
||||
"github.com/stashapp/stash/internal/manager/config"
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
"github.com/stashapp/stash/pkg/session"
|
||||
"github.com/stashapp/stash/pkg/utils"
|
||||
)
|
||||
|
||||
const loginRootDir = "login"
|
||||
const returnURLParam = "returnURL"
|
||||
|
||||
func getLoginPage(loginUIBox embed.FS) []byte {
|
||||
data, err := loginUIBox.ReadFile(loginRootDir + "/login.html")
|
||||
func getLoginPage(loginUIBox fs.FS) []byte {
|
||||
data, err := fs.ReadFile(loginUIBox, "login.html")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -29,36 +31,53 @@ type loginTemplateData struct {
|
||||
Error string
|
||||
}
|
||||
|
||||
func redirectToLogin(loginUIBox embed.FS, w http.ResponseWriter, returnURL string, loginError string) {
|
||||
data := getLoginPage(loginUIBox)
|
||||
templ, err := template.New("Login").Parse(string(data))
|
||||
func serveLoginPage(loginUIBox fs.FS, w http.ResponseWriter, r *http.Request, returnURL string, loginError string) {
|
||||
loginPage := string(getLoginPage(loginUIBox))
|
||||
prefix := getProxyPrefix(r)
|
||||
loginPage = strings.ReplaceAll(loginPage, "/%BASE_URL%", prefix)
|
||||
|
||||
templ, err := template.New("Login").Parse(loginPage)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("error: %s", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
err = templ.Execute(w, loginTemplateData{URL: returnURL, Error: loginError})
|
||||
buffer := bytes.Buffer{}
|
||||
err = templ.Execute(&buffer, loginTemplateData{URL: returnURL, Error: loginError})
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("error: %s", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
setPageSecurityHeaders(w, r)
|
||||
|
||||
utils.ServeStaticContent(w, r, buffer.Bytes())
|
||||
}
|
||||
|
||||
func getLoginHandler(loginUIBox embed.FS) http.HandlerFunc {
|
||||
func handleLogin(loginUIBox fs.FS) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
returnURL := r.URL.Query().Get(returnURLParam)
|
||||
|
||||
if !config.GetInstance().HasCredentials() {
|
||||
http.Redirect(w, r, "/", http.StatusFound)
|
||||
if returnURL != "" {
|
||||
http.Redirect(w, r, returnURL, http.StatusFound)
|
||||
} else {
|
||||
prefix := getProxyPrefix(r)
|
||||
http.Redirect(w, r, prefix+"/", http.StatusFound)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
redirectToLogin(loginUIBox, w, r.URL.Query().Get(returnURLParam), "")
|
||||
serveLoginPage(loginUIBox, w, r, returnURL, "")
|
||||
}
|
||||
}
|
||||
|
||||
func handleLogin(loginUIBox embed.FS) http.HandlerFunc {
|
||||
func handleLoginPost(loginUIBox fs.FS) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
url := r.FormValue(returnURLParam)
|
||||
if url == "" {
|
||||
url = "/"
|
||||
url = getProxyPrefix(r) + "/"
|
||||
}
|
||||
|
||||
err := manager.GetInstance().SessionStore.Login(w, r)
|
||||
@@ -70,8 +89,8 @@ func handleLogin(loginUIBox embed.FS) http.HandlerFunc {
|
||||
var invalidCredentialsError *session.InvalidCredentialsError
|
||||
|
||||
if errors.As(err, &invalidCredentialsError) {
|
||||
// redirect back to the login page with an error
|
||||
redirectToLogin(loginUIBox, w, url, "Username or password is invalid")
|
||||
// serve login page with an error
|
||||
serveLoginPage(loginUIBox, w, r, url, "Username or password is invalid")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -84,7 +103,7 @@ func handleLogin(loginUIBox embed.FS) http.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
func handleLogout(loginUIBox embed.FS) http.HandlerFunc {
|
||||
func handleLogout() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if err := manager.GetInstance().SessionStore.Logout(w, r); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@@ -92,6 +111,11 @@ func handleLogout(loginUIBox embed.FS) http.HandlerFunc {
|
||||
}
|
||||
|
||||
// redirect to the login page if credentials are required
|
||||
getLoginHandler(loginUIBox)(w, r)
|
||||
prefix := getProxyPrefix(r)
|
||||
if config.GetInstance().HasCredentials() {
|
||||
http.Redirect(w, r, prefix+loginEndpoint, http.StatusFound)
|
||||
} else {
|
||||
http.Redirect(w, r, prefix+"/", http.StatusFound)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user