1
0
Fork 0

initial commit

This commit is contained in:
ston1th 2019-08-31 16:39:50 +02:00
commit f6e1813d15
7 changed files with 296 additions and 0 deletions

24
LICENSE Normal file
View file

@ -0,0 +1,24 @@
Copyright (C) 2019 Marius Schellenberger
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of the authors and/or contributors may not be used to
endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL ston1th BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

59
README.md Normal file
View file

@ -0,0 +1,59 @@
# authdav - a x/net/webdav wrapper
Wrappers:
* HTTP Basic Auth wrapper for `webdav.Handler`
* write only once FileSystem wrapper for `webdav.FileSystem`
## Usage
### HTTP Basic Auth
```
package main
import (
"git.giftfish.de/ston1th/authdav"
"golang.org/x/net/webdav"
"log"
"net/http"
)
type exampleAuthenticator struct {}
func (exampleAuthenticator) BasicAuth(user, password string) bool {
if user == "user" && password == "password" {
return true
}
return false
}
func main() {
auth := exampleAuthenticator{}
handler := authdav.NewWebdavBasicAuth("", webdav.Dir("."), nil, nil, auth, "webdav with basic auth")
log.Fatal(http.ListenAndServe(":8080", handler))
}
```
### Write Only
```
package main
import (
"git.giftfish.de/ston1th/authdav"
"golang.org/x/net/webdav"
"log"
"net/http"
)
func main() {
fs := authdav.NewWriteOnlyOnceFileSystem(webdav.Dir("."))
handler := &webdav.Handler{
Prefix: "",
FileSystem: fs,
LockSystem: webdav.NewMemLS(),
Logger: nil,
}
log.Fatal(http.ListenAndServe(":8080", handler))
}
```

57
authdav.go Normal file
View file

@ -0,0 +1,57 @@
// Copyright (C) 2019 Marius Schellenberger
package authdav
import (
"golang.org/x/net/webdav"
"net/http"
)
// DefaultRealm is the HTTP Basic Auth default realm
const DefaultRealm = "WebDav"
// Authenticator is the interface for Webdav HTTP Basic Auth
type Authenticator interface {
BasicAuth(username string, password string) bool
}
// WebdavBasicAuth is a WebDav wrapper for HTTP Basic Auth and implements the http.Handler interface
type WebdavBasicAuth struct {
dav *webdav.Handler
auth Authenticator
realm string
}
// NewWebdavBasicAuth returns a new WebdavBasicAuth wrapper
// prefix can be empty
// ls and log can be nil
// an empty authenticator disables HTTP Basic Auth
// realm can be empty and defaults to authdav.DefaultRealm
func NewWebdavBasicAuth(prefix string, fs webdav.FileSystem, ls webdav.LockSystem, log func(*http.Request, error), auth Authenticator, realm string) *WebdavBasicAuth {
if ls == nil {
ls = webdav.NewMemLS()
}
if realm == "" {
realm = DefaultRealm
}
dav := &webdav.Handler{
Prefix: prefix,
FileSystem: fs,
LockSystem: ls,
Logger: log,
}
return &WebdavBasicAuth{dav, auth, `Basic realm="` + realm + `"`}
}
func (h *WebdavBasicAuth) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if h.auth != nil {
u, p, ok := r.BasicAuth()
if !ok || !h.auth.BasicAuth(u, p) {
w.Header().Set("WWW-Authenticate", h.realm)
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("Unauthorised\n"))
return
}
}
h.dav.ServeHTTP(w, r)
}

46
file.go Normal file
View file

@ -0,0 +1,46 @@
// Copyright (C) 2019 Marius Schellenberger
package authdav
import (
"golang.org/x/net/webdav"
"io"
"os"
)
// File is a wrapper for webdav.File providing write only functionality
type File struct {
f webdav.File
}
func (f *File) Close() error {
return f.f.Close()
}
func (f *File) Read(p []byte) (int, error) {
return 0, io.EOF
}
func (f *File) Seek(offset int64, whence int) (int64, error) {
return 0, nil
}
func (f *File) Readdir(count int) (fi []os.FileInfo, err error) {
ffi, err := f.f.Readdir(count)
for _, f := range ffi {
fi = append(fi, &FileInfo{f})
}
return
}
func (f *File) Stat() (os.FileInfo, error) {
fi, err := f.f.Stat()
if err != nil {
return nil, err
}
return &FileInfo{fi}, nil
}
func (f *File) Write(p []byte) (int, error) {
return f.f.Write(p)
}

44
fileinfo.go Normal file
View file

@ -0,0 +1,44 @@
// Copyright (C) 2019 Marius Schellenberger
package authdav
import (
"os"
"time"
)
// FileInfo is a wrapper for os.FileInfo which always raturns a zero length for regular files
type FileInfo struct {
fi os.FileInfo
}
func (fi *FileInfo) Name() string {
return fi.fi.Name()
}
func (fi *FileInfo) RealSize() int64 {
return fi.fi.Size()
}
func (fi *FileInfo) Size() int64 {
if fi.Mode().IsRegular() {
return 0
}
return fi.fi.Size()
}
func (fi *FileInfo) Mode() os.FileMode {
return fi.fi.Mode()
}
func (fi *FileInfo) ModTime() time.Time {
return fi.fi.ModTime()
}
func (fi *FileInfo) IsDir() bool {
return fi.fi.IsDir()
}
func (fi *FileInfo) Sys() interface{} {
return fi.fi.Sys()
}

65
filesystem.go Normal file
View file

@ -0,0 +1,65 @@
// Copyright (C) 2019 Marius Schellenberger
package authdav
import (
"context"
"errors"
"golang.org/x/net/webdav"
"os"
)
// ErrWonly indicates forbidden operation
var ErrWonly = errors.New("authdav: only file write once operations permitted")
const writeFlag = os.O_RDWR | os.O_CREATE | os.O_TRUNC
// WriteOnlyOnceFileSystem is a file write only wrapper for a webdav.FileSystem
type WriteOnlyOnceFileSystem struct {
fs webdav.FileSystem
}
// NewWriteOnlyOnceFileSystem returns a new WriteOnlyOnceFileSystem wrapping a webdav.FileSystem
func NewWriteOnlyOnceFileSystem(fs webdav.FileSystem) *WriteOnlyOnceFileSystem {
return &WriteOnlyOnceFileSystem{fs}
}
// Mkdir is not permitted
func (fs *WriteOnlyOnceFileSystem) Mkdir(ctx context.Context, name string, perm os.FileMode) error {
return ErrWonly
}
// OpenFile allows write only once operations
func (fs *WriteOnlyOnceFileSystem) OpenFile(ctx context.Context, name string, flag int, perm os.FileMode) (webdav.File, error) {
fi, err := fs.Stat(ctx, name)
if err == nil && fi.Mode().IsRegular() {
f, ok := fi.(*FileInfo)
if ok && flag == writeFlag && f.RealSize() > 0 {
return nil, ErrWonly
}
}
f, err := fs.fs.OpenFile(ctx, name, flag, perm)
if err != nil {
return nil, err
}
return &File{f}, nil
}
// RemoveAll is not permitted
func (fs *WriteOnlyOnceFileSystem) RemoveAll(ctx context.Context, name string) error {
return ErrWonly
}
// Rename is not permitted
func (fs *WriteOnlyOnceFileSystem) Rename(ctx context.Context, oldName, newName string) error {
return ErrWonly
}
// Stat returns os.FileInfo wrapped in FileInfo
func (fs *WriteOnlyOnceFileSystem) Stat(ctx context.Context, name string) (os.FileInfo, error) {
fi, err := fs.fs.Stat(ctx, name)
if err != nil {
return nil, err
}
return &FileInfo{fi}, nil
}

1
go.mod Normal file
View file

@ -0,0 +1 @@
module git.giftfish.de/ston1th/authdav