Add support for .htpasswd files.

- Improve logging
- Variableize dav prefix
This commit is contained in:
Aaron Bieber 2019-11-07 18:00:07 -07:00
parent 1caa24ccec
commit 90b3162b66
Signed by: qbit
GPG Key ID: 279160AB1BE1236B
3 changed files with 68 additions and 9 deletions

1
go.mod
View File

@ -3,6 +3,7 @@ module github.com/qbit/gavin
go 1.13 go 1.13
require ( require (
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
golang.org/x/net v0.0.0-20191105084925-a882066a44e0 golang.org/x/net v0.0.0-20191105084925-a882066a44e0
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a
) )

1
go.sum
View File

@ -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/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 h1:QPlSTtPE2k6PZPasQUbzuK3p9JbS+vMXYVto8g/yrsg=
golang.org/x/net v0.0.0-20191105084925-a882066a44e0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191105084925-a882066a44e0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=

75
main.go
View File

@ -1,55 +1,110 @@
package main package main
import ( import (
"encoding/csv"
"flag" "flag"
"fmt"
"log" "log"
"net" "net"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"time"
"golang.org/x/crypto/bcrypt"
"golang.org/x/net/webdav" "golang.org/x/net/webdav"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
var listen string var (
var davDir string davDir string
var staticDir string listen string
passPath string
prefix string
staticDir string
users map[string]string
)
func init() { func init() {
users = make(map[string]string)
dir, err := filepath.Abs(filepath.Dir(os.Args[0])) dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
flag.StringVar(&listen, "http", ":8080", "Listen on")
flag.StringVar(&davDir, "dir", dir, "WebDAV directory to serve.") 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.StringVar(&staticDir, "static", dir, "Directory to serve static resources from.")
flag.Parse() flag.Parse()
unix.Unveil(staticDir, "r") unix.Unveil(staticDir, "r")
unix.Unveil(passPath, "r")
unix.Unveil(davDir, "rwc") unix.Unveil(davDir, "rwc")
err = unix.UnveilBlock() err = unix.UnveilBlock()
if err != nil { if err != nil {
log.Fatal(err) 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() { func main() {
wdav := &webdav.Handler{ wdav := &webdav.Handler{
Prefix: "/dav/", Prefix: prefix,
LockSystem: webdav.NewMemLS(), LockSystem: webdav.NewMemLS(),
FileSystem: webdav.Dir(davDir), FileSystem: webdav.Dir(davDir),
Logger: func(r *http.Request, err error) { 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 := http.NewServeMux()
mux.Handle("/", http.FileServer(http.Dir(staticDir))) mux.Handle("/", http.FileServer(http.Dir(staticDir)))
mux.HandleFunc("/dav/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { mux.HandleFunc(prefix, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
u, p, ok := r.BasicAuth() user, pass, ok := r.BasicAuth()
if !(ok == true && u == "qbit" && p == "hai") { if !(ok == true && validate(user, pass)) {
w.Header().Set("WWW-Authenticate", `Basic realm="davfs"`) w.Header().Set("WWW-Authenticate", `Basic realm="davfs"`)
http.Error(w, "Unauthorized", http.StatusUnauthorized) http.Error(w, "Unauthorized", http.StatusUnauthorized)
return return
@ -63,5 +118,7 @@ func main() {
} }
s := http.Server{Handler: mux} s := http.Server{Handler: mux}
log.Printf("Listening on '%s'", listen)
log.Panic(s.Serve(lis)) log.Panic(s.Serve(lis))
} }