Files

80 lines
2.5 KiB
Go
Raw Permalink Normal View History

package handler
import (
"context"
"net/http"
"strings"
"img_infinite_canvas/internal/domain/design"
)
type bearerAuthenticator interface {
UserIDFromBearer(ctx context.Context, authorization string) (string, bool)
}
func UserContextMiddleware(authenticator bearerAuthenticator) func(http.HandlerFunc) http.HandlerFunc {
return func(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
userID := r.Header.Get("X-User-Id")
authenticated := false
if authenticator != nil {
if tokenUserID, ok := userIDFromRequestAuth(r.Context(), r, authenticator); ok {
userID = tokenUserID
authenticated = true
}
}
if requiresAuthenticatedUser(r) && !authenticated {
writeAuthRequired(w)
return
}
ctx := design.ContextWithUserID(r.Context(), userID)
next(w, r.WithContext(ctx))
}
}
}
func userIDFromRequestAuth(ctx context.Context, r *http.Request, authenticator bearerAuthenticator) (string, bool) {
if tokenUserID, ok := authenticator.UserIDFromBearer(ctx, r.Header.Get("Authorization")); ok {
return tokenUserID, true
}
if token := strings.TrimSpace(r.Header.Get("token")); token != "" {
if tokenUserID, ok := authenticator.UserIDFromBearer(ctx, "Bearer "+token); ok {
return tokenUserID, true
}
}
if cookie, err := r.Cookie("usertoken"); err == nil && strings.TrimSpace(cookie.Value) != "" {
if tokenUserID, ok := authenticator.UserIDFromBearer(ctx, "Bearer "+cookie.Value); ok {
return tokenUserID, true
}
}
return "", false
}
func requiresAuthenticatedUser(r *http.Request) bool {
path := r.URL.Path
if !strings.HasPrefix(path, "/api/") {
return false
}
if strings.HasPrefix(path, "/api/auth/") || path == "/api/auth/options" || path == "/api/health" || path == "/api/dashboard" {
return false
}
return strings.HasPrefix(path, "/api/projects") ||
strings.HasPrefix(path, "/api/account") ||
strings.HasPrefix(path, "/api/assets") ||
strings.HasPrefix(path, "/api/generator/")
}
func writeAuthRequired(w http.ResponseWriter) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(http.StatusUnauthorized)
_, _ = w.Write([]byte(`{"error":"login required","errorCode":"auth.login_required","code":401}`))
}
func LegacyUserContextMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
userID := r.Header.Get("X-User-Id")
ctx := design.ContextWithUserID(r.Context(), userID)
next(w, r.WithContext(ctx))
}
}