mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 04:14:39 +03:00
Plugin hooks (#1452)
* Refactor session and plugin code * Add context to job tasks * Show hooks in plugins page * Refactor session management
This commit is contained in:
@@ -29,6 +29,7 @@ import (
|
||||
"github.com/stashapp/stash/pkg/manager/config"
|
||||
"github.com/stashapp/stash/pkg/manager/paths"
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
"github.com/stashapp/stash/pkg/session"
|
||||
"github.com/stashapp/stash/pkg/utils"
|
||||
)
|
||||
|
||||
@@ -41,11 +42,6 @@ var uiBox *packr.Box
|
||||
//var legacyUiBox *packr.Box
|
||||
var loginUIBox *packr.Box
|
||||
|
||||
const (
|
||||
ApiKeyHeader = "ApiKey"
|
||||
ApiKeyParameter = "apikey"
|
||||
)
|
||||
|
||||
func allowUnauthenticated(r *http.Request) bool {
|
||||
return strings.HasPrefix(r.URL.Path, "/login") || r.URL.Path == "/css"
|
||||
}
|
||||
@@ -53,44 +49,26 @@ func allowUnauthenticated(r *http.Request) bool {
|
||||
func authenticateHandler() func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
c := config.GetInstance()
|
||||
ctx := r.Context()
|
||||
|
||||
// translate api key into current user, if present
|
||||
userID := ""
|
||||
apiKey := r.Header.Get(ApiKeyHeader)
|
||||
var err error
|
||||
|
||||
// try getting the api key as a query parameter
|
||||
if apiKey == "" {
|
||||
apiKey = r.URL.Query().Get(ApiKeyParameter)
|
||||
}
|
||||
|
||||
if apiKey != "" {
|
||||
// match against configured API and set userID to the
|
||||
// configured username. In future, we'll want to
|
||||
// get the username from the key.
|
||||
if c.GetAPIKey() != apiKey {
|
||||
w.Header().Add("WWW-Authenticate", `FormBased`)
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
userID, err := manager.GetInstance().SessionStore.Authenticate(w, r)
|
||||
if err != nil {
|
||||
if err != session.ErrUnauthorized {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
_, err = w.Write([]byte(err.Error()))
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
userID = c.GetUsername()
|
||||
} else {
|
||||
// handle session
|
||||
userID, err = getSessionUserID(w, r)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
_, err = w.Write([]byte(err.Error()))
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
}
|
||||
// unauthorized error
|
||||
w.Header().Add("WWW-Authenticate", `FormBased`)
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
c := config.GetInstance()
|
||||
ctx := r.Context()
|
||||
|
||||
// handle redirect if no user and user is required
|
||||
if userID == "" && c.HasCredentials() && !allowUnauthenticated(r) {
|
||||
// if we don't have a userID, then redirect
|
||||
@@ -112,7 +90,7 @@ func authenticateHandler() func(http.Handler) http.Handler {
|
||||
return
|
||||
}
|
||||
|
||||
ctx = context.WithValue(ctx, ContextUser, userID)
|
||||
ctx = session.SetCurrentUserID(ctx, userID)
|
||||
|
||||
r = r.WithContext(ctx)
|
||||
|
||||
@@ -121,6 +99,16 @@ func authenticateHandler() func(http.Handler) http.Handler {
|
||||
}
|
||||
}
|
||||
|
||||
func visitedPluginHandler() func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// get the visited plugins and set them in the context
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const loginEndPoint = "/login"
|
||||
|
||||
func Start() {
|
||||
@@ -128,13 +116,15 @@ func Start() {
|
||||
//legacyUiBox = packr.New("UI Box", "../../ui/v1/dist/stash-frontend")
|
||||
loginUIBox = packr.New("Login UI Box", "../../ui/login")
|
||||
|
||||
initSessionStore()
|
||||
initialiseImages()
|
||||
|
||||
r := chi.NewRouter()
|
||||
|
||||
r.Use(middleware.Heartbeat("/healthz"))
|
||||
r.Use(authenticateHandler())
|
||||
visitedPluginHandler := manager.GetInstance().SessionStore.VisitedPluginHandler()
|
||||
r.Use(visitedPluginHandler)
|
||||
|
||||
r.Use(middleware.Recoverer)
|
||||
|
||||
c := config.GetInstance()
|
||||
@@ -155,8 +145,10 @@ func Start() {
|
||||
}
|
||||
|
||||
txnManager := manager.GetInstance().TxnManager
|
||||
pluginCache := manager.GetInstance().PluginCache
|
||||
resolver := &Resolver{
|
||||
txnManager: txnManager,
|
||||
txnManager: txnManager,
|
||||
hookExecutor: pluginCache,
|
||||
}
|
||||
|
||||
gqlSrv := gqlHandler.New(models.NewExecutableSchema(models.Config{Resolvers: resolver}))
|
||||
@@ -184,7 +176,8 @@ func Start() {
|
||||
}
|
||||
|
||||
// register GQL handler with plugin cache
|
||||
manager.GetInstance().PluginCache.RegisterGQLHandler(gqlHandlerFunc)
|
||||
// chain the visited plugin handler
|
||||
manager.GetInstance().PluginCache.RegisterGQLHandler(visitedPluginHandler(http.HandlerFunc(gqlHandlerFunc)))
|
||||
|
||||
r.HandleFunc("/graphql", gqlHandlerFunc)
|
||||
r.HandleFunc("/playground", gqlPlayground.Handler("GraphQL playground", "/graphql"))
|
||||
@@ -358,15 +351,6 @@ func makeTLSConfig() *tls.Config {
|
||||
return tlsConfig
|
||||
}
|
||||
|
||||
func HasTLSConfig() bool {
|
||||
ret, _ := utils.FileExists(paths.GetSSLCert())
|
||||
if ret {
|
||||
ret, _ = utils.FileExists(paths.GetSSLKey())
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
type contextKey struct {
|
||||
name string
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user