Compare commits

...
2 Commits
Author SHA1 Message Date
Henrique Dias cd472b26be chore: bump to v2.0.0
License: MIT
Signed-off-by: Henrique Dias <[email protected]>
2019-06-11 13:09:51 +01:00
Steven Vandevelde 7358553e69 feat(BREAKING): extend cors functionality (#25) 2019-06-11 13:02:10 +01:00
6 changed files with 88 additions and 36 deletions
+18 -2
View File
@@ -28,8 +28,17 @@ rules: []
# CORS configuration # CORS configuration
cors: cors:
- enabled: false enabled: true
allowed_hosts: [] credentials: true
allowed_headers:
- Depth
allowed_hosts:
- http://localhost:8080
allowed_methods:
- GET
exposed_headers:
- Content-Length
- Content-Range
users: users:
- username: admin - username: admin
@@ -54,6 +63,13 @@ There are more ways to customize how you run WebDAV through flags and environmen
An example of how to use this with `systemd` is on [webdav.service.example](/webdav.service.example). An example of how to use this with `systemd` is on [webdav.service.example](/webdav.service.example).
### CORS
The `allowed_*` properties are optional, the default value for each of them will be `*`. `exposed_headers` is optional as well, but is not set if not defined. Setting `credentials` to `true` will allow you to:
1. Use `withCredentials = true` in javascript.
2. Use the `username:password@host` syntax.
## License ## License
MIT © [Henrique Dias](https://hacdias.com) MIT © [Henrique Dias](https://hacdias.com)
+34 -20
View File
@@ -8,7 +8,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/hacdias/webdav/webdav" "github.com/hacdias/webdav/v2/webdav"
"github.com/spf13/pflag" "github.com/spf13/pflag"
v "github.com/spf13/viper" v "github.com/spf13/viper"
wd "golang.org/x/net/webdav" wd "golang.org/x/net/webdav"
@@ -123,30 +123,44 @@ func parseUsers(raw []interface{}, c *webdav.Config) {
} }
} }
func parseCors(raw []interface{}, c *webdav.Config) { func parseCors(cfg map[string]interface{}, c *webdav.Config) {
hosts := []string{} cors := webdav.CorsCfg{
Enabled: cfg["enabled"].(bool),
Credentials: cfg["credentials"].(bool),
}
for _, v := range raw { cors.AllowedHeaders = corsProperty("allowed_headers", cfg)
cors.AllowedHosts = corsProperty("allowed_hosts", cfg)
cors.AllowedMethods = corsProperty("allowed_methods", cfg)
cors.ExposedHeaders = corsProperty("exposed_headers", cfg)
if cfg, ok := v.(map[interface{}]interface{}); ok { c.Cors = cors
}
cors := webdav.CorsCfg{ func corsProperty(property string, cfg map[string]interface{}) []string {
Enabled: cfg["enabled"].(bool), var def []string
AllowedHosts: []string{},
}
if allowedHosts, ok := cfg["allowed_hosts"]; ok { if property == "exposed_headers" {
hosts = append(hosts, strings.Split(allowedHosts.(string), ",")...) def = []string{}
} } else {
def = []string{"*"}
}
if len(hosts) == 0 { if allowed, ok := cfg[property].([]interface{}); ok {
hosts = append(hosts, "*") items := make([]string, len(allowed))
}
cors.AllowedHosts = hosts for idx, a := range allowed {
c.Cors = cors items[idx] = a.(string)
}
if len(items) == 0 {
return def
} else {
return items
} }
} }
return def
} }
func readConfig(flags *pflag.FlagSet) *webdav.Config { func readConfig(flags *pflag.FlagSet) *webdav.Config {
@@ -162,8 +176,8 @@ func readConfig(flags *pflag.FlagSet) *webdav.Config {
}, },
Auth: getOptB(flags, "auth"), Auth: getOptB(flags, "auth"),
Cors: webdav.CorsCfg{ Cors: webdav.CorsCfg{
Enabled: false, Enabled: false,
AllowedHosts: []string{}, Credentials: false,
}, },
Users: map[string]*webdav.User{}, Users: map[string]*webdav.User{},
} }
@@ -179,7 +193,7 @@ func readConfig(flags *pflag.FlagSet) *webdav.Config {
} }
rawCors := v.Get("cors") rawCors := v.Get("cors")
if cors, ok := rawCors.([]interface{}); ok { if cors, ok := rawCors.(map[string]interface{}); ok {
parseCors(cors, cfg) parseCors(cors, cfg)
} }
+2 -3
View File
@@ -1,10 +1,9 @@
module github.com/hacdias/webdav module github.com/hacdias/webdav/v2
go 1.12 go 1.12
require ( require (
github.com/BurntSushi/toml v0.3.1 // indirect github.com/hacdias/webdav v1.4.1 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/spf13/cobra v0.0.3 github.com/spf13/cobra v0.0.3
github.com/spf13/pflag v1.0.3 github.com/spf13/pflag v1.0.3
github.com/spf13/viper v1.3.2 github.com/spf13/viper v1.3.2
+2
View File
@@ -8,6 +8,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/hacdias/webdav v1.4.1 h1:yhR4dgKr3JUfgDhFO2nWTq3HiYA37Sk/kaud/bRx1io=
github.com/hacdias/webdav v1.4.1/go.mod h1:1qXJOCQfiAXgYonkWHIMgWSfbKqUW8F4DlzXxSJCYIg=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
+1 -1
View File
@@ -3,7 +3,7 @@ package main
import ( import (
"runtime" "runtime"
"github.com/hacdias/webdav/cmd" "github.com/hacdias/webdav/v2/cmd"
) )
func main() { func main() {
+31 -10
View File
@@ -4,12 +4,17 @@ import (
"context" "context"
"log" "log"
"net/http" "net/http"
"strings"
) )
// CorsCfg is the CORS config. // CorsCfg is the CORS config.
type CorsCfg struct { type CorsCfg struct {
Enabled bool Enabled bool
AllowedHosts []string Credentials bool
AllowedHeaders []string
AllowedHosts []string
AllowedMethods []string
ExposedHeaders []string
} }
// Config is the configuration of a WebDAV instance. // Config is the configuration of a WebDAV instance.
@@ -25,19 +30,34 @@ func (c *Config) ServeHTTP(w http.ResponseWriter, r *http.Request) {
u := c.User u := c.User
requestOrigin := r.Header.Get("Origin") requestOrigin := r.Header.Get("Origin")
// add cors headers before any operation so even on 401 unauthorized cors will working only when Origin header is present so request came from browser // Add CORS headers before any operation so even on a 401 unauthorized status, CORS will work.
if c.Cors.Enabled && requestOrigin != "" { if c.Cors.Enabled && requestOrigin != "" {
headers := w.Header() headers := w.Header()
if len(c.Cors.AllowedHosts) == 1 && c.Cors.AllowedHosts[0] == "*" { allowedHeaders := strings.Join(c.Cors.AllowedHeaders, ", ")
headers.Set("Access-Control-Allow-Methods", "*") allowedMethods := strings.Join(c.Cors.AllowedMethods, ", ")
headers.Set("Access-Control-Allow-Headers", "*") exposedHeaders := strings.Join(c.Cors.ExposedHeaders, ", ")
allowAllHosts := len(c.Cors.AllowedHosts) == 1 && c.Cors.AllowedHosts[0] == "*"
allowedHost := isAllowedHost(c.Cors.AllowedHosts, requestOrigin)
if allowAllHosts {
headers.Set("Access-Control-Allow-Origin", "*") headers.Set("Access-Control-Allow-Origin", "*")
} else if isAllowedHost(c.Cors.AllowedHosts, requestOrigin) { } else if allowedHost {
headers.Set("Access-Control-Allow-Origin", requestOrigin) headers.Set("Access-Control-Allow-Origin", requestOrigin)
headers.Set("Access-Control-Allow-Headers", "*") }
headers.Set("Access-Control-Allow-Methods", "*")
if allowAllHosts || allowedHost {
headers.Set("Access-Control-Allow-Headers", allowedHeaders)
headers.Set("Access-Control-Allow-Methods", allowedMethods)
if c.Cors.Credentials {
headers.Set("Access-Control-Allow-Credentials", "true")
}
if len(c.Cors.ExposedHeaders) > 0 {
headers.Set("Access-Control-Expose-Headers", exposedHeaders)
}
} }
} }
@@ -45,6 +65,7 @@ func (c *Config) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return return
} }
// Authentication
if c.Auth { if c.Auth {
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`) w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)