diff --git a/bootstrap/loader.go b/bootstrap/loader.go new file mode 100644 index 0000000..6dcfeec --- /dev/null +++ b/bootstrap/loader.go @@ -0,0 +1,30 @@ +package bootstrap + +import ( + "encoding/json" + "fmt" + "os" + + "synlotto-website/models" +) + +type AppState struct { + Config *models.Config +} + +func LoadAppState(configPath string) (*AppState, error) { + file, err := os.Open(configPath) + if err != nil { + return nil, fmt.Errorf("open config: %w", err) + } + defer file.Close() + + var config models.Config + if err := json.NewDecoder(file).Decode(&config); err != nil { + return nil, fmt.Errorf("decode config: %w", err) + } + + return &AppState{ + Config: &config, + }, nil +} diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..1b8d5d8 --- /dev/null +++ b/config/config.go @@ -0,0 +1,22 @@ +package config + +import ( + "sync" + + "synlotto-website/models" +) + +var ( + appConfig *models.Config + once sync.Once +) + +func Init(config *models.Config) { + once.Do(func() { + appConfig = config + }) +} + +func Get() *models.Config { + return appConfig +} diff --git a/logging/config.go b/logging/config.go new file mode 100644 index 0000000..c4b1022 --- /dev/null +++ b/logging/config.go @@ -0,0 +1,24 @@ +package logging + +import ( + "encoding/json" + "log" + + "synlotto-website/models" +) + +func LogConfig(config *models.Config) { + safeConfig := *config + safeConfig.CSRF.CSRFKey = "[REDACTED]" + safeConfig.Session.SessionAuthKey = "[REDACTED]" + safeConfig.Session.SessionEncryptionKey = "[REDACTED]" + + cfg, err := json.MarshalIndent(safeConfig, "", " ") + if err != nil { + log.Println("Failed to log config:", err) + return + } + + log.Println("App starting with config:") + log.Println(string(cfg)) +} diff --git a/logging/messages.go b/logging/messages.go new file mode 100644 index 0000000..1a7cee4 --- /dev/null +++ b/logging/messages.go @@ -0,0 +1,13 @@ +package logging + +import ( + "log" +) + +func Info(msg string, args ...any) { + log.Printf("[INFO] "+msg, args...) +} + +func Error(msg string, args ...any) { + log.Printf("[ERROR] "+msg, args...) +} diff --git a/main.go b/main.go index 6794f29..a0a3ed7 100644 --- a/main.go +++ b/main.go @@ -3,8 +3,11 @@ package main import ( "log" "net/http" + "synlotto-website/bootstrap" + "synlotto-website/config" "synlotto-website/handlers" "synlotto-website/helpers" + "synlotto-website/logging" "synlotto-website/middleware" "synlotto-website/models" "synlotto-website/routes" @@ -14,11 +17,16 @@ import ( ) func main() { + appState, err := bootstrap.LoadAppState("config/config.json") + if err != nil { + logging.Error("Failed to load app state: %v", err) + } + config.Init(appState.Config) + logging.LogConfig(appState.Config) + db := storage.InitDB("synlotto.db") models.SetDB(db) // Should be in storage not models. - var isProduction = false - csrfMiddleware := csrf.Protect( []byte("abcdefghijklmnopqrstuvwx12345678"), // TodO: Make Global csrf.Secure(true), @@ -35,7 +43,7 @@ func main() { mux.HandleFunc("/", handlers.Home(db)) wrapped := helpers.RateLimit(csrfMiddleware(mux)) - wrapped = middleware.EnforceHTTPS(wrapped, isProduction) + wrapped = middleware.EnforceHTTPS(wrapped, appState.Config.HttpServer.ProductionMode) wrapped = middleware.SecureHeaders(wrapped) wrapped = middleware.Recover(wrapped) diff --git a/models/config.go b/models/config.go new file mode 100644 index 0000000..5659594 --- /dev/null +++ b/models/config.go @@ -0,0 +1,19 @@ +package models + +type Config struct { + HttpServer struct { + Port int `json:"port"` + Address string `json:"address"` + ProductionMode bool `json:"productionMode"` + } `json:"httpServer"` + + CSRF struct { + CSRFKey string `json:"csrfKey"` + } `json:"csrf"` + + Session struct { + SessionAuthKey string `json:"authKey"` + SessionEncryptionKey string `json:"encryptionKey"` + SessionName string `json:"sessionName"` + } `json:"session"` +}