From b42beb0371cd8bc31a74a05c721ae9c8915d61f5 Mon Sep 17 00:00:00 2001 From: Eugene Gavrilov Date: Thu, 29 Nov 2018 00:17:46 +0500 Subject: [PATCH] [#23] add headers to configuration --- README.md | 4 ++++ config/config.go | 1 + config/config_test.go | 11 +++++++++++ router/router.go | 6 +++++- router/router_test.go | 37 ++++++++++++++++++++++++++++++++++++- 5 files changed, 57 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 683b4a3..e07b625 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,9 @@ server: hosts: # the hosts for which letsencrypt should request certificates - mydomain.tld - myotherdomain.tld + responseheaders: # response headers are added to every response (default: none) + Access-Control-Allow-Origin: "*" + Access-Control-Allow-Methods: "GET,POST" database: # for database see (configure database section) dialect: sqlite3 connection: data/gotify.db @@ -91,6 +94,7 @@ GOTIFY_SERVER_SSL_LETSENCRYPT_ACCEPTTOS=false GOTIFY_SERVER_SSL_LETSENCRYPT_CACHE=certs # lists are a little weird but do-able (: GOTIFY_SERVER_SSL_LETSENCRYPT_HOSTS=- mydomain.tld\n- myotherdomain.tld +GOTIFY_SERVER_RESPONSEHEADERS="Access-Control-Allow-Origin: \"*\"\nAccess-Control-Allow-Methods: \"GET,POST\"" GOTIFY_DATABASE_DIALECT=sqlite3 GOTIFY_DATABASE_CONNECTION=gotify.db GOTIFY_DEFAULTUSER_NAME=admin diff --git a/config/config.go b/config/config.go index 91e4d50..d885bc2 100644 --- a/config/config.go +++ b/config/config.go @@ -24,6 +24,7 @@ type Configuration struct { Hosts []string } } + ResponseHeaders map[string]string } Database struct { Dialect string `default:"sqlite3"` diff --git a/config/config_test.go b/config/config_test.go index 099cbbf..af76d82 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -12,12 +12,18 @@ import ( func TestConfigEnv(t *testing.T) { os.Setenv("GOTIFY_DEFAULTUSER_NAME", "jmattheis") os.Setenv("GOTIFY_SERVER_SSL_LETSENCRYPT_HOSTS", "- push.example.tld\n- push.other.tld") + os.Setenv("GOTIFY_SERVER_RESPONSEHEADERS", + "Access-Control-Allow-Origin: \"*\"\nAccess-Control-Allow-Methods: \"GET,POST\"", + ) conf := Get() assert.Equal(t, 80, conf.Server.Port, "should use defaults") assert.Equal(t, "jmattheis", conf.DefaultUser.Name, "should not use default but env var") assert.Equal(t, []string{"push.example.tld", "push.other.tld"}, conf.Server.SSL.LetsEncrypt.Hosts) + assert.Equal(t, "*", conf.Server.ResponseHeaders["Access-Control-Allow-Origin"]) + assert.Equal(t, "GET,POST", conf.Server.ResponseHeaders["Access-Control-Allow-Methods"]) os.Unsetenv("GOTIFY_DEFAULTUSER_NAME") os.Unsetenv("GOTIFY_SERVER_SSL_LETSENCRYPT_HOSTS") + os.Unsetenv("GOTIFY_SERVER_RESPONSEHEADERS") } func TestAddSlash(t *testing.T) { @@ -48,6 +54,9 @@ server: letsencrypt: hosts: - push.example.tld + responseheaders: + Access-Control-Allow-Origin: "*" + Access-Control-Allow-Methods: "GET,POST" database: dialect: mysql connection: user name @@ -65,6 +74,8 @@ defaultuser: assert.Equal(t, "12345", conf.DefaultUser.Pass) assert.Equal(t, "mysql", conf.Database.Dialect) assert.Equal(t, "user name", conf.Database.Connection) + assert.Equal(t, "*", conf.Server.ResponseHeaders["Access-Control-Allow-Origin"]) + assert.Equal(t, "GET,POST", conf.Server.ResponseHeaders["Access-Control-Allow-Methods"]) assert.Nil(t, os.Remove("config.yml")) } diff --git a/router/router.go b/router/router.go index 28cabd5..ccf49fe 100644 --- a/router/router.go +++ b/router/router.go @@ -50,11 +50,16 @@ func Create(db *database.GormDatabase, vInfo *model.VersionInfo, conf *config.Co g.Use(func(ctx *gin.Context) { ctx.Header("Content-Type", "application/json") + if mode.IsDev() { ctx.Header("Access-Control-Allow-Origin", "*") ctx.Header("Access-Control-Allow-Methods", "GET,POST,DELETE,OPTIONS,PUT") ctx.Header("Access-Control-Allow-Headers", "X-Gotify-Key,Authorization,Content-Type,Upgrade,Origin,Connection,Accept-Encoding,Accept-Language,Host") } + + for header, value := range conf.Server.ResponseHeaders { + ctx.Header(header, value) + } }) g.OPTIONS("/*any") @@ -88,7 +93,6 @@ func Create(db *database.GormDatabase, vInfo *model.VersionInfo, conf *config.Co app.POST("/:id/image", applicationHandler.UploadApplicationImage) - app.PUT("/:id", applicationHandler.UpdateApplication) app.DELETE("/:id", applicationHandler.DeleteApplication) diff --git a/router/router_test.go b/router/router_test.go index c23badc..c0e4be0 100644 --- a/router/router_test.go +++ b/router/router_test.go @@ -38,7 +38,10 @@ func (s *IntegrationSuite) BeforeTest(string, string) { var err error s.db = test.NewDBWithDefaultUser(s.T()) assert.Nil(s.T(), err) - g, closable := Create(s.db.GormDatabase, &model.VersionInfo{Version: "1.0.0", BuildDate: "2018-02-20-17:30:47", Commit: "asdasds"}, &config.Configuration{PassStrength: 5}) + g, closable := Create(s.db.GormDatabase, + &model.VersionInfo{Version: "1.0.0", BuildDate: "2018-02-20-17:30:47", Commit: "asdasds"}, + &config.Configuration{PassStrength: 5}, + ) s.closable = closable s.server = httptest.NewServer(g) } @@ -73,6 +76,38 @@ func (s *IntegrationSuite) TestHeaderInProd() { assert.Empty(s.T(), res.Header.Get("Access-Control-Allow-Origin")) } +func TestHeadersFromConfiguration(t *testing.T) { + mode.Set(mode.Prod) + db := test.NewDBWithDefaultUser(t) + defer db.Close() + + config := config.Configuration{PassStrength: 5} + config.Server.ResponseHeaders = map[string]string{ + "New-Cool-Header": "Nice", + "Access-Control-Allow-Origin": "---", + } + + g, closable := Create(db.GormDatabase, + &model.VersionInfo{Version: "1.0.0", BuildDate: "2018-02-20-17:30:47", Commit: "asdasds"}, + &config, + ) + server := httptest.NewServer(g) + + defer func() { + closable() + server.Close() + }() + + req, err := http.NewRequest("GET", fmt.Sprintf("%s/%s", server.URL, "version"), nil) + req.Header.Add("Content-Type", "application/json") + assert.Nil(t, err) + + res, err := client.Do(req) + assert.Nil(t, err) + assert.Equal(t, "---", res.Header.Get("Access-Control-Allow-Origin")) + assert.Equal(t, "Nice", res.Header.Get("New-Cool-Header")) +} + func (s *IntegrationSuite) TestOptionsRequest() { req := s.newRequest("OPTIONS", "version", "")