Initial commit

Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
This commit is contained in:
Vincent Batts 2016-09-22 10:19:43 -04:00
commit da559ee7ca
Signed by: vbatts
GPG Key ID: 10937E57733F1362
3 changed files with 177 additions and 0 deletions

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016 Vincent Batts
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

52
README.md Normal file
View File

@ -0,0 +1,52 @@
# srvdav
dangerously simple webdav server for a local filesystem
# Building
```bash
go get github.com/vbatts/srvdav
```
# Basic use
This daemon can serve up [WebDAV](https://en.wikipedia.org/wiki/WebDAV) for a local directory without any auth, nor encryption.
*DO NOT DO THIS*
# More proper use
Produce an x.509 certificate and accompanying key.
For development use case use can use the generator in golang's stdlib.
```bash
> go run $(go env GOROOT)/src/crypto/tls/generate_cert.go -h
> go run $(go env GOROOT)/src/crypto/tls/generate_cert.go -host="localhost,example.com"
2016/09/22 09:46:19 written cert.pem
2016/09/22 09:46:19 written key.pem
```
Produce a password list for users.
The `htpasswd(1)` utility creates the password file nicely.
```bash
> htpasswd -bc srvdav.passwd vbatts topsecretpassword
```
Then launch `srvdav` with these credentials.
```bash
> mkdir -p ./test/
> srvdav -htpasswd ./srvdav.passwd -cert ./cert.pem -key ./key.pem
Serving HTTPS:// :9999
[...]
```
# Accompanying Clients
There are a number of webdav clients.
For my specific use case, I am working with ChromeOS and there is a [WebDAV Storage Provider](https://chrome.google.com/webstore/detail/webdav-file-system/hmckflbfniicjijmdoffagjkpnjgbieh?hl=en).
For Linux hosts, there is a package commonly `davfs2`, that provides a `mount.davfs` command.
See `mount.davfs(8)` man page for more information.

104
main.go Normal file
View File

@ -0,0 +1,104 @@
package main
import (
"flag"
"fmt"
"log"
"net/http"
"net/url"
"os"
"path/filepath"
"github.com/abbot/go-http-auth"
"golang.org/x/net/webdav"
)
var (
flPort = flag.Int("port", 9999, "server port")
flCert = flag.String("cert", "", "server SSL cert (both -cert and -key must be present to use SSL). See `go run $(go env GOROOT)/src/crypto/tls/generate_cert.go -h` to generate development cert/key")
flKey = flag.String("key", "", "server SSL key")
flHtpasswd = flag.String("htpasswd", "", "htpasswd file for auth (must be present to use auth) See htpasswd(1) to create this file.")
)
func main() {
flag.Parse()
if flag.NArg() == 0 {
log.Fatal("One argument required. Please provide path to serve (you can use a special keyword of 'mem' to serve an in-memory filesystem)")
}
var fs webdav.FileSystem
if flag.Args()[0] == "mem" {
fs = webdav.NewMemFS()
} else {
fs = NewPassThroughFS(flag.Args()[0])
}
log.SetFlags(0)
h := &webdav.Handler{
FileSystem: fs,
LockSystem: webdav.NewMemLS(),
Logger: func(r *http.Request, err error) {
switch r.Method {
case "COPY", "MOVE":
dst := ""
if u, err := url.Parse(r.Header.Get("Destination")); err == nil {
dst = u.Path
}
o := r.Header.Get("Overwrite")
log.Printf("%-20s%-20s%-10s%-30s%-30so=%-2s%v", r.Header.Get("Date"), r.RemoteAddr, r.Method, r.URL.Path, dst, o, err)
default:
log.Printf("%-20s%-20s%-10s%-30s%v", r.Header.Get("Date"), r.RemoteAddr, r.Method, r.URL.Path, err)
}
},
}
if *flHtpasswd != "" {
secret := auth.HtpasswdFileProvider(*flHtpasswd)
authenticator := auth.NewBasicAuthenticator("", secret)
authHandlerFunc := func(w http.ResponseWriter, r *auth.AuthenticatedRequest) {
h.ServeHTTP(w, &r.Request)
}
http.HandleFunc("/", authenticator.Wrap(authHandlerFunc))
} else {
log.Println("WARNING: connections are not authenticated. STRONGLY consider using -htpasswd.")
http.Handle("/", h)
}
addr := fmt.Sprintf(":%d", *flPort)
if *flCert != "" && *flKey != "" {
log.Printf("Serving HTTPS:// %v", addr)
log.Fatal(http.ListenAndServeTLS(addr, *flCert, *flKey, nil))
} else {
log.Println("WARNING: connections are not encrypted. STRONGLY consider using -cert/-key.")
log.Printf("Serving HTTP:// %v", addr)
log.Fatal(http.ListenAndServe(addr, nil))
}
}
func NewPassThroughFS(path string) webdav.FileSystem {
return &passThroughFS{root: path}
}
type passThroughFS struct {
root string
}
func (ptfs *passThroughFS) Mkdir(name string, perm os.FileMode) error {
// TODO(vbatts) check for escaping the root directory
return os.Mkdir(filepath.Join(ptfs.root, name), perm)
}
func (ptfs *passThroughFS) OpenFile(name string, flag int, perm os.FileMode) (webdav.File, error) {
// TODO(vbatts) check for escaping the root directory
return os.OpenFile(filepath.Join(ptfs.root, name), flag, perm)
}
func (ptfs *passThroughFS) RemoveAll(name string) error {
// TODO(vbatts) check for escaping the root directory
return os.RemoveAll(filepath.Join(ptfs.root, name))
}
func (ptfs *passThroughFS) Rename(oldName, newName string) error {
// TODO(vbatts) check for escaping the root directory
return os.Rename(filepath.Join(ptfs.root, oldName), filepath.Join(ptfs.root, newName))
}
func (ptfs *passThroughFS) Stat(name string) (os.FileInfo, error) {
// TODO(vbatts) check for escaping the root directory
return os.Stat(filepath.Join(ptfs.root, name))
}