dropped fiber for std http + gorilla websocket
Session serialization will use gob encoding instead of json. Binary size will likely be reduced. General backend code refactoring.
This commit is contained in:
15
server/middleware/cors.go
Normal file
15
server/middleware/cors.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package middlewares
|
||||
|
||||
import "net/http"
|
||||
|
||||
// Middleware for applying CORS policy for ALL hosts and for
|
||||
// allowing ALL request headers.
|
||||
func CORS(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
|
||||
w.Header().Set("Access-Control-Allow-Headers", "*")
|
||||
w.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
@@ -2,10 +2,10 @@ package middlewares
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/marcopeocchi/yt-dlp-web-ui/server/config"
|
||||
)
|
||||
@@ -14,37 +14,49 @@ const (
|
||||
TOKEN_COOKIE_NAME = "jwt"
|
||||
)
|
||||
|
||||
var Authenticated = func(c *fiber.Ctx) error {
|
||||
if !config.Instance().GetConfig().RequireAuth {
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
cookie := c.Cookies(TOKEN_COOKIE_NAME)
|
||||
|
||||
if cookie == "" {
|
||||
return c.Status(fiber.StatusUnauthorized).SendString("invalid token")
|
||||
}
|
||||
|
||||
token, _ := jwt.Parse(cookie, func(t *jwt.Token) (interface{}, error) {
|
||||
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
|
||||
func Authenticated(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if !config.Instance().GetConfig().RequireAuth {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
return []byte(os.Getenv("JWT_SECRET")), nil
|
||||
})
|
||||
|
||||
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
|
||||
expiresAt, err := time.Parse(time.RFC3339, claims["expiresAt"].(string))
|
||||
cookie, err := r.Cookie(TOKEN_COOKIE_NAME)
|
||||
|
||||
if err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
http.Error(w, "invalid token", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if time.Now().After(expiresAt) {
|
||||
return c.Status(fiber.StatusBadRequest).SendString("expired token")
|
||||
if cookie == nil {
|
||||
http.Error(w, "invalid token", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
return c.Status(fiber.StatusUnauthorized).SendString("invalid token")
|
||||
}
|
||||
|
||||
return c.Next()
|
||||
token, _ := jwt.Parse(cookie.Value, func(t *jwt.Token) (interface{}, error) {
|
||||
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
|
||||
}
|
||||
return []byte(os.Getenv("JWTSECRET")), nil
|
||||
})
|
||||
|
||||
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
|
||||
expiresAt, err := time.Parse(time.RFC3339, claims["expiresAt"].(string))
|
||||
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if time.Now().After(expiresAt) {
|
||||
http.Error(w, "token expired", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
http.Error(w, "invalid token", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
93
server/middleware/spa_handler.go
Normal file
93
server/middleware/spa_handler.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"mime"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type SpaHandler struct {
|
||||
Entrypoint string
|
||||
Filesystem fs.FS
|
||||
routes []string
|
||||
}
|
||||
|
||||
func NewSpaHandler(index string, fs fs.FS) *SpaHandler {
|
||||
return &SpaHandler{
|
||||
Entrypoint: index,
|
||||
Filesystem: fs,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SpaHandler) AddClientRoute(route string) *SpaHandler {
|
||||
s.routes = append(s.routes, route)
|
||||
return s
|
||||
}
|
||||
|
||||
// Handler for serving a compiled react frontend
|
||||
// each client-side routes must be provided
|
||||
func (s *SpaHandler) Handler() http.HandlerFunc {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
http.Error(
|
||||
w,
|
||||
http.StatusText(http.StatusMethodNotAllowed),
|
||||
http.StatusMethodNotAllowed,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
path := filepath.Clean(r.URL.Path)
|
||||
|
||||
// basically all frontend routes are needed :/
|
||||
hasRoute := false
|
||||
for _, route := range s.routes {
|
||||
hasRoute = strings.HasPrefix(path, route)
|
||||
if hasRoute {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if path == "/" || hasRoute {
|
||||
path = s.Entrypoint
|
||||
}
|
||||
|
||||
path = strings.TrimPrefix(path, "/")
|
||||
|
||||
file, err := s.Filesystem.Open(path)
|
||||
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
http.Error(
|
||||
w,
|
||||
http.StatusText(http.StatusInternalServerError),
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
contentType := mime.TypeByExtension(filepath.Ext(path))
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
|
||||
if strings.HasPrefix(path, "assets/") {
|
||||
w.Header().Set("Cache-Control", "public, max-age=2592000")
|
||||
}
|
||||
|
||||
stat, err := file.Stat()
|
||||
if err == nil && stat.Size() > 0 {
|
||||
w.Header().Set("Content-Length", fmt.Sprintf("%d", stat.Size()))
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
io.Copy(w, file)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user