diff --git a/config-raw.json b/config-raw.json index 6bb00e6cf..b43345f7b 100644 --- a/config-raw.json +++ b/config-raw.json @@ -3,10 +3,15 @@ { "key": "service", "children": [ + { + "key": "secret", + "default_value": "\u003ca-secret\u003e", + "comment": "This secret is used to sign JWT tokens and for other cryptographic operations.\nDefault is a random secret which will be generated at each startup of Vikunja.\n(This means all already issued tokens will be invalid once you restart Vikunja)" + }, { "key": "JWTSecret", "default_value": "\u003cjwt-secret\u003e", - "comment": "This token is used to verify issued JWT tokens.\nDefault is a random token which will be generated at each startup of Vikunja.\n(This means all already issued tokens will be invalid once you restart Vikunja)" + "comment": "Deprecated: use service.secret instead. If set, its value will be copied to service.secret." }, { "key": "jwtttl", diff --git a/pkg/config/config.go b/pkg/config/config.go index c1bac6ee9..764f33196 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -41,7 +41,8 @@ type Key string // These constants hold all config value keys const ( // #nosec - ServiceJWTSecret Key = `service.JWTSecret` + ServiceSecret Key = `service.secret` + ServiceJWTSecret Key = `service.JWTSecret` // #nosec G101 -- Deprecated config key alias, not a credential ServiceJWTTTL Key = `service.jwtttl` ServiceJWTTTLLong Key = `service.jwtttllong` ServiceJWTTTLShort Key = `service.jwtttlshort` @@ -333,7 +334,7 @@ func InitDefaultConfig() { } // Service - ServiceJWTSecret.setDefault(random) + ServiceSecret.setDefault(random) ServiceJWTTTL.setDefault(259200) // 72 hours ServiceJWTTTLLong.setDefault(2592000) // 30 days ServiceJWTTTLShort.setDefault(600) // 10 minutes @@ -635,6 +636,17 @@ func InitConfig() { readConfigValuesFromFiles() + // Deprecation: migrate service.JWTSecret → service.secret only when the + // user has not explicitly set service.secret (so the new key takes precedence). + if ServiceJWTSecret.GetString() != "" { + if viper.IsSet(string(ServiceSecret)) { + log.Warning("config: both service.secret and service.jwtsecret are set. Using service.secret. Please remove service.jwtsecret, it is deprecated and will be removed in a future release.") + } else { + log.Warning("config: service.jwtsecret is deprecated and will be removed in a future release. Please use service.secret instead.") + ServiceSecret.Set(ServiceJWTSecret.GetString()) + } + } + if _, err := url.ParseRequestURI(AvatarGravatarBaseURL.GetString()); err != nil { log.Fatalf("Could not parse gravatarbaseurl: %s", err) } diff --git a/pkg/doctor/config.go b/pkg/doctor/config.go index b9114d757..209c6e6a5 100644 --- a/pkg/doctor/config.go +++ b/pkg/doctor/config.go @@ -78,7 +78,7 @@ func checkPublicURL() CheckResult { func checkJWTSecret() CheckResult { // We can't check the actual value, but we can check if it's the default length // which would indicate it was auto-generated - secret := config.ServiceJWTSecret.GetString() + secret := config.ServiceSecret.GetString() // Auto-generated secrets are 64 hex characters (32 bytes) if len(secret) == 64 { diff --git a/pkg/e2etests/integrations.go b/pkg/e2etests/integrations.go index cb1ce6371..6ac8860d6 100644 --- a/pkg/e2etests/integrations.go +++ b/pkg/e2etests/integrations.go @@ -126,7 +126,7 @@ func addUserTokenToContext(t *testing.T, u *user.User, c *echo.Context) { token, err := auth.NewUserJWTAuthtoken(u, "test-session-id") require.NoError(t, err) tken, err := jwt.Parse(token, func(_ *jwt.Token) (interface{}, error) { - return []byte(config.ServiceJWTSecret.GetString()), nil + return []byte(config.ServiceSecret.GetString()), nil }) require.NoError(t, err) c.Set("user", tken) diff --git a/pkg/modules/auth/auth.go b/pkg/modules/auth/auth.go index dc2ba2c78..2b6662031 100644 --- a/pkg/modules/auth/auth.go +++ b/pkg/modules/auth/auth.go @@ -135,7 +135,7 @@ func NewUserJWTAuthtoken(u *user.User, sessionID string) (token string, err erro claims["sid"] = sessionID claims["jti"] = uuid.New().String() - return t.SignedString([]byte(config.ServiceJWTSecret.GetString())) + return t.SignedString([]byte(config.ServiceSecret.GetString())) } // NewLinkShareJWTAuthtoken creates a new jwt token from a link share @@ -156,7 +156,7 @@ func NewLinkShareJWTAuthtoken(share *models.LinkSharing) (token string, err erro claims["exp"] = exp // Generate encoded token and send it as response. - return t.SignedString([]byte(config.ServiceJWTSecret.GetString())) + return t.SignedString([]byte(config.ServiceSecret.GetString())) } // GetAuthFromClaims returns a web.Auth object from jwt claims diff --git a/pkg/routes/api_tokens.go b/pkg/routes/api_tokens.go index 7d8ffe35b..31045f28c 100644 --- a/pkg/routes/api_tokens.go +++ b/pkg/routes/api_tokens.go @@ -39,7 +39,7 @@ const ErrCodeInvalidToken = 11 func SetupTokenMiddleware() echo.MiddlewareFunc { return echojwt.WithConfig(echojwt.Config{ - SigningKey: []byte(config.ServiceJWTSecret.GetString()), + SigningKey: []byte(config.ServiceSecret.GetString()), Skipper: func(c *echo.Context) bool { authHeader := c.Request().Header.Values("Authorization") if len(authHeader) == 0 { diff --git a/pkg/webtests/integrations.go b/pkg/webtests/integrations.go index b00f3d8a1..0decb1f0a 100644 --- a/pkg/webtests/integrations.go +++ b/pkg/webtests/integrations.go @@ -134,7 +134,7 @@ func addUserTokenToContext(t *testing.T, user *user.User, c *echo.Context) { require.NoError(t, err) // We send the string token through the parsing function to get a valid jwt.Token tken, err := jwt.Parse(token, func(_ *jwt.Token) (interface{}, error) { - return []byte(config.ServiceJWTSecret.GetString()), nil + return []byte(config.ServiceSecret.GetString()), nil }) require.NoError(t, err) c.Set("user", tken) @@ -146,7 +146,7 @@ func addLinkShareTokenToContext(t *testing.T, share *models.LinkSharing, c *echo require.NoError(t, err) // We send the string token through the parsing function to get a valid jwt.Token tken, err := jwt.Parse(token, func(_ *jwt.Token) (interface{}, error) { - return []byte(config.ServiceJWTSecret.GetString()), nil + return []byte(config.ServiceSecret.GetString()), nil }) require.NoError(t, err) c.Set("user", tken)