From 51b84067cb3788cb0dcf8fad6d0359fb28d3617f Mon Sep 17 00:00:00 2001 From: Kevin Bennett Date: Sun, 26 Jan 2020 21:02:59 -0700 Subject: [PATCH] make CORS feature configurable via environment variable --- README.md | 16 ++++++++++++++++ main.go | 37 ++++++++++++++++++++++++++++++++++++- rest/api.go | 30 +++++++++++++++++++++--------- 3 files changed, 73 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 96bc772..5f5ce90 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ Zookeeper REST API - [Zoorest](#zoorest) - [Usage](#usage) + - [CORS](#cors) - [API v1](#api-v1) - [List node childrens](#list-node-childrens) - [Errors](#errors) @@ -70,6 +71,21 @@ Typical usage scheme: [![tupical usage](img/usage.png)](img/usage.png) +### CORS +`Cross-origin resource sharing` is a feature that securely allows access to a zoorest instance from a web browser. This is an optional feature and is disabled by default. It is enabled and configured via OS environment variables. + +**ZOOREST_CORS_ENABLE** + enable the feature. Any non-empty value is considered "true" and enables it. + **default: false** + +**ZOOREST_CORS_DEBUG_ENABLE** + enable CORS debug mode Any non-null value is considered "true" and enables it. + **default: false** + +**ZOOREST_CORS_ALLOWED_ORIGINS** + comma delimited list of origin url patterns to allow access to the service. + **default: \*** (any origin) + ## API v1 ### List node childrens diff --git a/main.go b/main.go index 71c9780..db87033 100644 --- a/main.go +++ b/main.go @@ -3,9 +3,16 @@ package main import ( "flag" "github.com/Difrex/zoorest/rest" + "os" "strings" ) +const ( + CorsFeatureEnableEnvVar string = `ZOOREST_CORS_ENABLE` + CorsDebugModeEnvVar string = `ZOOREST_CORS_DEBUG_ENABLE` + CorsAllowedOrigins string = `ZOOREST_CORS_ALLOWED_ORIGINS` +) + var ( zk string listen string @@ -13,6 +20,7 @@ var ( mc bool mcHosts string mcPrefix string + ok bool ) // init ... @@ -49,7 +57,34 @@ func main() { zoo.MC = MC - rest.Serve(listen, zoo) + // get CORS settins from environment + // start by establishing defaults. + var cors = rest.CorsOptions{ + Enabled: false, + DebugEnabled: false, + AllowedOrigins: []string{"*"}, + } + + var corsEnabled string + var ok bool + corsEnabled, ok = os.LookupEnv(CorsFeatureEnableEnvVar) + if ok && corsEnabled != "" { + cors.Enabled = true + } + + var corsDebugEnabled string + corsDebugEnabled, ok = os.LookupEnv(CorsDebugModeEnvVar) + if ok && corsDebugEnabled != "" { + cors.DebugEnabled = true + } + + var corsAllowedOrigins string + corsAllowedOrigins, ok = os.LookupEnv(CorsAllowedOrigins) + if ok && corsAllowedOrigins != "" { + cors.AllowedOrigins = strings.Split(corsAllowedOrigins, ",") + } + + rest.Serve(listen, zoo, cors) } // getSlice returm slice diff --git a/rest/api.go b/rest/api.go index 4335ecb..0923cf1 100644 --- a/rest/api.go +++ b/rest/api.go @@ -39,6 +39,12 @@ type GetJSON struct { Data interface{} `json:"data"` } +type CorsOptions struct { + Enabled bool + DebugEnabled bool + AllowedOrigins []string +} + // LS ... func (zk ZooNode) LS(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) @@ -210,7 +216,7 @@ func (zk ZooNode) GetJSON(w http.ResponseWriter, r *http.Request) { } // Serve ... -func Serve(listen string, zk ZooNode) { +func Serve(listen string, zk ZooNode, cors_options CorsOptions) { r := mux.NewRouter() // API v1 @@ -227,16 +233,22 @@ func Serve(listen string, zk ZooNode) { r.HandleFunc("/v2{path:[A-Za-z0-9-_/.:]+}", zk.RM).Methods("DELETE") r.HandleFunc("/v2{path:[A-Za-z0-9-_/.:]+}", zk.UP).Methods("PUT", "POST", "PATCH") - c := cors.New(cors.Options{ - AllowedMethods: []string{"GET", "LIST", "DELETE", "PUT", "POST", "PATCH"}, - - // Enable Debugging for testing, consider disabling in production - Debug: true, - }) + var handler http.Handler - handler := c.Handler(r) + if cors_options.Enabled { + c := cors.New(cors.Options{ + AllowedMethods: []string{"GET", "LIST", "DELETE", "PUT", "POST", "PATCH"}, + AllowedOrigins: cors_options.AllowedOrigins, + // Enable Debugging for testing, consider disabling in production + Debug: cors_options.DebugEnabled, + }) - http.Handle("/", handler) + // decorate with cors handler + handler = c.Handler(r) + } else { + // default to no + handler = r + } srv := http.Server{ Handler: handler,