diff --git a/README.md b/README.md index 3fe39df..6d0b1e9 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,8 @@ See the `scripts/` directory on how to install docstore on Linux or OpenBSD. "tesseract_oem": 1, // tesseract oem value "foreground": false, // do not fork into the background "secure_cookie": false, // enable secure cookie flag - "debug": false // enable debugging + "debug": false, // enable debugging + "webdav": false // enable webdav upload } ``` @@ -61,6 +62,9 @@ See the `scripts/` directory on how to install docstore on Linux or OpenBSD. * The `Index All` button tries add every file not already indexed to the index * Custom regex based tags (see https://golang.org/pkg/regexp/syntax/) * The `Retag All` button will reapply the current tags to all indexed documents +* Optional WebDav upload functionality + * WebDav can be accessed at `http://:/webdav` + * This WebDav does only permit writing files **once** (reading files or creating directories is not allowed) * Password hashing using BCrypt * 2FA using TOTP * Content Security Policy diff --git a/go.mod b/go.mod index 59b541d..1b87c6d 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module git.giftfish.de/ston1th/docstore go 1.12 require ( + git.giftfish.de/ston1th/authdav v1.0.0 git.giftfish.de/ston1th/godrop/v2 v2.1.0 git.giftfish.de/ston1th/jwt/v3 v3.2.0 github.com/RoaringBitmap/roaring v0.4.17 // indirect @@ -32,4 +33,5 @@ require ( github.com/urfave/cli v1.20.0 go.etcd.io/bbolt v1.3.3 // indirect golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 + golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 ) diff --git a/go.sum b/go.sum index a8ee9ef..91ddefe 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +git.giftfish.de/ston1th/authdav v1.0.0 h1:lbDLK/nW5K0kNzry9rYVp0leNCbZ0trAWcH55668OPg= +git.giftfish.de/ston1th/authdav v1.0.0/go.mod h1:LKpYWom0EiBKDHHqVTDvagBLxT1J7L8Nz+JRybHEDmw= git.giftfish.de/ston1th/godrop/v2 v2.1.0 h1:vR4aWVeMGJ+tHQH0p44esZrSl5dYJzuCmZqhKWP/vwI= git.giftfish.de/ston1th/godrop/v2 v2.1.0/go.mod h1:z8KA3HP/vB04wddLXZfYVKURYDxBGau9hlHtV61x9mM= git.giftfish.de/ston1th/jwt/v3 v3.2.0 h1:V6Lh7OjXn4D3HPd/LoDf7w5N7cyiSXEPAQCIfSVZ05c= diff --git a/pkg/cmd/cmd.go b/pkg/cmd/cmd.go index 3d0fe41..33339d9 100644 --- a/pkg/cmd/cmd.go +++ b/pkg/cmd/cmd.go @@ -312,6 +312,11 @@ func serverFlags() []cli.Flag { Usage: "enable debugging", Destination: &config.Debug, }, + cli.BoolFlag{ + Name: "webdav", + Usage: "enable webdav file uploader", + Destination: &config.WebDav, + }, } } diff --git a/pkg/core/const.go b/pkg/core/const.go index d2f0c9a..9cf77cc 100644 --- a/pkg/core/const.go +++ b/pkg/core/const.go @@ -20,6 +20,7 @@ const ( MovePrefix = "/move" TagsPrefix = "/tags" DeletePrefix = "/delete" + WebDavPrefix = "/webdav" Favicon = "/favicon.ico" BootstrapCSS = "/bootstrap.css" diff --git a/pkg/core/types.go b/pkg/core/types.go index 78e006f..7019d41 100644 --- a/pkg/core/types.go +++ b/pkg/core/types.go @@ -80,4 +80,5 @@ type Config struct { Foreground bool `json:"foreground,omitempty"` SecureCookie bool `json:"secure_cookie,omitempty"` Debug bool `json:"debug,omitempty"` + WebDav bool `json:"webdav,omitempty"` } diff --git a/pkg/db/user.go b/pkg/db/user.go index 57b3258..f89f3f9 100644 --- a/pkg/db/user.go +++ b/pkg/db/user.go @@ -64,6 +64,14 @@ func (db *DB) CreateUser(username, password string) error { }) } +func (db *DB) BasicAuth(username, password string) bool { + _, err := db.Login(username, password) + if err == nil { + return true + } + return false +} + func (db *DB) Login(username, password string) (u core.User, err error) { u, err = db.GetUser() if err != nil { diff --git a/pkg/fs/helper.go b/pkg/fs/helper.go index 6d3cba3..6ae3315 100644 --- a/pkg/fs/helper.go +++ b/pkg/fs/helper.go @@ -35,6 +35,7 @@ var reserved = []string{ core.NewPrefix, core.MovePrefix, core.DeletePrefix, + core.WebDavPrefix, core.Favicon, core.BootstrapCSS, core.CustomCSS, diff --git a/pkg/server/server.go b/pkg/server/server.go index 93afdae..aab94ff 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -6,6 +6,7 @@ import ( "bytes" "context" "errors" + "git.giftfish.de/ston1th/authdav" "git.giftfish.de/ston1th/docstore/pkg/core" "git.giftfish.de/ston1th/docstore/pkg/db" "git.giftfish.de/ston1th/docstore/pkg/fs" @@ -14,6 +15,7 @@ import ( "git.giftfish.de/ston1th/godrop/v2" "git.giftfish.de/ston1th/jwt/v3" "github.com/gorilla/mux" + "golang.org/x/net/webdav" "html/template" "net" "net/http" @@ -48,7 +50,6 @@ func NewHTTPServer(cfg core.Config, l net.Listener, s *scan.Scanner) (srv *HTTPS Scanner: s, Log: log.NewScanLog(0), } - srv.handler = srv.buildRoutes() srv.loadTemplates() srv.srv = &http.Server{} return @@ -75,6 +76,7 @@ func (s *HTTPServer) Start() (err error) { if err != nil { return errors.New("server: " + err.Error()) } + s.handler = s.buildRoutes() if !s.DB.UserExists() { log.Debug("server: starting register handler") s.srv.Handler = s.register() @@ -107,6 +109,11 @@ func (s *HTTPServer) register() http.Handler { func (s *HTTPServer) buildRoutes() http.Handler { r := mux.NewRouter() r.NotFoundHandler = ¬FoundHandler{s} + if s.Config.WebDav { + fs := authdav.NewWriteOnlyOnceFileSystem(webdav.Dir(s.Config.DataDir)) + h := authdav.NewWebdavBasicAuth(core.WebDavPrefix, fs, nil, webdavLogger, s.DB, "DocStore WebDav") + r.PathPrefix(core.WebDavPrefix).Handler(h) + } for _, v := range routes { r.HandleFunc(v.Path, s.contextWrapper(v.Handler)).Methods(v.Methods...) } diff --git a/pkg/server/webdav.go b/pkg/server/webdav.go new file mode 100644 index 0000000..3d8e260 --- /dev/null +++ b/pkg/server/webdav.go @@ -0,0 +1,14 @@ +package server + +import ( + "git.giftfish.de/ston1th/docstore/pkg/log" + "net/http" +) + +func webdavLogger(r *http.Request, err error) { + if err != nil { + log.Printf("webdav: %s %s %s error: %s\n", r.RemoteAddr, r.Method, r.URL, err) + return + } + log.Printf("webdav: %s %s %s\n", r.RemoteAddr, r.Method, r.URL) +}