This commit is contained in:
2026-04-23 21:56:59 +02:00
commit 7a11b5bbbf
17 changed files with 1710 additions and 0 deletions
+112
View File
@@ -0,0 +1,112 @@
package config
import (
"fmt"
"os"
"gopkg.in/yaml.v3"
)
// Config is the top-level server configuration.
type Config struct {
Server ServerConfig `yaml:"server"`
Auth AuthConfig `yaml:"auth"`
Storage StorageConfig `yaml:"storage"`
Users map[string]UserConfig `yaml:"users"`
TLS TLSConfig `yaml:"tls"`
Logging LoggingConfig `yaml:"logging"`
}
type ServerConfig struct {
Host string `yaml:"host"`
Port int `yaml:"port"`
// Base URL used in DAV responses (e.g. https://dav.example.com)
BaseURL string `yaml:"base_url"`
}
type AuthConfig struct {
// Realm shown in WWW-Authenticate header
Realm string `yaml:"realm"`
}
type StorageConfig struct {
// Root directory for all data
DataDir string `yaml:"data_dir"`
}
type UserConfig struct {
// bcrypt-hashed password (use `htpasswd -nB <user>`)
Password string `yaml:"password"`
DisplayName string `yaml:"display_name"`
Email string `yaml:"email"`
Calendars []string `yaml:"calendars"`
AddressBooks []string `yaml:"address_books"`
}
type TLSConfig struct {
Enabled bool `yaml:"enabled"`
CertFile string `yaml:"cert_file"`
KeyFile string `yaml:"key_file"`
}
type LoggingConfig struct {
Level string `yaml:"level"` // debug | info | warn | error
Format string `yaml:"format"` // text | json
}
// Load reads and parses a YAML config file.
func Load(path string) (*Config, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("reading config %q: %w", path, err)
}
cfg := &Config{}
if err := yaml.Unmarshal(data, cfg); err != nil {
return nil, fmt.Errorf("parsing config %q: %w", path, err)
}
cfg.applyDefaults()
return cfg, cfg.validate()
}
func (c *Config) applyDefaults() {
if c.Server.Host == "" {
c.Server.Host = "0.0.0.0"
}
if c.Server.Port == 0 {
c.Server.Port = 8080
}
if c.Server.BaseURL == "" {
scheme := "http"
if c.TLS.Enabled {
scheme = "https"
}
c.Server.BaseURL = fmt.Sprintf("%s://%s:%d", scheme, c.Server.Host, c.Server.Port)
}
if c.Auth.Realm == "" {
c.Auth.Realm = "DAV Server"
}
if c.Storage.DataDir == "" {
c.Storage.DataDir = "./data"
}
if c.Logging.Level == "" {
c.Logging.Level = "info"
}
if c.Logging.Format == "" {
c.Logging.Format = "text"
}
}
func (c *Config) validate() error {
if c.TLS.Enabled {
if c.TLS.CertFile == "" || c.TLS.KeyFile == "" {
return fmt.Errorf("tls.cert_file and tls.key_file are required when tls is enabled")
}
}
if len(c.Users) == 0 {
return fmt.Errorf("at least one user must be configured")
}
return nil
}