diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0307a77..a42298d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: fail-fast: false matrix: os: [ ubuntu-latest, macos-latest, windows-latest ] - go: [ '1.15' ] + go: [ '1.16' ] runs-on: ${{ matrix.os }} @@ -75,6 +75,7 @@ jobs: github_token: ${{ secrets.github_token }} goreleaser-check: + # goreleaser --rm-dist --skip-validate --skip-publish runs-on: ubuntu-latest steps: - name: checkout diff --git a/cmd/config.go b/cmd/config.go index 50ca8b9..e8ca28b 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -8,7 +8,7 @@ import ( "strconv" "strings" - "github.com/hacdias/webdav/v3/lib" + "github.com/hacdias/webdav/v4/lib" "github.com/spf13/pflag" v "github.com/spf13/viper" "golang.org/x/net/webdav" @@ -20,10 +20,10 @@ func parseRules(raw []interface{}, defaultModify bool) []*lib.Rule { for _, v := range raw { if r, ok := v.(map[interface{}]interface{}); ok { rule := &lib.Rule{ - Regex: false, - Allow: false, + Regex: false, + Allow: false, Modify: defaultModify, - Path: "", + Path: "", } if regex, ok := r["regex"].(bool); ok { @@ -196,7 +196,8 @@ func readConfig(flags *pflag.FlagSet) *lib.Config { Enabled: false, Credentials: false, }, - Users: map[string]*lib.User{}, + Users: map[string]*lib.User{}, + LogFormat: getOpt(flags, "log_format"), } rawRules := v.Get("rules") diff --git a/cmd/root.go b/cmd/root.go index c323c1f..c4cba1d 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,7 +1,6 @@ package cmd import ( - "fmt" "log" "net" "net/http" @@ -9,6 +8,8 @@ import ( "github.com/spf13/cobra" v "github.com/spf13/viper" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" ) var ( @@ -27,6 +28,7 @@ func init() { flags.StringP("address", "a", "0.0.0.0", "address to listen to") flags.StringP("port", "p", "0", "port to listen to") flags.StringP("prefix", "P", "/", "URL path prefix") + flags.String("log_format", "console", "logging format") } var rootCmd = &cobra.Command{ @@ -67,18 +69,31 @@ set WD_CERT.`, if err != nil { log.Fatal(err) } - + loggerConfig := zap.NewProductionConfig() + loggerConfig.DisableCaller = true + loggerConfig.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder + loggerConfig.Encoding = cfg.LogFormat + logger, err := loggerConfig.Build() + if err != nil { + // if we fail to configure proper logging, then the user has deliberately + // misconfigured the logger. Abort. + panic(err) + } + zap.ReplaceGlobals(logger) + defer func() { + _ = zap.L().Sync() + }() // Tell the user the port in which is listening. - fmt.Println("Listening on", listener.Addr().String()) + zap.L().Info("Listening", zap.String("address", listener.Addr().String())) // Starts the server. if getOptB(flags, "tls") { if err := http.ServeTLS(listener, cfg, getOpt(flags, "cert"), getOpt(flags, "key")); err != nil { - log.Fatal(err) + zap.L().Fatal("shutting server", zap.Error(err)) } } else { if err := http.Serve(listener, cfg); err != nil { - log.Fatal(err) + zap.L().Fatal("shutting server", zap.Error(err)) } } }, diff --git a/go.mod b/go.mod index 5870d85..d99e212 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/hacdias/webdav/v3 +module github.com/hacdias/webdav/v4 go 1.16 @@ -13,8 +13,11 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.7.1 + go.uber.org/zap v1.19.0 golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a golang.org/x/net v0.0.0-20210614182718-04defd469f4e golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect gopkg.in/ini.v1 v1.62.0 // indirect ) + +retract v4.1.0 diff --git a/go.sum b/go.sum index 44839e2..1dcbd14 100644 --- a/go.sum +++ b/go.sum @@ -19,6 +19,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= @@ -137,6 +139,7 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -185,8 +188,9 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -195,8 +199,16 @@ go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.19.0 h1:mZQZefskPPCMIBCSEH0v2/iUqqLrYtaeqwD6FUGUnFE= +go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -218,6 +230,7 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -291,6 +304,8 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc h1:NCy3Ohtk6Iny5V/reW2Ktypo4zIpWBdRJ1uFMjBxdg8= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= @@ -327,8 +342,12 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/lib/log.go b/lib/log.go deleted file mode 100644 index 250796d..0000000 --- a/lib/log.go +++ /dev/null @@ -1,31 +0,0 @@ -package lib - -import ( - "context" - "log" - "time" -) - -// map[reqHost:username]lastRequestSuccessTime -var authorizedSource = make(map[string]time.Time, 1) - -func LastRequestLogIndex(ctx context.Context) { - updateInterval := 5 * time.Second - ticker := time.NewTicker(updateInterval) - for { - ticker.Reset(updateInterval) - select { - case <-ctx.Done(): - log.Println("received a signal to cancel the service") - return - case <-ticker.C: - for v, k := range authorizedSource { - // no response for 2 minutes log again - if k.Unix()+(60*2) < time.Now().Unix() { - log.Printf("%s cache will be clean\n", v) - delete(authorizedSource, v) - } - } - } - } -} diff --git a/lib/webdav.go b/lib/webdav.go index e73ac72..270a72f 100644 --- a/lib/webdav.go +++ b/lib/webdav.go @@ -2,11 +2,10 @@ package lib import ( "context" - "fmt" - "log" "net/http" "strings" - "time" + + "go.uber.org/zap" ) // CorsCfg is the CORS config. @@ -22,10 +21,11 @@ type CorsCfg struct { // Config is the configuration of a WebDAV instance. type Config struct { *User - Auth bool - NoSniff bool - Cors CorsCfg - Users map[string]*User + Auth bool + NoSniff bool + Cors CorsCfg + Users map[string]*User + LogFormat string } // ServeHTTP determines if the request is for this plugin, and if all prerequisites are met. @@ -74,16 +74,7 @@ func (c *Config) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Gets the correct user for this request. username, password, ok := r.BasicAuth() - reqHost := func() string { - hArr := strings.Split(r.RemoteAddr, ":") - return hArr[0] - } - reqMark := fmt.Sprintf("%s:%s", reqHost(), username) - - if _, found := authorizedSource[reqMark]; !found { - log.Printf("%s tried to verify account , username is [%s]", r.RemoteAddr, username) - } - + zap.L().Info("login attempt", zap.String("username", username), zap.String("remote_address", r.RemoteAddr)) if !ok { http.Error(w, "Not authorized", 401) return @@ -96,14 +87,13 @@ func (c *Config) ServeHTTP(w http.ResponseWriter, r *http.Request) { } if !checkPassword(user.Password, password) { - log.Println("Wrong Password for user", username) + zap.L().Info("invalid password", zap.String("username", username), zap.String("remote_address", r.RemoteAddr)) http.Error(w, "Not authorized", 401) return - } else { - authorizedSource[reqMark] = time.Now() } u = user + zap.L().Info("user authorized", zap.String("username", username)) } else { // Even if Auth is disabled, we might want to get // the user from the Basic Auth header. Useful for Caddy diff --git a/main.go b/main.go index 85433cb..a2c430f 100644 --- a/main.go +++ b/main.go @@ -1,32 +1,9 @@ package main import ( - "context" - "github.com/hacdias/webdav/v3/lib" - "log" - "os" - "os/signal" - "runtime" - "syscall" - "time" - - "github.com/hacdias/webdav/v3/cmd" + "github.com/hacdias/webdav/v4/cmd" ) func main() { - runtime.GOMAXPROCS(runtime.NumCPU()) - ctx, cancel := context.WithCancel(context.Background()) - - go lib.LastRequestLogIndex(ctx) - go cmd.Execute() - - sigterm := make(chan os.Signal, 1) - signal.Notify(sigterm, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT) - - <-sigterm - log.Println("receive stop signal") - - cancel() - // wait for other goroutines to quit - time.Sleep(2 * time.Second) + cmd.Execute() }