100 lines
2.5 KiB
Go
100 lines
2.5 KiB
Go
package presences
|
|
|
|
import (
|
|
"context"
|
|
"crypto/subtle"
|
|
"crypto/tls"
|
|
"fmt"
|
|
"log"
|
|
"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)
|
|
|
|
switch {
|
|
case cfg.TLS.Cert != "" && cfg.TLS.Key != "":
|
|
return e.StartTLS(address, cfg.TLS.Cert, cfg.TLS.Key)
|
|
case cfg.TLS.Cert != "" && cfg.TLS.Key == "":
|
|
return fmt.Errorf("found TLS certificate but missing associated TLS private key")
|
|
case cfg.TLS.Cert == "" && cfg.TLS.Key != "":
|
|
return fmt.Errorf("found TLS private key but missing associated TLS certificate")
|
|
default:
|
|
log.Println("No TLS pair was provided. Generating self-signed pair.")
|
|
|
|
tlsPair, err := newTLSPair()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
server := &http.Server{
|
|
Addr: address,
|
|
Handler: e,
|
|
TLSConfig: &tls.Config{
|
|
Certificates: []tls.Certificate{tlsPair},
|
|
},
|
|
}
|
|
|
|
return server.ListenAndServeTLS("", "")
|
|
}
|
|
}
|
|
}
|