diff --git a/http.go b/http.go index 89a686f..c26d9b2 100644 --- a/http.go +++ b/http.go @@ -16,6 +16,7 @@ import ( rice "github.com/GeertJohan/go.rice" "github.com/c2h5oh/datasize" + "github.com/unrolled/secure" ) // MegaUploader acts as controller for all the application. Since this is inherently a web-focused @@ -23,11 +24,21 @@ import ( type MegaUploader struct { Conf Config configLock *sync.RWMutex + secureMW *secure.Secure } // NewMegaUploader create a new mega uploader func NewMegaUploader(c Config) MegaUploader { - return MegaUploader{Conf: c, configLock: new(sync.RWMutex)} + return MegaUploader{ + Conf: c, + configLock: new(sync.RWMutex), + secureMW: secure.New(secure.Options{ + FrameDeny: true, + ContentTypeNosniff: true, + BrowserXssFilter: true, + ContentSecurityPolicy: "default-src 'self'", + }), + } } func (mu *MegaUploader) ChangeConf(newconf Config) { @@ -37,27 +48,37 @@ func (mu *MegaUploader) ChangeConf(newconf Config) { } // confAcquire is a middleware to read-lock configuration -func (mu *MegaUploader) confAcquire(inner func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) { - return func(w http.ResponseWriter, r *http.Request) { +func (mu *MegaUploader) confAcquire(inner http.Handler) http.Handler { + f := func(w http.ResponseWriter, r *http.Request) { mu.configLock.RLock() - inner(w, r) + inner.ServeHTTP(w, r) mu.configLock.RUnlock() } + + return http.HandlerFunc(f) +} + +func (mu *MegaUploader) privateMiddleware(inner func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) { + return mu.secureMW.Handler(mu.confAcquire(requireUserMiddleware(inner))).ServeHTTP +} +func (mu *MegaUploader) publicMiddleware(inner func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) { + return mu.secureMW.Handler(requireUserMiddleware(inner)).ServeHTTP } // SetupRoutes adds API routes func (mu *MegaUploader) SetupRoutes() { + prefix := strings.TrimRight(mu.Conf.Global.RoutePrefix, "/") - http.HandleFunc(prefix+"/", mu.confAcquire(requireUserMiddleware(mu.home))) - http.HandleFunc(prefix+"/upload/", mu.confAcquire(requireUserMiddleware(mu.uploadUI))) + http.HandleFunc(prefix+"/", mu.privateMiddleware(mu.home)) + http.HandleFunc(prefix+"/upload/", mu.privateMiddleware(mu.uploadUI)) static := rice.MustFindBox("res/static") - http.HandleFunc(prefix+"/static/", requireUserMiddleware( + http.HandleFunc(prefix+"/static/", mu.publicMiddleware( http.StripPrefix(prefix+"/static/", http.FileServer(static.HTTPBox())).ServeHTTP, )) - http.HandleFunc(prefix+"/api/share", mu.confAcquire(requireUserMiddleware(mu.listShares))) - http.HandleFunc(prefix+"/api/share/", mu.confAcquire(requireUserMiddleware(mu.getShare))) - http.HandleFunc(prefix+"/api/upload/", mu.confAcquire(requireUserMiddleware(mu.upload))) + http.HandleFunc(prefix+"/api/share", mu.privateMiddleware(mu.listShares)) + http.HandleFunc(prefix+"/api/share/", mu.privateMiddleware(mu.getShare)) + http.HandleFunc(prefix+"/api/upload/", mu.privateMiddleware(mu.upload)) } func getUser(r *http.Request) (string, error) { @@ -68,8 +89,8 @@ func getUser(r *http.Request) (string, error) { return user, nil } -func requireUserMiddleware(inner func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) { - return func(w http.ResponseWriter, r *http.Request) { +func requireUserMiddleware(inner func(w http.ResponseWriter, r *http.Request)) http.Handler { + f := func(w http.ResponseWriter, r *http.Request) { _, err := getUser(r) if err != nil { http.Error(w, "Only logged-in users are authorized", http.StatusUnauthorized) @@ -77,6 +98,7 @@ func requireUserMiddleware(inner func(w http.ResponseWriter, r *http.Request)) f } inner(w, r) } + return http.HandlerFunc(f) } func (mu *MegaUploader) listShares(w http.ResponseWriter, r *http.Request) {