refactor: move BuildS5TusApi and export middlewares to break import cycle
This commit is contained in:
parent
92cddb40c3
commit
55f515157d
|
@ -21,8 +21,8 @@ func AdaptMiddleware(mid func(http.Handler) http.Handler) JapeMiddlewareFunc {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// proxyMiddleware creates a new HTTP middleware for handling X-Forwarded-For headers.
|
// ProxyMiddleware creates a new HTTP middleware for handling X-Forwarded-For headers.
|
||||||
func proxyMiddleware(next http.Handler) http.Handler {
|
func ProxyMiddleware(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
|
if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
|
||||||
ips := strings.Split(xff, ", ")
|
ips := strings.Split(xff, ", ")
|
||||||
|
|
|
@ -5,11 +5,8 @@ import (
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
"fmt"
|
"fmt"
|
||||||
"git.lumeweb.com/LumeWeb/portal/account"
|
"git.lumeweb.com/LumeWeb/portal/account"
|
||||||
"git.lumeweb.com/LumeWeb/portal/storage"
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
"go.sia.tech/jape"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -19,8 +16,8 @@ const (
|
||||||
S5AuthQueryParam = "auth_token"
|
S5AuthQueryParam = "auth_token"
|
||||||
)
|
)
|
||||||
|
|
||||||
func findAuthToken(r *http.Request) string {
|
func FindAuthToken(r *http.Request) string {
|
||||||
authHeader := parseAuthTokenHeader(r.Header)
|
authHeader := ParseAuthTokenHeader(r.Header)
|
||||||
|
|
||||||
if authHeader != "" {
|
if authHeader != "" {
|
||||||
return authHeader
|
return authHeader
|
||||||
|
@ -35,7 +32,7 @@ func findAuthToken(r *http.Request) string {
|
||||||
return r.FormValue(S5AuthQueryParam)
|
return r.FormValue(S5AuthQueryParam)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseAuthTokenHeader(headers http.Header) string {
|
func ParseAuthTokenHeader(headers http.Header) string {
|
||||||
authHeader := headers.Get("Authorization")
|
authHeader := headers.Get("Authorization")
|
||||||
if authHeader == "" {
|
if authHeader == "" {
|
||||||
return ""
|
return ""
|
||||||
|
@ -49,7 +46,7 @@ func parseAuthTokenHeader(headers http.Header) string {
|
||||||
func AuthMiddleware(identity ed25519.PrivateKey, accounts *account.AccountServiceImpl) func(http.Handler) http.Handler {
|
func AuthMiddleware(identity ed25519.PrivateKey, accounts *account.AccountServiceImpl) func(http.Handler) http.Handler {
|
||||||
return func(next http.Handler) http.Handler {
|
return func(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
authToken := findAuthToken(r)
|
authToken := FindAuthToken(r)
|
||||||
|
|
||||||
if authToken == "" {
|
if authToken == "" {
|
||||||
http.Error(w, "Invalid JWT", http.StatusUnauthorized)
|
http.Error(w, "Invalid JWT", http.StatusUnauthorized)
|
||||||
|
@ -109,64 +106,3 @@ func AuthMiddleware(identity ed25519.PrivateKey, accounts *account.AccountServic
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type tusJwtResponseWriter struct {
|
|
||||||
http.ResponseWriter
|
|
||||||
req *http.Request
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *tusJwtResponseWriter) WriteHeader(statusCode int) {
|
|
||||||
// Check if this is the specific route and status
|
|
||||||
if statusCode == http.StatusCreated {
|
|
||||||
location := w.Header().Get("Location")
|
|
||||||
authToken := parseAuthTokenHeader(w.req.Header)
|
|
||||||
|
|
||||||
if authToken != "" && location != "" {
|
|
||||||
|
|
||||||
parsedUrl, _ := url.Parse(location)
|
|
||||||
|
|
||||||
query := parsedUrl.Query()
|
|
||||||
query.Set("auth_token", authToken)
|
|
||||||
parsedUrl.RawQuery = query.Encode()
|
|
||||||
|
|
||||||
w.Header().Set("Location", parsedUrl.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
w.ResponseWriter.WriteHeader(statusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BuildS5TusApi(identity ed25519.PrivateKey, accounts *account.AccountServiceImpl, storage *storage.StorageServiceImpl) jape.Handler {
|
|
||||||
// Create a jape.Handler for your tusHandler
|
|
||||||
tusJapeHandler := func(c jape.Context) {
|
|
||||||
tusHandler := storage.Tus()
|
|
||||||
tusHandler.ServeHTTP(c.ResponseWriter, c.Request)
|
|
||||||
}
|
|
||||||
|
|
||||||
protocolMiddleware := func(next http.Handler) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
ctx := context.WithValue(r.Context(), "protocol", "s5")
|
|
||||||
next.ServeHTTP(w, r.WithContext(ctx))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
stripPrefix := func(next http.Handler) http.Handler {
|
|
||||||
return http.StripPrefix("/s5/upload/tus", next)
|
|
||||||
}
|
|
||||||
|
|
||||||
injectJwt := func(next http.Handler) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
res := w
|
|
||||||
if r.Method == http.MethodPost && r.URL.Path == "/s5/upload/tus" {
|
|
||||||
res = &tusJwtResponseWriter{ResponseWriter: w, req: r}
|
|
||||||
}
|
|
||||||
|
|
||||||
next.ServeHTTP(res, r)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply the middlewares to the tusJapeHandler
|
|
||||||
tusHandler := ApplyMiddlewares(tusJapeHandler, AuthMiddleware(identity, accounts), injectJwt, protocolMiddleware, stripPrefix, proxyMiddleware)
|
|
||||||
|
|
||||||
return tusHandler
|
|
||||||
}
|
|
||||||
|
|
65
api/s5.go
65
api/s5.go
|
@ -15,6 +15,8 @@ import (
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"go.sia.tech/jape"
|
"go.sia.tech/jape"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -91,7 +93,7 @@ func (s S5API) Stop(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRoutes(s *S5API) map[string]jape.Handler {
|
func getRoutes(s *S5API) map[string]jape.Handler {
|
||||||
tusHandler := middleware.BuildS5TusApi(s.identity, s.accounts, s.storage)
|
tusHandler := BuildS5TusApi(s.identity, s.accounts, s.storage)
|
||||||
|
|
||||||
return map[string]jape.Handler{
|
return map[string]jape.Handler{
|
||||||
// Account API
|
// Account API
|
||||||
|
@ -133,3 +135,64 @@ func getRoutes(s *S5API) map[string]jape.Handler {
|
||||||
"GET /s5/registry/subscription": middleware.ApplyMiddlewares(s.httpHandler.RegistrySubscription, middleware.AuthMiddleware(s.identity, s.accounts)),
|
"GET /s5/registry/subscription": middleware.ApplyMiddlewares(s.httpHandler.RegistrySubscription, middleware.AuthMiddleware(s.identity, s.accounts)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type s5TusJwtResponseWriter struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
req *http.Request
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *s5TusJwtResponseWriter) WriteHeader(statusCode int) {
|
||||||
|
// Check if this is the specific route and status
|
||||||
|
if statusCode == http.StatusCreated {
|
||||||
|
location := w.Header().Get("Location")
|
||||||
|
authToken := middleware.ParseAuthTokenHeader(w.req.Header)
|
||||||
|
|
||||||
|
if authToken != "" && location != "" {
|
||||||
|
|
||||||
|
parsedUrl, _ := url.Parse(location)
|
||||||
|
|
||||||
|
query := parsedUrl.Query()
|
||||||
|
query.Set("auth_token", authToken)
|
||||||
|
parsedUrl.RawQuery = query.Encode()
|
||||||
|
|
||||||
|
w.Header().Set("Location", parsedUrl.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
w.ResponseWriter.WriteHeader(statusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BuildS5TusApi(identity ed25519.PrivateKey, accounts *account.AccountServiceImpl, storage *storage.StorageServiceImpl) jape.Handler {
|
||||||
|
// Create a jape.Handler for your tusHandler
|
||||||
|
tusJapeHandler := func(c jape.Context) {
|
||||||
|
tusHandler := storage.Tus()
|
||||||
|
tusHandler.ServeHTTP(c.ResponseWriter, c.Request)
|
||||||
|
}
|
||||||
|
|
||||||
|
protocolMiddleware := func(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := context.WithValue(r.Context(), "protocol", "s5")
|
||||||
|
next.ServeHTTP(w, r.WithContext(ctx))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
stripPrefix := func(next http.Handler) http.Handler {
|
||||||
|
return http.StripPrefix("/s5/upload/tus", next)
|
||||||
|
}
|
||||||
|
|
||||||
|
injectJwt := func(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
res := w
|
||||||
|
if r.Method == http.MethodPost && r.URL.Path == "/s5/upload/tus" {
|
||||||
|
res = &s5TusJwtResponseWriter{ResponseWriter: w, req: r}
|
||||||
|
}
|
||||||
|
|
||||||
|
next.ServeHTTP(res, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the middlewares to the tusJapeHandler
|
||||||
|
tusHandler := middleware.ApplyMiddlewares(tusJapeHandler, middleware.AuthMiddleware(identity, accounts), injectJwt, protocolMiddleware, stripPrefix, middleware.ProxyMiddleware)
|
||||||
|
|
||||||
|
return tusHandler
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue