package bootstrap import ( "bytes" "crypto/rand" "encoding/base64" "encoding/gob" "fmt" "net/http" "os" "time" sessionHandlers "synlotto-website/handlers/session" sessionHelpers "synlotto-website/helpers/session" "synlotto-website/logging" "synlotto-website/models" "github.com/gorilla/sessions" ) var ( sessionStore *sessions.CookieStore Name string authKey []byte encryptKey []byte ) func InitSession(cfg *models.Config) error { gob.Register(time.Time{}) authPath := cfg.Session.AuthKeyPath encPath := cfg.Session.EncryptionKeyPath if _, err := os.Stat(authPath); os.IsNotExist(err) { logging.Info("⚠️ Auth key not found, creating: %s", authPath) key, err := generateRandomBytes(32) if err != nil { return err } encoded := sessionHelpers.EncodeKey(key) err = os.WriteFile(authPath, []byte(encoded), 0600) if err != nil { return err } } if _, err := os.Stat(encPath); os.IsNotExist(err) { logging.Info("⚠️ Encryption key not found, creating: %s", encPath) key, err := generateRandomBytes(32) if err != nil { return err } encoded := sessionHelpers.EncodeKey(key) err = os.WriteFile(encPath, []byte(encoded), 0600) if err != nil { return err } } return loadSessionKeys( authPath, encPath, cfg.Session.Name, cfg.HttpServer.ProductionMode, ) } func generateRandomBytes(length int) ([]byte, error) { b := make([]byte, length) _, err := rand.Read(b) if err != nil { logging.Error("failed to generate random bytes: %w", err) return nil, err } return b, nil } func loadSessionKeys(authPath, encryptionPath, name string, isProduction bool) error { var err error rawAuth, err := os.ReadFile(authPath) if err != nil { return fmt.Errorf("error reading auth key: %w", err) } authKey, err = base64.StdEncoding.DecodeString(string(bytes.TrimSpace(rawAuth))) if err != nil { return fmt.Errorf("error decoding auth key: %w", err) } rawEnc, err := os.ReadFile(encryptionPath) if err != nil { return fmt.Errorf("error reading encryption key: %w", err) } encryptKey, err = base64.StdEncoding.DecodeString(string(bytes.TrimSpace(rawEnc))) if err != nil { return fmt.Errorf("error decoding encryption key: %w", err) } if len(authKey) != 32 || len(encryptKey) != 32 { return fmt.Errorf("auth and encryption keys must be 32 bytes each (got auth=%d, enc=%d)", len(authKey), len(encryptKey)) } sessionHandlers.SessionStore = sessions.NewCookieStore(authKey, encryptKey) sessionHandlers.SessionStore.Options = &sessions.Options{ Path: "/", MaxAge: 86400, HttpOnly: true, Secure: isProduction, SameSite: http.SameSiteLaxMode, } sessionHandlers.Name = name return nil }