Initial commit
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
This commit is contained in:
commit
da559ee7ca
3 changed files with 177 additions and 0 deletions
21
LICENSE
Normal file
21
LICENSE
Normal 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
52
README.md
Normal 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
104
main.go
Normal 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))
|
||||||
|
}
|
Loading…
Reference in a new issue