From 2229a266538f10d0ea6b9ca0e512b39e0dcea1eb Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Thu, 3 Aug 2017 17:09:27 +0100 Subject: [PATCH] Update readme --- cmd/webdav/config.go | 175 +++++++++++++++++++++++++++++++++++++++ cmd/webdav/main.go | 191 ++++--------------------------------------- readme.md | 22 ++++- 3 files changed, 213 insertions(+), 175 deletions(-) create mode 100644 cmd/webdav/config.go diff --git a/cmd/webdav/config.go b/cmd/webdav/config.go new file mode 100644 index 0000000..e35343a --- /dev/null +++ b/cmd/webdav/config.go @@ -0,0 +1,175 @@ +package main + +import ( + "encoding/json" + "io/ioutil" + "log" + "os" + "path/filepath" + "regexp" + + "github.com/hacdias/webdav" + wd "golang.org/x/net/webdav" + yaml "gopkg.in/yaml.v2" +) + +func parseRules(raw []map[string]interface{}) []*webdav.Rule { + rules := []*webdav.Rule{} + + for _, r := range raw { + rule := &webdav.Rule{ + Regex: false, + Allow: false, + Path: "", + } + + if regex, ok := r["regex"].(bool); ok { + rule.Regex = regex + } + + if allow, ok := r["allow"].(bool); ok { + rule.Allow = allow + } + + path, ok := r["rule"].(string) + if !ok { + continue + } + + if rule.Regex { + rule.Regexp = regexp.MustCompile(path) + } else { + rule.Path = path + } + + rules = append(rules, rule) + } + + return rules +} + +func parseUsers(raw []map[string]interface{}, c *cfg) { + for _, r := range raw { + username, ok := r["username"].(string) + if !ok { + log.Fatal("user needs an username") + } + + password, ok := r["password"].(string) + if !ok { + log.Fatal("user needs a password") + } + + c.auth[username] = password + + user := &webdav.User{ + Scope: c.webdav.User.Scope, + Modify: c.webdav.User.Modify, + Rules: c.webdav.User.Rules, + } + + if scope, ok := r["scope"].(string); ok { + user.Scope = scope + } + + if modify, ok := r["modify"].(bool); ok { + user.Modify = modify + } + + if rules, ok := r["rules"].([]map[string]interface{}); ok { + user.Rules = parseRules(rules) + } + + user.Handler = &wd.Handler{ + FileSystem: wd.Dir(user.Scope), + LockSystem: wd.NewMemLS(), + } + + c.webdav.Users[username] = user + } +} + +func getConfig() []byte { + if config == "" { + for _, v := range defaultConfigs { + _, err := os.Stat(v) + if err == nil { + config = v + break + } + } + } + + if config == "" { + log.Fatal("no config file specified; couldn't find any config.{yaml,json}") + } + + file, err := ioutil.ReadFile(config) + if err != nil { + log.Fatal(err) + } + + return file +} + +type cfg struct { + webdav *webdav.Config + port string + auth map[string]string +} + +func parseConfig() *cfg { + file := getConfig() + + data := struct { + Port string `json:"port" yaml:"port"` + Scope string `json:"scope" yaml:"scope"` + Modify bool `json:"modify" yaml:"modify"` + Rules []map[string]interface{} `json:"rules" yaml:"rules"` + Users []map[string]interface{} `json:"users" yaml:"users"` + }{ + Port: "0", + Scope: "./", + Modify: true, + } + + var err error + if filepath.Ext(config) == ".json" { + err = json.Unmarshal(file, &data) + } else { + err = yaml.Unmarshal(file, &data) + } + + if err != nil { + log.Fatal(err) + } + + config := &cfg{ + port: data.Port, + auth: map[string]string{}, + webdav: &webdav.Config{ + BaseURL: "", + User: &webdav.User{ + Scope: data.Scope, + Modify: data.Modify, + Rules: []*webdav.Rule{}, + Handler: &wd.Handler{ + FileSystem: wd.Dir(data.Scope), + LockSystem: wd.NewMemLS(), + }, + }, + Users: map[string]*webdav.User{}, + }, + } + + if len(data.Users) == 0 { + log.Fatal("no user defined") + } + + if len(data.Rules) != 0 { + config.webdav.User.Rules = parseRules(data.Rules) + } + + parseUsers(data.Users, config) + return config +} diff --git a/cmd/webdav/main.go b/cmd/webdav/main.go index 244a9b8..3f739da 100644 --- a/cmd/webdav/main.go +++ b/cmd/webdav/main.go @@ -1,18 +1,11 @@ package main import ( - "encoding/json" - "errors" "flag" - "io/ioutil" + "fmt" + "log" + "net" "net/http" - "os" - "path/filepath" - "regexp" - - "github.com/hacdias/webdav" - wd "golang.org/x/net/webdav" - "gopkg.in/yaml.v2" ) var ( @@ -21,168 +14,7 @@ var ( ) func init() { - flag.StringVar(&config, "config", "config.yaml", "Configuration file") -} - -func parseRules(raw []map[string]interface{}) []*webdav.Rule { - rules := []*webdav.Rule{} - - for _, r := range raw { - rule := &webdav.Rule{ - Regex: false, - Allow: false, - Path: "", - } - - if regex, ok := r["regex"].(bool); ok { - rule.Regex = regex - } - - if allow, ok := r["allow"].(bool); ok { - rule.Allow = allow - } - - path, ok := r["rule"].(string) - if !ok { - continue - } - - if rule.Regex { - rule.Regexp = regexp.MustCompile(path) - } else { - rule.Path = path - } - - rules = append(rules, rule) - } - - return rules -} - -func parseUsers(raw []map[string]interface{}, c *cfg) { - for _, r := range raw { - username, ok := r["username"].(string) - if !ok { - panic("user needs an username") - } - - password, ok := r["password"].(string) - if !ok { - panic("user needs a password") - } - - c.auth[username] = password - - user := &webdav.User{ - Scope: c.webdav.User.Scope, - Modify: c.webdav.User.Modify, - Rules: c.webdav.User.Rules, - } - - if scope, ok := r["scope"].(string); ok { - user.Scope = scope - } - - if modify, ok := r["modify"].(bool); ok { - user.Modify = modify - } - - if rules, ok := r["rules"].([]map[string]interface{}); ok { - user.Rules = parseRules(rules) - } - - user.Handler = &wd.Handler{ - FileSystem: wd.Dir(user.Scope), - LockSystem: wd.NewMemLS(), - } - - c.webdav.Users[username] = user - } -} - -func getConfig() []byte { - if config == "" { - for _, v := range defaultConfigs { - _, err := os.Stat(v) - if err == nil { - config = v - break - } - } - } - - if config == "" { - panic(errors.New("no config file")) - } - - file, err := ioutil.ReadFile(config) - if err != nil { - panic(err) - } - - return file -} - -type cfg struct { - webdav *webdav.Config - port string - auth map[string]string -} - -func parseConfig() *cfg { - file := getConfig() - - data := struct { - Port string `json:"port" yaml:"port"` - Scope string `json:"scope" yaml:"scope"` - Modify bool `json:"modify" yaml:"modify"` - Rules []map[string]interface{} `json:"rules" yaml:"rules"` - Users []map[string]interface{} `json:"users" yaml:"users"` - }{ - Port: "80", - Scope: "./", - Modify: true, - } - - var err error - if filepath.Ext(config) == ".json" { - err = json.Unmarshal(file, &data) - } else { - err = yaml.Unmarshal(file, &data) - } - - if err != nil { - panic(err) - } - - config := &cfg{ - port: data.Port, - auth: map[string]string{}, - webdav: &webdav.Config{ - BaseURL: "", - User: &webdav.User{ - Scope: data.Scope, - Modify: data.Modify, - Rules: []*webdav.Rule{}, - Handler: &wd.Handler{ - FileSystem: wd.Dir(data.Scope), - LockSystem: wd.NewMemLS(), - }, - }, - Users: map[string]*webdav.User{}, - }, - } - - if len(data.Users) == 0 { - panic("no user defined") - } - - if len(data.Rules) != 0 { - config.webdav.User.Rules = parseRules(data.Rules) - } - - parseUsers(data.Users, config) - return config + flag.StringVar(&config, "config", "", "Configuration file") } func basicAuth(c *cfg) http.Handler { @@ -215,7 +47,18 @@ func main() { cfg := parseConfig() handler := basicAuth(cfg) - if err := http.ListenAndServe(":"+cfg.port, handler); err != nil { - panic(err) + // Builds the address and a listener. + laddr := ":" + cfg.port + listener, err := net.Listen("tcp", laddr) + if err != nil { + log.Fatal(err) + } + + // Tell the user the port in which is listening. + fmt.Println("Listening on", listener.Addr().String()) + + // Starts the server. + if err := http.Serve(listener, handler); err != nil { + log.Fatal(err) } } diff --git a/readme.md b/readme.md index 693e73a..09cd565 100644 --- a/readme.md +++ b/readme.md @@ -1,3 +1,23 @@ # webdav -(TODO) \ No newline at end of file +[![Build](https://img.shields.io/travis/hacdias/webdav.svg?style=flat-square)](https://travis-ci.org/hacdias/webdav) +[![Go Report Card](https://goreportcard.com/badge/github.com/hacdias/webdav?style=flat-square)](https://goreportcard.com/report/hacdias/webdav) + +```webdav``` is a simple tool that creates a WebDAV server for you. By default, it runs on a random free port and supports JSON and YAML configuration. Here is a simple YAML configuration example: + +```yaml +scope: /path/to/files +port: 8080 +users: + - username: admin + password: admin + - username: basic + password: basic + modify: false + rules: + - regex: false + - allow: false + - path: /some/file +``` + +You can specify the path to the configuration file using the `--config` flag. By default, it will search for a `config.{yaml,json}` file on your current working directory. \ No newline at end of file