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