presences/server.go

75 lines
1.8 KiB
Go

package presences
import (
"context"
"crypto/subtle"
"fmt"
"net/http"
"git.agecem.com/bottin/bottin/v11"
"git.agecem.com/bottin/presences/ui"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
func RunUIServer(ctx context.Context, cfg Config, bottinClient *bottin.APIClient, dbClient *DBClient) error {
select {
case <-ctx.Done():
return ctx.Err()
default:
if bottinClient == nil {
return fmt.Errorf("nil bottin client")
}
if dbClient == nil {
return fmt.Errorf("nil dbClient")
}
if err := dbClient.Init(ctx); err != nil {
return err
}
e := echo.New()
r := ui.NewRenderer()
if r == nil {
return fmt.Errorf("nil renderer")
}
e.Renderer = r
e.Pre(middleware.AddTrailingSlash())
if len(cfg.UI.Credentials) == 0 {
return fmt.Errorf("UI.Credentials config file option of type map[string]string must contain at least one username-password key-value pair. Note that there is no flag or ENV counterpart, this must be done through a config file.")
}
e.Pre(middleware.BasicAuth(
func(username, password string, c echo.Context) (bool, error) {
rightPassword, userExists := cfg.UI.Credentials[username]
if !userExists {
return false, nil
}
passwordOK := subtle.ConstantTimeCompare([]byte(password), []byte(rightPassword)) == 1
return passwordOK, nil
}),
)
e.Group("/public/js/*").Use(middleware.StaticWithConfig(middleware.StaticConfig{
Root: "/js/",
Filesystem: http.FS(ui.JSFS()),
}))
e.GET("/", UIIndex(ctx, cfg))
e.GET("/nothing/", func(c echo.Context) error { return c.NoContent(http.StatusOK) })
e.GET("/decompte/", UICountPresences(ctx, cfg, dbClient))
e.POST("/scan/", UICreatePresence(ctx, cfg, bottinClient, dbClient))
address := fmt.Sprintf(":%d", cfg.Port)
return e.StartTLS(address, cfg.TLS.Cert, cfg.TLS.Key)
}
}