diff --git a/api/authentication.go b/api/authentication.go index 792e6e2..bbac2c9 100644 --- a/api/authentication.go +++ b/api/authentication.go @@ -242,6 +242,14 @@ func authenticateRequest(w http.ResponseWriter, r *http.Request, targetHandler h } func checkAuth(w http.ResponseWriter, r *http.Request, authRequired bool) (token *AuthToken, handled bool) { + // Return highest possible permissions in dev mode. + if devMode() { + return &AuthToken{ + Read: PermitSelf, + Write: PermitSelf, + }, false + } + // Check for valid API key. token = checkAPIKey(r) if token != nil { @@ -462,7 +470,12 @@ func deleteSession(sessionKey string) { } func isReadMethod(method string) bool { - return method == http.MethodGet || method == http.MethodHead + switch method { + case http.MethodGet, http.MethodHead, http.MethodOptions: + return true + default: + return false + } } func parseAPIPermission(s string) (Permission, error) { diff --git a/api/config.go b/api/config.go index 706f5b4..ebcc515 100644 --- a/api/config.go +++ b/api/config.go @@ -19,6 +19,8 @@ var ( defaultListenAddress string configuredAPIKeys config.StringArrayOption + + devMode config.BoolOption ) func init() { @@ -79,6 +81,8 @@ func registerConfig() error { } configuredAPIKeys = config.GetAsStringArray(CfgAPIKeys, []string{}) + devMode = config.Concurrent.GetAsBool(config.CfgDevModeKey, false) + return nil } diff --git a/api/endpoints.go b/api/endpoints.go index c977fee..bdb068d 100644 --- a/api/endpoints.go +++ b/api/endpoints.go @@ -256,6 +256,9 @@ func (eh *endpointHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { apiRequest.InputData = inputData case http.MethodGet: // Nothing special to do here. + case http.MethodOptions: + w.WriteHeader(http.StatusNoContent) + return default: http.Error(w, "Unsupported method for the actions API.", http.StatusMethodNotAllowed) return @@ -308,7 +311,6 @@ func (eh *endpointHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Write response. w.Header().Set("Content-Type", apiEndpoint.MimeType+"; charset=utf-8") w.Header().Set("Content-Length", strconv.Itoa(len(responseData))) - w.Header().Set("X-Content-Type-Options", "nosniff") w.WriteHeader(http.StatusOK) _, err = w.Write(responseData) if err != nil { diff --git a/api/router.go b/api/router.go index 81154a5..6b2280c 100644 --- a/api/router.go +++ b/api/router.go @@ -16,17 +16,6 @@ var ( // gorilla mux mainMux = mux.NewRouter() - // middlewares - middlewareHandler = &mwHandler{ - final: mainMux, - handlers: []Middleware{ - ModuleWorker, - LogTracer, - RequestLogger, - authMiddleware, - }, - } - // main server and lock server = &http.Server{} handlerLock sync.RWMutex @@ -46,18 +35,12 @@ func RegisterHandleFunc(path string, handleFunc func(http.ResponseWriter, *http. return mainMux.HandleFunc(path, handleFunc) } -// RegisterMiddleware registers a middle function with the API endoint. -func RegisterMiddleware(middleware Middleware) { - handlerLock.Lock() - defer handlerLock.Unlock() - middlewareHandler.handlers = append(middlewareHandler.handlers, middleware) -} - // Serve starts serving the API endpoint. func Serve() { // configure server server.Addr = listenAddressConfig() server.Handler = &mainHandler{ + // TODO: mainMux should not be modified anymore. mux: mainMux, } @@ -134,6 +117,22 @@ func (mh *mainHandler) handle(w http.ResponseWriter, r *http.Request) error { return nil } + // Add security headers. + if !devMode() { + w.Header().Set( + "Content-Security-Policy", + "default-src 'self'; "+ + "style-src 'self' 'unsafe-inline'; "+ + "img-src 'self' data:", + ) + w.Header().Set("Referrer-Policy", "no-referrer") + w.Header().Set("X-Content-Type-Options", "nosniff") + w.Header().Set("X-Frame-Options", "deny") + w.Header().Set("X-XSS-Protection", "1; mode=block") + } else { + w.Header().Set("Access-Control-Allow-Origin", "*") + } + // Handle request. switch { case handler != nil: