From 90b3162b6606fd1a0ec236a8f2260b2eee1ea725 Mon Sep 17 00:00:00 2001 From: Aaron Bieber Date: Thu, 7 Nov 2019 18:00:07 -0700 Subject: [PATCH] Add support for .htpasswd files. - Improve logging - Variableize dav prefix --- go.mod | 1 + go.sum | 1 + main.go | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 68 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index cc784fa..1fc38aa 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/qbit/gavin go 1.13 require ( + golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 golang.org/x/net v0.0.0-20191105084925-a882066a44e0 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a ) diff --git a/go.sum b/go.sum index e8332bd..8040b0e 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20191105084925-a882066a44e0 h1:QPlSTtPE2k6PZPasQUbzuK3p9JbS+vMXYVto8g/yrsg= golang.org/x/net v0.0.0-20191105084925-a882066a44e0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= diff --git a/main.go b/main.go index cafe52f..68681d5 100644 --- a/main.go +++ b/main.go @@ -1,55 +1,110 @@ package main import ( + "encoding/csv" "flag" + "fmt" "log" "net" "net/http" "os" "path/filepath" + "time" + "golang.org/x/crypto/bcrypt" "golang.org/x/net/webdav" "golang.org/x/sys/unix" ) -var listen string -var davDir string -var staticDir string +var ( + davDir string + listen string + passPath string + prefix string + staticDir string + users map[string]string +) func init() { + users = make(map[string]string) dir, err := filepath.Abs(filepath.Dir(os.Args[0])) if err != nil { log.Fatal(err) } - flag.StringVar(&listen, "http", ":8080", "Listen on") flag.StringVar(&davDir, "dir", dir, "WebDAV directory to serve.") + flag.StringVar(&listen, "http", ":8080", "Listen on") + flag.StringVar(&passPath, "htpass", fmt.Sprintf("%s/.htpasswd", dir), "Path to .htpasswd file..") + flag.StringVar(&prefix, "prefix", "/dav/", "Prefix to serve dav things from.") flag.StringVar(&staticDir, "static", dir, "Directory to serve static resources from.") flag.Parse() unix.Unveil(staticDir, "r") + unix.Unveil(passPath, "r") unix.Unveil(davDir, "rwc") err = unix.UnveilBlock() if err != nil { log.Fatal(err) } + + p, err := os.Open(passPath) + defer p.Close() + if err != nil { + log.Fatal(err) + } + + ht := csv.NewReader(p) + ht.Comma = ':' + ht.Comment = '#' + ht.TrimLeadingSpace = true + + entries, err := ht.ReadAll() + if err != nil { + log.Fatal(err) + } + + for _, parts := range entries { + users[parts[0]] = parts[1] + } +} + +func validate(user string, pass string) bool { + htpass, exists := users[user] + + if !exists { + return false + } + + err := bcrypt.CompareHashAndPassword([]byte(htpass), []byte(pass)) + if err == nil { + return true + } + return false } func main() { wdav := &webdav.Handler{ - Prefix: "/dav/", + Prefix: prefix, LockSystem: webdav.NewMemLS(), FileSystem: webdav.Dir(davDir), Logger: func(r *http.Request, err error) { - log.Printf("%s : %s - %s", r.Method, r.URL.Path, err) + n := time.Now() + fmt.Printf("%s [%s] \"%s %s %s\" %03d\n", + r.RemoteAddr, + n.Format(time.RFC822Z), + r.Method, + r.URL.Path, + r.Proto, + r.ContentLength, + ) }, } mux := http.NewServeMux() mux.Handle("/", http.FileServer(http.Dir(staticDir))) - mux.HandleFunc("/dav/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - u, p, ok := r.BasicAuth() - if !(ok == true && u == "qbit" && p == "hai") { + mux.HandleFunc(prefix, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + user, pass, ok := r.BasicAuth() + if !(ok == true && validate(user, pass)) { w.Header().Set("WWW-Authenticate", `Basic realm="davfs"`) http.Error(w, "Unauthorized", http.StatusUnauthorized) return @@ -63,5 +118,7 @@ func main() { } s := http.Server{Handler: mux} + + log.Printf("Listening on '%s'", listen) log.Panic(s.Serve(lis)) }