From 1e1895de208f6e5e420023771e5914721a787afc Mon Sep 17 00:00:00 2001 From: Denis Gukov Date: Fri, 20 Dec 2024 02:23:58 +0500 Subject: [PATCH 1/8] feat(tls): add config and listener --- cli/cmd/root.go | 47 ++++++++++++++++++++++++++++++++++++++++++++--- util/config.go | 13 ++++++++++++- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/cli/cmd/root.go b/cli/cmd/root.go index 5b622e4a..fb1092c0 100644 --- a/cli/cmd/root.go +++ b/cli/cmd/root.go @@ -3,9 +3,12 @@ package cmd import ( "fmt" "net/http" + "net/url" "os" "strings" + "github.com/gorilla/context" + "github.com/gorilla/handlers" "github.com/semaphoreui/semaphore/api" "github.com/semaphoreui/semaphore/api/sockets" "github.com/semaphoreui/semaphore/db" @@ -13,8 +16,6 @@ import ( "github.com/semaphoreui/semaphore/services/schedules" "github.com/semaphoreui/semaphore/services/tasks" "github.com/semaphoreui/semaphore/util" - "github.com/gorilla/context" - "github.com/gorilla/handlers" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -107,7 +108,47 @@ func runService() { store.Close("root") } - err := http.ListenAndServe(util.Config.Interface+port, cropTrailingSlashMiddleware(router)) + var err error + if util.Config.TLS != nil { + if util.Config.TLS.HTTPRedirectPort != nil { + + go func() { + httpRedirectPort := fmt.Sprintf(":%d", *util.Config.TLS.HTTPRedirectPort) + err = http.ListenAndServe(httpRedirectPort, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + target := "https://" + + if util.Config.WebHost != "" { + webHost, err2 := url.Parse(util.Config.WebHost) + if err2 != nil { + log.Panic(err2) + } + target += webHost.Scheme + webHost.Host + r.URL.Path + } else { + hostParts := strings.Split(r.Host, ":") + host := hostParts[0] + target += host + port[1:] + r.URL.Path + } + + if len(r.URL.RawQuery) > 0 { + target += "?" + r.URL.RawQuery + } + http.Redirect(w, r, target, http.StatusTemporaryRedirect) + })) + if err != nil { + log.Panic(err) + } + }() + } + + err = http.ListenAndServeTLS(util.Config.Interface+port, util.Config.TLS.TLSCertFile, util.Config.TLS.TLSKeyFile, cropTrailingSlashMiddleware(router)) + + if err != nil { + log.Panic(err) + } + + } else { + err = http.ListenAndServe(util.Config.Interface+port, cropTrailingSlashMiddleware(router)) + } if err != nil { log.Panic(err) diff --git a/util/config.go b/util/config.go index d2824c51..87e9142f 100644 --- a/util/config.go +++ b/util/config.go @@ -112,6 +112,12 @@ type RunnerConfig struct { MaxParallelTasks int `json:"max_parallel_tasks,omitempty" default:"1" env:"SEMAPHORE_RUNNER_MAX_PARALLEL_TASKS"` } +type TLSConfig struct { + TLSCertFile string `json:"tls_cert_file,omitempty" env:"SEMAPHORE_TLS_CERT_FILE"` + TLSKeyFile string `json:"tls_key_file,omitempty" env:"SEMAPHORE_TLS_KEY_FILE"` + HTTPRedirectPort *int `json:"http_redirect_port,omitempty" env:"SEMAPHORE_TLS_HTTP_PORT"` +} + // ConfigType mapping between Config and the json file that sets it type ConfigType struct { MySQL *DbConfig `json:"mysql,omitempty"` @@ -122,7 +128,8 @@ type ConfigType struct { // Format `:port_num` eg, :3000 // if : is missing it will be corrected - Port string `json:"port,omitempty" default:":3000" rule:"^:?([0-9]{1,5})$" env:"SEMAPHORE_PORT"` + Port string `json:"port,omitempty" default:":3000" rule:"^:?([0-9]{1,5})$" env:"SEMAPHORE_PORT"` + TLS *TLSConfig `json:"tls,omitempty"` // Interface ip, put in front of the port. // defaults to empty @@ -231,6 +238,10 @@ func ConfigInit(configPath string, noConfigFile bool) { Config = NewConfigType() Config.Apps = map[string]App{} + if os.Getenv("SEMAPHORE_TLS_CERT_FILE") != "" { + Config.TLS = &TLSConfig{} + } + if !noConfigFile { loadConfigFile(configPath) } From c59f2cb584cc26be494db2b3f66e52ea1cfcf0ff Mon Sep 17 00:00:00 2001 From: Denis Gukov Date: Fri, 20 Dec 2024 02:26:24 +0500 Subject: [PATCH 2/8] feat(tls): do not redirect POST requests --- cli/cmd/root.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cli/cmd/root.go b/cli/cmd/root.go index fb1092c0..9417761c 100644 --- a/cli/cmd/root.go +++ b/cli/cmd/root.go @@ -132,6 +132,12 @@ func runService() { if len(r.URL.RawQuery) > 0 { target += "?" + r.URL.RawQuery } + + if r.Method != "GET" && r.Method != "HEAD" && r.Method != "OPTIONS" { + http.Error(w, "http requests forbidden", http.StatusForbidden) + return + } + http.Redirect(w, r, target, http.StatusTemporaryRedirect) })) if err != nil { From 25bbbcae3a18abae05dcab58d2fa4e41404b3ac8 Mon Sep 17 00:00:00 2001 From: Denis Gukov Date: Sat, 21 Dec 2024 00:08:46 +0500 Subject: [PATCH 3/8] fix(tls): correct redirect --- .gitignore | 1 + cli/cmd/root.go | 4 ++-- util/config.go | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index c2b9288f..b7725c35 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ gin-bin build/ +/certs/ web/public/js/bundle.js web/public/css/*.* web/public/html/**/*.* diff --git a/cli/cmd/root.go b/cli/cmd/root.go index 9417761c..4ca79e3a 100644 --- a/cli/cmd/root.go +++ b/cli/cmd/root.go @@ -126,7 +126,7 @@ func runService() { } else { hostParts := strings.Split(r.Host, ":") host := hostParts[0] - target += host + port[1:] + r.URL.Path + target += host + port + r.URL.Path } if len(r.URL.RawQuery) > 0 { @@ -146,7 +146,7 @@ func runService() { }() } - err = http.ListenAndServeTLS(util.Config.Interface+port, util.Config.TLS.TLSCertFile, util.Config.TLS.TLSKeyFile, cropTrailingSlashMiddleware(router)) + err = http.ListenAndServeTLS(util.Config.Interface+port, util.Config.TLS.CertFile, util.Config.TLS.KeyFile, cropTrailingSlashMiddleware(router)) if err != nil { log.Panic(err) diff --git a/util/config.go b/util/config.go index 87e9142f..c7ea77b9 100644 --- a/util/config.go +++ b/util/config.go @@ -113,8 +113,8 @@ type RunnerConfig struct { } type TLSConfig struct { - TLSCertFile string `json:"tls_cert_file,omitempty" env:"SEMAPHORE_TLS_CERT_FILE"` - TLSKeyFile string `json:"tls_key_file,omitempty" env:"SEMAPHORE_TLS_KEY_FILE"` + CertFile string `json:"cert_file,omitempty" env:"SEMAPHORE_TLS_CERT_FILE"` + KeyFile string `json:"key_file,omitempty" env:"SEMAPHORE_TLS_KEY_FILE"` HTTPRedirectPort *int `json:"http_redirect_port,omitempty" env:"SEMAPHORE_TLS_HTTP_PORT"` } From 5e2aa5ca4aef5fd56c78a90eb3003fcbe2b8ecf2 Mon Sep 17 00:00:00 2001 From: Denis Gukov Date: Sat, 21 Dec 2024 00:39:35 +0500 Subject: [PATCH 4/8] feat(tls): add flag Enabled --- cli/cmd/root.go | 4 ++-- util/config.go | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/cli/cmd/root.go b/cli/cmd/root.go index 4ca79e3a..24b356dd 100644 --- a/cli/cmd/root.go +++ b/cli/cmd/root.go @@ -109,7 +109,7 @@ func runService() { } var err error - if util.Config.TLS != nil { + if util.Config.TLS.Enabled { if util.Config.TLS.HTTPRedirectPort != nil { go func() { @@ -138,7 +138,7 @@ func runService() { return } - http.Redirect(w, r, target, http.StatusTemporaryRedirect) + http.Redirect(w, nil, target, http.StatusTemporaryRedirect) })) if err != nil { log.Panic(err) diff --git a/util/config.go b/util/config.go index c7ea77b9..33dc2877 100644 --- a/util/config.go +++ b/util/config.go @@ -113,9 +113,10 @@ type RunnerConfig struct { } type TLSConfig struct { + Enabled bool `json:"enabled,omitempty" env:"SEMAPHORE_TLS_ENABLED"` CertFile string `json:"cert_file,omitempty" env:"SEMAPHORE_TLS_CERT_FILE"` KeyFile string `json:"key_file,omitempty" env:"SEMAPHORE_TLS_KEY_FILE"` - HTTPRedirectPort *int `json:"http_redirect_port,omitempty" env:"SEMAPHORE_TLS_HTTP_PORT"` + HTTPRedirectPort *int `json:"http_redirect_port,omitempty" env:"SEMAPHORE_TLS_HTTP_REDIRECT_PORT"` } // ConfigType mapping between Config and the json file that sets it @@ -236,15 +237,12 @@ func ConfigInit(configPath string, noConfigFile bool) { fmt.Println("Loading config") Config = NewConfigType() - Config.Apps = map[string]App{} - - if os.Getenv("SEMAPHORE_TLS_CERT_FILE") != "" { - Config.TLS = &TLSConfig{} - } + //Config.Apps = map[string]App{} if !noConfigFile { loadConfigFile(configPath) } + loadConfigEnvironment() loadConfigDefaults() From 642a2e235e0adcff13f58d25fcf0dd94f579965c Mon Sep 17 00:00:00 2001 From: Denis Gukov Date: Sat, 21 Dec 2024 00:41:47 +0500 Subject: [PATCH 5/8] chore(tls): remove extra omitempty flags --- util/config.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/util/config.go b/util/config.go index 33dc2877..d5bbeac9 100644 --- a/util/config.go +++ b/util/config.go @@ -113,9 +113,9 @@ type RunnerConfig struct { } type TLSConfig struct { - Enabled bool `json:"enabled,omitempty" env:"SEMAPHORE_TLS_ENABLED"` - CertFile string `json:"cert_file,omitempty" env:"SEMAPHORE_TLS_CERT_FILE"` - KeyFile string `json:"key_file,omitempty" env:"SEMAPHORE_TLS_KEY_FILE"` + Enabled bool `json:"enabled" env:"SEMAPHORE_TLS_ENABLED"` + CertFile string `json:"cert_file" env:"SEMAPHORE_TLS_CERT_FILE"` + KeyFile string `json:"key_file" env:"SEMAPHORE_TLS_KEY_FILE"` HTTPRedirectPort *int `json:"http_redirect_port,omitempty" env:"SEMAPHORE_TLS_HTTP_REDIRECT_PORT"` } From 35e886b436e922cdd57f957d044bd7377cc744fd Mon Sep 17 00:00:00 2001 From: Denis Gukov Date: Sat, 21 Dec 2024 00:49:40 +0500 Subject: [PATCH 6/8] fix(ci): minor bug from codacy --- .devcontainer/postCreateCommand.sh | 2 ++ .vscode/launch.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.devcontainer/postCreateCommand.sh b/.devcontainer/postCreateCommand.sh index 7af1a2c4..86cc32d6 100755 --- a/.devcontainer/postCreateCommand.sh +++ b/.devcontainer/postCreateCommand.sh @@ -1,3 +1,5 @@ +#!/bin/sh + go install github.com/go-task/task/v3/cmd/task@latest (cd ./web && npm install) diff --git a/.vscode/launch.json b/.vscode/launch.json index 4440b412..0896d4b2 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -46,7 +46,7 @@ "runtimeExecutable": "task", "args": ["e2e:test:local"], "cwd": "${workspaceFolder}", - "console": "integratedTerminal", + "console": "integratedTerminal" } ] } \ No newline at end of file From 834f75bac07be25d8357efe6c318d99400cb390e Mon Sep 17 00:00:00 2001 From: Denis Gukov Date: Sat, 21 Dec 2024 00:51:11 +0500 Subject: [PATCH 7/8] feat(be): http only for cookies --- api/login.go | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/api/login.go b/api/login.go index 95836c1f..df114742 100644 --- a/api/login.go +++ b/api/login.go @@ -16,13 +16,13 @@ import ( "text/template" "time" + "github.com/coreos/go-oidc/v3/oidc" + "github.com/go-ldap/ldap/v3" + "github.com/gorilla/mux" "github.com/semaphoreui/semaphore/api/helpers" "github.com/semaphoreui/semaphore/db" "github.com/semaphoreui/semaphore/pkg/random" "github.com/semaphoreui/semaphore/util" - "github.com/coreos/go-oidc/v3/oidc" - "github.com/go-ldap/ldap/v3" - "github.com/gorilla/mux" log "github.com/sirupsen/logrus" "golang.org/x/crypto/bcrypt" "golang.org/x/oauth2" @@ -171,9 +171,10 @@ func createSession(w http.ResponseWriter, r *http.Request, user db.User) { } http.SetCookie(w, &http.Cookie{ - Name: "semaphore", - Value: encoded, - Path: "/", + Name: "semaphore", + Value: encoded, + Path: "/", + HttpOnly: true, }) } @@ -317,10 +318,11 @@ func login(w http.ResponseWriter, r *http.Request) { func logout(w http.ResponseWriter, r *http.Request) { http.SetCookie(w, &http.Cookie{ - Name: "semaphore", - Value: "", - Expires: time.Now().Add(24 * 7 * time.Hour * -1), - Path: "/", + Name: "semaphore", + Value: "", + Expires: time.Now().Add(24 * 7 * time.Hour * -1), + Path: "/", + HttpOnly: true, }) w.WriteHeader(http.StatusNoContent) From d100bee70fb52abb00ddbdf7f795138b77139db2 Mon Sep 17 00:00:00 2001 From: Denis Gukov Date: Sat, 21 Dec 2024 01:25:43 +0500 Subject: [PATCH 8/8] fix(be): return app init --- util/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/config.go b/util/config.go index d5bbeac9..3f7bad3d 100644 --- a/util/config.go +++ b/util/config.go @@ -237,7 +237,7 @@ func ConfigInit(configPath string, noConfigFile bool) { fmt.Println("Loading config") Config = NewConfigType() - //Config.Apps = map[string]App{} + Config.Apps = map[string]App{} if !noConfigFile { loadConfigFile(configPath)