199 lines
5.1 KiB
Go
199 lines
5.1 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"crypto/subtle"
|
|
"os"
|
|
"strings"
|
|
|
|
"git.odit.services/lfk/document-server/docs" // Correct import path for docs
|
|
"git.odit.services/lfk/document-server/handlers"
|
|
"git.odit.services/lfk/document-server/models"
|
|
"git.odit.services/lfk/document-server/services"
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/gofiber/fiber/v2/middleware/cors"
|
|
"github.com/gofiber/fiber/v2/middleware/keyauth"
|
|
"github.com/gofiber/fiber/v2/middleware/requestid"
|
|
"github.com/gofiber/swagger"
|
|
"github.com/redis/go-redis/v9"
|
|
"github.com/spf13/viper"
|
|
"go.uber.org/zap"
|
|
"go.uber.org/zap/zapcore"
|
|
)
|
|
|
|
var (
|
|
config *models.Config
|
|
logger *zap.SugaredLogger
|
|
)
|
|
|
|
func validateAPIKey(c *fiber.Ctx, key string) (bool, error) {
|
|
hashedAPIKey := sha256.Sum256([]byte(config.APIKey))
|
|
hashedKey := sha256.Sum256([]byte(key))
|
|
|
|
if subtle.ConstantTimeCompare(hashedAPIKey[:], hashedKey[:]) == 1 {
|
|
return true, nil
|
|
}
|
|
return false, keyauth.ErrMissingOrMalformedAPIKey
|
|
}
|
|
|
|
func loadEnv() error {
|
|
|
|
viper.SetDefault("LOGLEVEL", "INFO")
|
|
viper.SetDefault("PRODUCION", false)
|
|
viper.SetDefault("PORT", "3000")
|
|
viper.SetDefault("APIKEY", "lfk")
|
|
viper.SetDefault("EVENTNAME", "Demo Event")
|
|
viper.SetDefault("CURRENCYSYMBOL", "€")
|
|
viper.SetDefault("CURRENCYIDENTIFIER", "EUR")
|
|
viper.SetDefault("CARD_SUBTITLE", "Runner Card")
|
|
viper.SetDefault("CARD_BARCODEFORMAT", "ean13")
|
|
viper.SetDefault("CARD_BARCODEPREFIX", "")
|
|
viper.SetDefault("SPONSORING_RECEIPTMINIMUM", 0)
|
|
viper.SetDefault("SPONSORING_DISCLAIMER", "Disclaimer")
|
|
viper.SetDefault("SPONSORING_BARCODEFORMAT", "code128")
|
|
viper.SetDefault("SPONSORING_BARCODEPREFIX", "")
|
|
viper.SetDefault("CERTIFICATE_FOOTER", "Footer")
|
|
viper.SetDefault("GOTENBERG_BASEURL", "")
|
|
viper.SetDefault("REDIS_ADDR", "")
|
|
viper.SetDefault("SEPA_BIC", "")
|
|
viper.SetDefault("SEPA_NAME", "")
|
|
viper.SetDefault("SEPA_IBAN", "")
|
|
|
|
// Load .env file
|
|
viper.SetConfigFile(".env")
|
|
|
|
// Load environment variables
|
|
viper.AutomaticEnv()
|
|
err := viper.ReadInConfig()
|
|
if err != nil {
|
|
logger.Warn("No .env file found")
|
|
}
|
|
|
|
// Unmarshal the config from file and env into the config struct
|
|
err = viper.Unmarshal(&config)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
logger.Infow("Loaded config", "config", &config)
|
|
|
|
return nil
|
|
}
|
|
|
|
func initLogger() error {
|
|
logLevel := os.Getenv("LOGLEVEL")
|
|
if logLevel == "" {
|
|
logLevel = "INFO"
|
|
}
|
|
|
|
var zapLogLevel zapcore.Level
|
|
err := zapLogLevel.UnmarshalText([]byte(strings.ToLower(logLevel)))
|
|
if err != nil {
|
|
zapLogLevel = zapcore.InfoLevel
|
|
}
|
|
|
|
zapConfig := zap.NewProductionConfig()
|
|
zapConfig.Level = zap.NewAtomicLevelAt(zapLogLevel)
|
|
zapLogger, err := zapConfig.Build()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer zapLogger.Sync()
|
|
logger = zapLogger.Sugar()
|
|
|
|
logger.Debug("Initialized logger")
|
|
|
|
return nil
|
|
}
|
|
|
|
// @title LfK Document Server API
|
|
// @description This is the API documentation for the LfK Document Server - a tool for pdf generation.
|
|
// @license.name CC BY-NC-SA 4.0
|
|
// @termsOfService https://lauf-fuer-kaya.de/datenschutz
|
|
// @contact.name ODIT.Services UG (haftungsbeschränkt)
|
|
// @contact.url https://odit.services
|
|
// @contact.email info@odit.services
|
|
// @securityDefinitions.apiKey ApiKeyAuth
|
|
// @in query
|
|
// @name key
|
|
func main() {
|
|
|
|
// Init the logger
|
|
err := initLogger()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
err = loadEnv()
|
|
if err != nil {
|
|
logger.Error(err)
|
|
return
|
|
}
|
|
|
|
var redisClient *redis.Client
|
|
if config.RedisAddr != "" {
|
|
logger.Infow("Using redis", "redisAddr", config.RedisAddr)
|
|
redisClient = redis.NewClient(&redis.Options{
|
|
Addr: config.RedisAddr,
|
|
})
|
|
}
|
|
|
|
barcodeGenerator := &services.DefaultBarcodeService{
|
|
RedisClient: redisClient,
|
|
Logger: logger.Named("DefaultBarcodeService"),
|
|
}
|
|
staticService := &services.DefaultStaticService{
|
|
Cache: make(map[string]string),
|
|
Logger: logger.Named("DefaultStaticService"),
|
|
}
|
|
handler := handlers.DefaultHandler{
|
|
Config: config,
|
|
BarcodeService: barcodeGenerator,
|
|
StaticService: staticService,
|
|
Templater: &services.DefaultTemplater{
|
|
BarcodeService: barcodeGenerator,
|
|
StaticService: staticService,
|
|
Logger: logger.Named("DefaultTemplater"),
|
|
},
|
|
Converter: &services.GotenbergConverter{
|
|
BaseUrl: config.GotenbergBaseUrl,
|
|
Logger: logger.Named("GotenbergConverter"),
|
|
},
|
|
Logger: logger.Named("DefaultHandler"),
|
|
}
|
|
logger.Debug("Initialized services")
|
|
|
|
// Create a new Fiber instance
|
|
app := fiber.New(fiber.Config{
|
|
Prefork: config.Prod,
|
|
})
|
|
|
|
app.Use(cors.New())
|
|
app.Use(requestid.New())
|
|
|
|
// Swagger documentation route
|
|
app.Get("/swagger/*", swagger.HandlerDefault)
|
|
|
|
v1 := app.Group("/v1")
|
|
|
|
pdfv1 := v1.Group("/pdfs")
|
|
pdfv1.Use(keyauth.New(keyauth.Config{
|
|
KeyLookup: "query:key",
|
|
Validator: validateAPIKey,
|
|
}))
|
|
|
|
pdfv1.Post("/contracts", handler.GenerateContract)
|
|
pdfv1.Post("/cards", handler.GenerateCard)
|
|
pdfv1.Post("/certificates", handler.GenerateCertificate)
|
|
|
|
v1.Get("/barcodes/:type/:content", handler.GenerateBarcode)
|
|
logger.Debug("Initialized routes")
|
|
|
|
app.Use(handler.NotFoundHandler)
|
|
docs.SwaggerInfo.BasePath = "/"
|
|
|
|
logger.Infow("Starting server", "port", config.Port)
|
|
logger.Error(app.Listen("0.0.0.0:" + config.Port))
|
|
}
|