refactor: move resource handling to a controller

This commit is contained in:
Stavros
2025-08-26 12:22:10 +03:00
parent 03af18fd15
commit 645c555cf0
13 changed files with 86 additions and 71 deletions

3
.gitignore vendored
View File

@@ -24,3 +24,6 @@ tmp
# version files
internal/assets/version
# data directory
data

View File

@@ -33,6 +33,7 @@ var rootCmd = &cobra.Command{
conf.GoogleClientSecret = utils.GetSecret(conf.GoogleClientSecret, conf.GoogleClientSecretFile)
conf.GenericClientSecret = utils.GetSecret(conf.GenericClientSecret, conf.GenericClientSecretFile)
// Validate config
validator := validator.New()
err = validator.Struct(conf)

View File

@@ -19,6 +19,11 @@ export default defineConfig({
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ""),
},
"/resources": {
target: "http://tinyauth-backend:3000/resources",
changeOrigin: true,
rewrite: (path) => path.replace(/^\/resources/, ""),
},
},
allowedHosts: true,
},

View File

@@ -20,7 +20,6 @@ type Controller interface {
type Middleware interface {
Middleware() gin.HandlerFunc
Init() error
Name() string
}
type Service interface {
@@ -103,6 +102,7 @@ func (app *BootstrapApp) Setup() error {
err := ldapService.Init()
if err != nil {
log.Warn().Err(err).Msg("Failed to initialize LDAP service, continuing without LDAP")
ldapService = nil
}
}
@@ -120,6 +120,7 @@ func (app *BootstrapApp) Setup() error {
for _, svc := range services {
if svc != nil {
log.Debug().Str("service", fmt.Sprintf("%T", svc)).Msg("Initializing service")
err := svc.Init()
if err != nil {
return err
@@ -142,7 +143,13 @@ func (app *BootstrapApp) Setup() error {
// Create engine
engine := gin.New()
router := engine.Group("/api")
if config.Version != "development" {
gin.SetMode(gin.ReleaseMode)
}
router := engine.Group("/")
apiRouter := router.Group("/api")
// Create middlewares
var middlewares []Middleware
@@ -151,18 +158,16 @@ func (app *BootstrapApp) Setup() error {
Domain: domain,
}, authService, oauthBrokerService)
uiMiddleware := middleware.NewUIMiddleware(middleware.UIMiddlewareConfig{
ResourcesDir: app.Config.ResourcesDir,
})
uiMiddleware := middleware.NewUIMiddleware()
zerologMiddleware := middleware.NewZerologMiddleware()
middlewares = append(middlewares, contextMiddleware, uiMiddleware, zerologMiddleware)
for _, middleware := range middlewares {
log.Debug().Str("middleware", middleware.Name()).Msg("Initializing middleware")
log.Debug().Str("middleware", fmt.Sprintf("%T", middleware)).Msg("Initializing middleware")
err := middleware.Init()
if err != nil {
return fmt.Errorf("failed to initialize %s middleware: %w", middleware.Name(), err)
return fmt.Errorf("failed to initialize %s middleware: %T", middleware, err)
}
router.Use(middleware.Middleware())
}
@@ -177,24 +182,28 @@ func (app *BootstrapApp) Setup() error {
ForgotPasswordMessage: app.Config.FogotPasswordMessage,
BackgroundImage: app.Config.BackgroundImage,
OAuthAutoRedirect: app.Config.OAuthAutoRedirect,
}, router)
}, apiRouter)
oauthController := controller.NewOAuthController(controller.OAuthControllerConfig{
AppURL: app.Config.AppURL,
SecureCookie: app.Config.SecureCookie,
CSRFCookieName: csrfCookieName,
RedirectCookieName: redirectCookieName,
}, router, authService, oauthBrokerService)
}, apiRouter, authService, oauthBrokerService)
proxyController := controller.NewProxyController(controller.ProxyControllerConfig{
AppURL: app.Config.AppURL,
}, router, dockerService, authService)
}, apiRouter, dockerService, authService)
userController := controller.NewUserController(controller.UserControllerConfig{
Domain: domain,
}, router, authService)
}, apiRouter, authService)
healthController := controller.NewHealthController(router)
resourcesController := controller.NewResourcesController(controller.ResourcesControllerConfig{
ResourcesDir: app.Config.ResourcesDir,
}, router)
healthController := controller.NewHealthController(apiRouter)
// Setup routes
controller := []Controller{
@@ -203,10 +212,11 @@ func (app *BootstrapApp) Setup() error {
proxyController,
userController,
healthController,
resourcesController,
}
for _, ctrl := range controller {
log.Debug().Msgf("Setting up %T routes", ctrl)
log.Debug().Msgf("Setting up %T controller", ctrl)
ctrl.SetupRoutes()
}

View File

@@ -14,6 +14,7 @@ func NewHealthController(router *gin.RouterGroup) *HealthController {
func (controller *HealthController) SetupRoutes() {
controller.Router.GET("/health", controller.healthHandler)
controller.Router.HEAD("/health", controller.healthHandler)
}
func (controller *HealthController) healthHandler(c *gin.Context) {

View File

@@ -0,0 +1,32 @@
package controller
import (
"net/http"
"github.com/gin-gonic/gin"
)
type ResourcesControllerConfig struct {
ResourcesDir string
}
type ResourcesController struct {
Config ResourcesControllerConfig
Router *gin.RouterGroup
}
func NewResourcesController(config ResourcesControllerConfig, router *gin.RouterGroup) *ResourcesController {
return &ResourcesController{
Config: config,
Router: router,
}
}
func (controller *ResourcesController) SetupRoutes() {
controller.Router.GET("/resources/*resource", controller.resourcesHandler)
}
func (controller *ResourcesController) resourcesHandler(c *gin.Context) {
fileServer := http.StripPrefix("/resources", http.FileServer(http.Dir(controller.Config.ResourcesDir)))
fileServer.ServeHTTP(c.Writer, c.Request)
}

View File

@@ -32,10 +32,6 @@ func (m *ContextMiddleware) Init() error {
return nil
}
func (m *ContextMiddleware) Name() string {
return "ContextMiddleware"
}
func (m *ContextMiddleware) Middleware() gin.HandlerFunc {
return func(c *gin.Context) {
cookie, err := m.Auth.GetSessionCookie(c)

View File

@@ -4,28 +4,19 @@ import (
"io/fs"
"net/http"
"os"
"path/filepath"
"strings"
"tinyauth/internal/assets"
"github.com/gin-gonic/gin"
)
type UIMiddlewareConfig struct {
ResourcesDir string
}
type UIMiddleware struct {
Config UIMiddlewareConfig
UIFS fs.FS
UIFileServer http.Handler
ResourcesFileServer http.Handler
}
func NewUIMiddleware(config UIMiddlewareConfig) *UIMiddleware {
return &UIMiddleware{
Config: config,
}
func NewUIMiddleware() *UIMiddleware {
return &UIMiddleware{}
}
func (m *UIMiddleware) Init() error {
@@ -37,15 +28,10 @@ func (m *UIMiddleware) Init() error {
m.UIFS = ui
m.UIFileServer = http.FileServer(http.FS(ui))
m.ResourcesFileServer = http.FileServer(http.Dir(m.Config.ResourcesDir))
return nil
}
func (m *UIMiddleware) Name() string {
return "UIMiddleware"
}
func (m *UIMiddleware) Middleware() gin.HandlerFunc {
return func(c *gin.Context) {
switch strings.Split(c.Request.URL.Path, "/")[1] {
@@ -53,24 +39,7 @@ func (m *UIMiddleware) Middleware() gin.HandlerFunc {
c.Next()
return
case "resources":
requestFilePath := m.Config.ResourcesDir + strings.TrimPrefix(c.Request.URL.Path, "/resources/")
if !filepath.IsLocal(requestFilePath) {
c.Status(404)
c.Abort()
return
}
_, err := os.Stat(requestFilePath)
if os.IsNotExist(err) {
c.Status(404)
c.Abort()
return
}
m.ResourcesFileServer.ServeHTTP(c.Writer, c.Request)
c.Abort()
c.Next()
return
default:
_, err := fs.Stat(m.UIFS, strings.TrimPrefix(c.Request.URL.Path, "/"))

View File

@@ -26,10 +26,6 @@ func (m *ZerologMiddleware) Init() error {
return nil
}
func (m *ZerologMiddleware) Name() string {
return "ZerologMiddleware"
}
func (m *ZerologMiddleware) logPath(path string) bool {
for _, prefix := range loggerSkipPathsPrefix {
if strings.HasPrefix(path, prefix) {

View File

@@ -7,7 +7,6 @@ import (
"tinyauth/internal/config"
"github.com/gin-gonic/gin"
"github.com/traefik/paerser/parser"
"github.com/rs/zerolog"
)
@@ -39,17 +38,6 @@ func ParseFileToLine(content string) string {
return strings.Join(users, ",")
}
func GetLabels(labels map[string]string) (config.Labels, error) {
var labelsParsed config.Labels
err := parser.Decode(labels, &labelsParsed, "tinyauth", "tinyauth.users", "tinyauth.allowed", "tinyauth.headers", "tinyauth.domain", "tinyauth.basic", "tinyauth.oauth", "tinyauth.ip")
if err != nil {
return config.Labels{}, err
}
return labelsParsed, nil
}
func Filter[T any](slice []T, test func(T) bool) (res []T) {
for _, value := range slice {
if test(value) {

View File

@@ -2,8 +2,22 @@ package utils
import (
"strings"
"tinyauth/internal/config"
"github.com/traefik/paerser/parser"
)
func GetLabels(labels map[string]string) (config.Labels, error) {
var labelsParsed config.Labels
err := parser.Decode(labels, &labelsParsed, "tinyauth", "tinyauth.users", "tinyauth.allowed", "tinyauth.headers", "tinyauth.domain", "tinyauth.basic", "tinyauth.oauth", "tinyauth.ip")
if err != nil {
return config.Labels{}, err
}
return labelsParsed, nil
}
func ParseHeaders(headers []string) map[string]string {
headerMap := make(map[string]string)
for _, header := range headers {

View File

@@ -10,6 +10,6 @@ import (
)
func main() {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}).With().Timestamp().Logger().Level(zerolog.FatalLevel)
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}).With().Timestamp().Caller().Logger().Level(zerolog.FatalLevel)
cmd.Execute()
}