diff --git a/README.md b/README.md index 11a0fa2..c377388 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,31 @@ modify: true # Default permissions rules to apply at the paths. rules: [] +# Logging configuration +log: + # Logging format ('console', 'json'). Default is 'console'. + format: console + # Enable or disable colors. Default is 'true'. Only applied if format is 'console'. + colors: true + # Logging outputs. You can have more than one output. Default is only 'stderr'. + outputs: + - stderr + +# CORS configuration +cors: + # Whether or not CORS configuration should be applied. Default is 'false'. + enabled: true + credentials: true + allowed_headers: + - Depth + allowed_hosts: + - http://localhost:8080 + allowed_methods: + - GET + exposed_headers: + - Content-Length + - Content-Range + # The list of users. If users is empty, then there will be no authentication. users: # Example 'admin' user with plaintext password. @@ -108,20 +133,6 @@ users: # a regular expression. - regex: "^.+\.js$" modify: true - -# CORS configuration -cors: - enabled: true - credentials: true - allowed_headers: - - Depth - allowed_hosts: - - http://localhost:8080 - allowed_methods: - - GET - exposed_headers: - - Content-Length - - Content-Range ``` ### CORS diff --git a/cmd/root.go b/cmd/root.go index c6e27e6..449e237 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -13,19 +13,17 @@ import ( "github.com/hacdias/webdav/v5/lib" "github.com/spf13/cobra" "go.uber.org/zap" - "go.uber.org/zap/zapcore" ) func init() { flags := rootCmd.Flags() flags.StringP("config", "c", "", "config file path") + flags.StringP("address", "a", lib.DefaultAddress, "address to listen on") + flags.IntP("port", "p", lib.DefaultPort, "port to listen on") flags.BoolP("tls", "t", lib.DefaultTLS, "enable TLS") flags.String("cert", lib.DefaultCert, "path to TLS certificate") flags.String("key", lib.DefaultKey, "path to TLS key") - flags.StringP("address", "a", lib.DefaultAddress, "address to listen on") - flags.IntP("port", "p", lib.DefaultPort, "port to listen on") flags.StringP("prefix", "P", lib.DefaultPrefix, "URL path prefix") - flags.String("log_format", lib.DefaultLogFormat, "logging format") } var rootCmd = &cobra.Command{ @@ -57,14 +55,15 @@ set WD_CERT.`, return err } - // Create HTTP handler from the config - handler, err := lib.NewHandler(cfg) + // Setup the logger based on the configuration + logger, err := cfg.GetLogger() if err != nil { return err } + zap.ReplaceGlobals(logger) - // Setup the logger based on the configuration - err = setupLogger(cfg) + // Create HTTP handler from the config + handler, err := lib.NewHandler(cfg) if err != nil { return err } @@ -126,19 +125,3 @@ func getListener(cfg *lib.Config) (net.Listener, error) { return net.Listen(network, address) } - -func setupLogger(cfg *lib.Config) error { - loggerConfig := zap.NewProductionConfig() - loggerConfig.DisableCaller = true - if cfg.Debug { - loggerConfig.Level = zap.NewAtomicLevelAt(zap.DebugLevel) - } - loggerConfig.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder - loggerConfig.Encoding = cfg.LogFormat - logger, err := loggerConfig.Build() - if err != nil { - return err - } - zap.ReplaceGlobals(logger) - return nil -} diff --git a/lib/config.go b/lib/config.go index 5099791..48eef1b 100644 --- a/lib/config.go +++ b/lib/config.go @@ -10,20 +10,16 @@ import ( "github.com/spf13/pflag" "github.com/spf13/viper" "go.uber.org/zap" + "go.uber.org/zap/zapcore" ) const ( - DefaultDirectory = "." - DefaultModify = false - DefaultDebug = false - DefaultNoSniff = false - DefaultTLS = false - DefaultCert = "cert.pem" - DefaultKey = "key.pem" - DefaultAddress = "0.0.0.0" - DefaultPort = 6065 - DefaultPrefix = "/" - DefaultLogFormat = "console" + DefaultTLS = false + DefaultCert = "cert.pem" + DefaultKey = "key.pem" + DefaultAddress = "0.0.0.0" + DefaultPort = 6065 + DefaultPrefix = "/" ) type Config struct { @@ -36,7 +32,7 @@ type Config struct { Key string Prefix string NoSniff bool - LogFormat string `mapstructure:"log_format"` + Log Log CORS CORS Users []User } @@ -50,11 +46,6 @@ func ParseConfig(filename string, flags *pflag.FlagSet) (*Config, error) { if err != nil { return nil, err } - - err = v.BindPFlag("LogFormat", flags.Lookup("log_format")) - if err != nil { - return nil, err - } } // Configuration file settings @@ -74,19 +65,21 @@ func ParseConfig(filename string, flags *pflag.FlagSet) (*Config, error) { // empty or false. // Defaults shared with flags - v.SetDefault("Directory", DefaultDirectory) - v.SetDefault("Modify", DefaultModify) - v.SetDefault("Debug", DefaultDebug) - v.SetDefault("NoSniff", DefaultNoSniff) v.SetDefault("TLS", DefaultTLS) v.SetDefault("Cert", DefaultCert) v.SetDefault("Key", DefaultKey) v.SetDefault("Address", DefaultAddress) v.SetDefault("Port", DefaultPort) v.SetDefault("Prefix", DefaultPrefix) - v.SetDefault("Log_Format", DefaultLogFormat) // Other defaults + v.SetDefault("Directory", ".") + v.SetDefault("Modify", false) + v.SetDefault("Debug", false) + v.SetDefault("NoSniff", false) + v.SetDefault("Log.Format", "console") + v.SetDefault("Log.Outputs", []string{"stderr"}) + v.SetDefault("Log.Colors", true) v.SetDefault("CORS.Allowed_Headers", []string{"*"}) v.SetDefault("CORS.Allowed_Hosts", []string{"*"}) v.SetDefault("CORS.Allowed_Methods", []string{"*"}) @@ -135,10 +128,6 @@ func ParseConfig(filename string, flags *pflag.FlagSet) (*Config, error) { func (c *Config) Validate() error { var err error - if len(c.Users) == 0 { - zap.L().Warn("unprotected config: no users have been set, so no authentication will be used") - } - c.Directory, err = filepath.Abs(c.Directory) if err != nil { return fmt.Errorf("invalid config: %w", err) @@ -179,6 +168,27 @@ func (c *Config) Validate() error { return nil } +func (cfg *Config) GetLogger() (*zap.Logger, error) { + loggerConfig := zap.NewProductionConfig() + loggerConfig.DisableCaller = true + if cfg.Debug { + loggerConfig.Level = zap.NewAtomicLevelAt(zap.DebugLevel) + } + if cfg.Log.Colors && cfg.Log.Format != "json" { + loggerConfig.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder + } + loggerConfig.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder + loggerConfig.Encoding = cfg.Log.Format + loggerConfig.OutputPaths = cfg.Log.Outputs + return loggerConfig.Build() +} + +type Log struct { + Format string + Colors bool + Outputs []string +} + type CORS struct { Enabled bool Credentials bool diff --git a/lib/config_test.go b/lib/config_test.go index 7398f82..84c0df7 100644 --- a/lib/config_test.go +++ b/lib/config_test.go @@ -32,7 +32,9 @@ func TestConfigDefaults(t *testing.T) { require.EqualValues(t, DefaultAddress, cfg.Address) require.EqualValues(t, DefaultPort, cfg.Port) require.EqualValues(t, DefaultPrefix, cfg.Prefix) - require.EqualValues(t, DefaultLogFormat, cfg.LogFormat) + require.EqualValues(t, "console", cfg.Log.Format) + require.EqualValues(t, true, cfg.Log.Colors) + require.EqualValues(t, []string{"stderr"}, cfg.Log.Outputs) dir, err := os.Getwd() require.NoError(t, err) diff --git a/lib/handler.go b/lib/handler.go index f69005a..35c0825 100644 --- a/lib/handler.go +++ b/lib/handler.go @@ -61,6 +61,10 @@ func NewHandler(c *Config) (http.Handler, error) { }).Handler(h), nil } + if len(c.Users) == 0 { + zap.L().Warn("unprotected config: no users have been set, so no authentication will be used") + } + return h, nil }