From 3afbeb1ab00423fd65abc4864314c93389a7b273 Mon Sep 17 00:00:00 2001 From: h Date: Sat, 28 Feb 2026 04:11:11 -0700 Subject: [PATCH 1/4] Adding TLS options to Redis connection. --- config-raw.json | 29 +++++++++++++++++++++++++++-- pkg/config/config.go | 18 ++++++++++++++---- pkg/red/redis.go | 33 +++++++++++++++++++++++++++++++-- 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/config-raw.json b/config-raw.json index 277da7ae4..bf179861d 100644 --- a/config-raw.json +++ b/config-raw.json @@ -256,7 +256,7 @@ { "key": "enabled", "default_value": "false", - "comment": "Whether to enable redis or not" + "comment": "Whether to enable redis or not." }, { "key": "host", @@ -266,12 +266,37 @@ { "key": "password", "default_value": "", - "comment": "The password used to authenticate against the redis server" + "comment": "The password used to authenticate against the redis server." }, { "key": "db", "default_value": "0", "comment": "0 means default database" + }, + { + "key": "tls", + "default_value": "false", + "comment": "Whether to enable TLS or not." + }, + { + "key": "tlsclientcert", + "default_value": "", + "comment": "The path to a client certificate, if you choose to use one." + }, + { + "key": "tlsclientkey", + "default_value": "", + "comment": "The path to the client certificate's private key." + }, + { + "key": "tlscacert", + "default_value": "", + "comment": "The path to a certificate authority certificate, for verifying the server's certificate." + }, + { + "key": "tlsskipverify", + "default_value": "true", + "comment": "Whether to skip verification of the server's TLS certificate." } ] }, diff --git a/pkg/config/config.go b/pkg/config/config.go index cc61ec51b..c9c5a4a16 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -129,10 +129,15 @@ const ( MailerQueueTimeout Key = `mailer.queuetimeout` MailerForceSSL Key = `mailer.forcessl` - RedisEnabled Key = `redis.enabled` - RedisHost Key = `redis.host` - RedisPassword Key = `redis.password` - RedisDB Key = `redis.db` + RedisEnabled Key = `redis.enabled` + RedisHost Key = `redis.host` + RedisPassword Key = `redis.password` + RedisDB Key = `redis.db` + RedisTLS Key = `redis.tls` + RedisTLSClientCert Key = `redis.tlsclientcert` + RedisTLSClientKey Key = `redis.tlsclientkey` + RedisTLSClientCACert Key = `redis.tlsclientcacert` + RedisTLSSkipVerify Key = `redis.tlsskipverify` LogEnabled Key = `log.enabled` LogStandard Key = `log.standard` @@ -411,6 +416,11 @@ func InitDefaultConfig() { RedisHost.setDefault("localhost:6379") RedisPassword.setDefault("") RedisDB.setDefault(0) + RedisTLS.setDefault(false) + RedisTLSClientCert.setDefault("") + RedisTLSClientKey.setDefault("") + RedisTLSClientCACert.setDefault("") + RedisTLSSkipVerify.setDefault(false) // Logger LogEnabled.setDefault(true) LogStandard.setDefault("stdout") diff --git a/pkg/red/redis.go b/pkg/red/redis.go index abdc4f6cb..571bb1077 100644 --- a/pkg/red/redis.go +++ b/pkg/red/redis.go @@ -18,6 +18,9 @@ package red import ( "context" + "crypto/tls" + "crypto/x509" + "os" "code.vikunja.io/api/pkg/config" "code.vikunja.io/api/pkg/log" @@ -40,11 +43,37 @@ func InitRedis() { log.Fatal("No redis host provided.") } - r = redis.NewClient(&redis.Options{ + redisOpts := &redis.Options{ Addr: config.RedisHost.GetString(), Password: config.RedisPassword.GetString(), DB: config.RedisDB.GetInt(), - }) + } + + if config.RedisTLS.GetBool() { + tlsConfig := &tls.Config{} + if config.RedisTLSClientCert.GetString() != "" && config.RedisTLSClientKey.GetString() != "" { + cert, err := tls.LoadX509KeyPair(config.RedisTLSClientCert.GetString(), config.RedisTLSClientKey.GetString()) + if err != nil { + log.Fatal("Error loading client certificate and/or key.") + } + tlsConfig.Certificates = []tls.Certificate{cert} + } + if config.RedisTLSClientCACert.GetString() != "" { + caCert, err := os.ReadFile(config.RedisTLSClientCACert.GetString()) + if err != nil { + log.Fatal("Error loading CA certificate.") + } + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + tlsConfig.RootCAs = caCertPool + } + if config.RedisTLSSkipVerify.GetBool() { + tlsConfig.InsecureSkipVerify = config.RedisTLSSkipVerify.GetBool() + } + redisOpts.TLSConfig = tlsConfig + } + + r = redis.NewClient(redisOpts) err := r.Ping(context.Background()).Err() if err != nil { From 715bfaf21bba3385e6c1dc4c54a5f4a6501e3fb1 Mon Sep 17 00:00:00 2001 From: h Date: Sat, 28 Feb 2026 04:19:17 -0700 Subject: [PATCH 2/4] Adding TLS MinVersion of TLS1.2 --- pkg/red/redis.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/red/redis.go b/pkg/red/redis.go index 571bb1077..8439931a0 100644 --- a/pkg/red/redis.go +++ b/pkg/red/redis.go @@ -50,7 +50,9 @@ func InitRedis() { } if config.RedisTLS.GetBool() { - tlsConfig := &tls.Config{} + tlsConfig := &tls.Config{ + MinVersion: tls.VersionTLS12, + } if config.RedisTLSClientCert.GetString() != "" && config.RedisTLSClientKey.GetString() != "" { cert, err := tls.LoadX509KeyPair(config.RedisTLSClientCert.GetString(), config.RedisTLSClientKey.GetString()) if err != nil { From 8a6acdd2ada5d2dd3dd53595d2f2b383c191b792 Mon Sep 17 00:00:00 2001 From: h Date: Sat, 28 Feb 2026 05:26:04 -0700 Subject: [PATCH 3/4] Add TLS client cert options to mailer --- config-raw.json | 15 +++++++++++++++ pkg/config/config.go | 28 +++++++++++++++++----------- pkg/mail/mail.go | 32 +++++++++++++++++++++++++++----- 3 files changed, 59 insertions(+), 16 deletions(-) diff --git a/config-raw.json b/config-raw.json index bf179861d..6f50fa813 100644 --- a/config-raw.json +++ b/config-raw.json @@ -384,6 +384,21 @@ "key": "forcessl", "default_value": "false", "comment": "By default, Vikunja will try to connect with starttls, use this option to force it to use ssl." + }, + { + "key": "tlsclientcert", + "default_value": "", + "comment": "The path to a client certificate, if you choose to use one." + }, + { + "key": "tlsclientkey", + "default_value": "", + "comment": "The path to the client certificate's private key." + }, + { + "key": "tlscacert", + "default_value": "", + "comment": "The path to a certificate authority certificate, for verifying the server's certificate." } ] }, diff --git a/pkg/config/config.go b/pkg/config/config.go index c9c5a4a16..d7d8d9acd 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -117,17 +117,20 @@ const ( DatabaseTLS Key = `database.tls` DatabaseSchema Key = `database.schema` - MailerEnabled Key = `mailer.enabled` - MailerHost Key = `mailer.host` - MailerPort Key = `mailer.port` - MailerUsername Key = `mailer.username` - MailerPassword Key = `mailer.password` - MailerAuthType Key = `mailer.authtype` - MailerSkipTLSVerify Key = `mailer.skiptlsverify` - MailerFromEmail Key = `mailer.fromemail` - MailerQueuelength Key = `mailer.queuelength` - MailerQueueTimeout Key = `mailer.queuetimeout` - MailerForceSSL Key = `mailer.forcessl` + MailerEnabled Key = `mailer.enabled` + MailerHost Key = `mailer.host` + MailerPort Key = `mailer.port` + MailerUsername Key = `mailer.username` + MailerPassword Key = `mailer.password` + MailerAuthType Key = `mailer.authtype` + MailerSkipTLSVerify Key = `mailer.skiptlsverify` + MailerFromEmail Key = `mailer.fromemail` + MailerQueuelength Key = `mailer.queuelength` + MailerQueueTimeout Key = `mailer.queuetimeout` + MailerForceSSL Key = `mailer.forcessl` + MailerTLSClientCert Key = `mailer.tlsclientcert` + MailerTLSClientKey Key = `mailer.tlsclientkey` + MailerTLSClientCACert Key = `mailer.tlsclientcacert` RedisEnabled Key = `redis.enabled` RedisHost Key = `redis.host` @@ -411,6 +414,9 @@ func InitDefaultConfig() { MailerQueueTimeout.setDefault(30) MailerForceSSL.setDefault(false) MailerAuthType.setDefault("plain") + MailerTLSClientCert.setDefault("") + MailerTLSClientKey.setDefault("") + MailerTLSClientCACert.setDefault("") // Redis RedisEnabled.setDefault(false) RedisHost.setDefault("localhost:6379") diff --git a/pkg/mail/mail.go b/pkg/mail/mail.go index 2cc9e50f5..f490b4916 100644 --- a/pkg/mail/mail.go +++ b/pkg/mail/mail.go @@ -19,6 +19,8 @@ package mail import ( "context" "crypto/tls" + "crypto/x509" + "os" "time" "code.vikunja.io/api/pkg/config" @@ -47,13 +49,33 @@ func getClient() (*mail.Client, error) { tlsPolicy = mail.TLSMandatory } + tlsConfig := &tls.Config{ + //#nosec G402 + InsecureSkipVerify: config.MailerSkipTLSVerify.GetBool(), + ServerName: config.MailerHost.GetString(), + MinVersion: tls.VersionTLS12, + } + + if config.MailerTLSClientCert.GetString() != "" && config.MailerTLSClientKey.GetString() != "" { + cert, err := tls.LoadX509KeyPair(config.MailerTLSClientCert.GetString(), config.MailerTLSClientKey.GetString()) + if err != nil { + log.Fatal("Error loading client certificate and/or key.") + } + tlsConfig.Certificates = []tls.Certificate{cert} + } + if config.MailerTLSClientCACert.GetString() != "" { + caCert, err := os.ReadFile(config.MailerTLSClientCACert.GetString()) + if err != nil { + log.Fatal("Error loading CA certificate.") + } + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + tlsConfig.RootCAs = caCertPool + } + opts := []mail.Option{ mail.WithTLSPortPolicy(tlsPolicy), - mail.WithTLSConfig(&tls.Config{ - //#nosec G402 - InsecureSkipVerify: config.MailerSkipTLSVerify.GetBool(), - ServerName: config.MailerHost.GetString(), - }), + mail.WithTLSConfig(tlsConfig), mail.WithPort(config.MailerPort.GetInt()), mail.WithTimeout((config.MailerQueueTimeout.GetDuration() + 3) * time.Second), // 3s more for us to close before mail server timeout mail.WithLogger(log.NewMailLogger(config.LogEnabled.GetBool(), config.LogMail.GetString(), config.LogMailLevel.GetString(), config.LogFormat.GetString())), From 5f75ea633c63075356af9194414ddffacf422057 Mon Sep 17 00:00:00 2001 From: h Date: Thu, 5 Mar 2026 09:20:51 -0700 Subject: [PATCH 4/4] Changing new variables to end with 'path' --- config-raw.json | 12 ++++----- pkg/config/config.go | 58 ++++++++++++++++++++++---------------------- pkg/mail/mail.go | 8 +++--- pkg/red/redis.go | 8 +++--- 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/config-raw.json b/config-raw.json index 6f50fa813..d22df2c61 100644 --- a/config-raw.json +++ b/config-raw.json @@ -279,17 +279,17 @@ "comment": "Whether to enable TLS or not." }, { - "key": "tlsclientcert", + "key": "tlsclientcertpath", "default_value": "", "comment": "The path to a client certificate, if you choose to use one." }, { - "key": "tlsclientkey", + "key": "tlsclientkeypath", "default_value": "", "comment": "The path to the client certificate's private key." }, { - "key": "tlscacert", + "key": "tlscacertpath", "default_value": "", "comment": "The path to a certificate authority certificate, for verifying the server's certificate." }, @@ -386,17 +386,17 @@ "comment": "By default, Vikunja will try to connect with starttls, use this option to force it to use ssl." }, { - "key": "tlsclientcert", + "key": "tlsclientcertpath", "default_value": "", "comment": "The path to a client certificate, if you choose to use one." }, { - "key": "tlsclientkey", + "key": "tlsclientkeypath", "default_value": "", "comment": "The path to the client certificate's private key." }, { - "key": "tlscacert", + "key": "tlscacertpath", "default_value": "", "comment": "The path to a certificate authority certificate, for verifying the server's certificate." } diff --git a/pkg/config/config.go b/pkg/config/config.go index d7d8d9acd..6869a8393 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -117,30 +117,30 @@ const ( DatabaseTLS Key = `database.tls` DatabaseSchema Key = `database.schema` - MailerEnabled Key = `mailer.enabled` - MailerHost Key = `mailer.host` - MailerPort Key = `mailer.port` - MailerUsername Key = `mailer.username` - MailerPassword Key = `mailer.password` - MailerAuthType Key = `mailer.authtype` - MailerSkipTLSVerify Key = `mailer.skiptlsverify` - MailerFromEmail Key = `mailer.fromemail` - MailerQueuelength Key = `mailer.queuelength` - MailerQueueTimeout Key = `mailer.queuetimeout` - MailerForceSSL Key = `mailer.forcessl` - MailerTLSClientCert Key = `mailer.tlsclientcert` - MailerTLSClientKey Key = `mailer.tlsclientkey` - MailerTLSClientCACert Key = `mailer.tlsclientcacert` + MailerEnabled Key = `mailer.enabled` + MailerHost Key = `mailer.host` + MailerPort Key = `mailer.port` + MailerUsername Key = `mailer.username` + MailerPassword Key = `mailer.password` + MailerAuthType Key = `mailer.authtype` + MailerSkipTLSVerify Key = `mailer.skiptlsverify` + MailerFromEmail Key = `mailer.fromemail` + MailerQueuelength Key = `mailer.queuelength` + MailerQueueTimeout Key = `mailer.queuetimeout` + MailerForceSSL Key = `mailer.forcessl` + MailerTLSClientCertPath Key = `mailer.tlsclientcertpath` + MailerTLSClientKeyPath Key = `mailer.tlsclientkeypath` + MailerTLSClientCACertPath Key = `mailer.tlsclientcacertpath` - RedisEnabled Key = `redis.enabled` - RedisHost Key = `redis.host` - RedisPassword Key = `redis.password` - RedisDB Key = `redis.db` - RedisTLS Key = `redis.tls` - RedisTLSClientCert Key = `redis.tlsclientcert` - RedisTLSClientKey Key = `redis.tlsclientkey` - RedisTLSClientCACert Key = `redis.tlsclientcacert` - RedisTLSSkipVerify Key = `redis.tlsskipverify` + RedisEnabled Key = `redis.enabled` + RedisHost Key = `redis.host` + RedisPassword Key = `redis.password` + RedisDB Key = `redis.db` + RedisTLS Key = `redis.tls` + RedisTLSClientCertPath Key = `redis.tlsclientcertpath` + RedisTLSClientKeyPath Key = `redis.tlsclientkeypath` + RedisTLSClientCACertPath Key = `redis.tlsclientcacertpath` + RedisTLSSkipVerify Key = `redis.tlsskipverify` LogEnabled Key = `log.enabled` LogStandard Key = `log.standard` @@ -414,18 +414,18 @@ func InitDefaultConfig() { MailerQueueTimeout.setDefault(30) MailerForceSSL.setDefault(false) MailerAuthType.setDefault("plain") - MailerTLSClientCert.setDefault("") - MailerTLSClientKey.setDefault("") - MailerTLSClientCACert.setDefault("") + MailerTLSClientCertPath.setDefault("") + MailerTLSClientKeyPath.setDefault("") + MailerTLSClientCACertPath.setDefault("") // Redis RedisEnabled.setDefault(false) RedisHost.setDefault("localhost:6379") RedisPassword.setDefault("") RedisDB.setDefault(0) RedisTLS.setDefault(false) - RedisTLSClientCert.setDefault("") - RedisTLSClientKey.setDefault("") - RedisTLSClientCACert.setDefault("") + RedisTLSClientCertPath.setDefault("") + RedisTLSClientKeyPath.setDefault("") + RedisTLSClientCACertPath.setDefault("") RedisTLSSkipVerify.setDefault(false) // Logger LogEnabled.setDefault(true) diff --git a/pkg/mail/mail.go b/pkg/mail/mail.go index f490b4916..dc31fa8d1 100644 --- a/pkg/mail/mail.go +++ b/pkg/mail/mail.go @@ -56,15 +56,15 @@ func getClient() (*mail.Client, error) { MinVersion: tls.VersionTLS12, } - if config.MailerTLSClientCert.GetString() != "" && config.MailerTLSClientKey.GetString() != "" { - cert, err := tls.LoadX509KeyPair(config.MailerTLSClientCert.GetString(), config.MailerTLSClientKey.GetString()) + if config.MailerTLSClientCertPath.GetString() != "" && config.MailerTLSClientKeyPath.GetString() != "" { + cert, err := tls.LoadX509KeyPair(config.MailerTLSClientCertPath.GetString(), config.MailerTLSClientKeyPath.GetString()) if err != nil { log.Fatal("Error loading client certificate and/or key.") } tlsConfig.Certificates = []tls.Certificate{cert} } - if config.MailerTLSClientCACert.GetString() != "" { - caCert, err := os.ReadFile(config.MailerTLSClientCACert.GetString()) + if config.MailerTLSClientCACertPath.GetString() != "" { + caCert, err := os.ReadFile(config.MailerTLSClientCACertPath.GetString()) if err != nil { log.Fatal("Error loading CA certificate.") } diff --git a/pkg/red/redis.go b/pkg/red/redis.go index 8439931a0..535ccf2f5 100644 --- a/pkg/red/redis.go +++ b/pkg/red/redis.go @@ -53,15 +53,15 @@ func InitRedis() { tlsConfig := &tls.Config{ MinVersion: tls.VersionTLS12, } - if config.RedisTLSClientCert.GetString() != "" && config.RedisTLSClientKey.GetString() != "" { - cert, err := tls.LoadX509KeyPair(config.RedisTLSClientCert.GetString(), config.RedisTLSClientKey.GetString()) + if config.RedisTLSClientCertPath.GetString() != "" && config.RedisTLSClientKeyPath.GetString() != "" { + cert, err := tls.LoadX509KeyPair(config.RedisTLSClientCertPath.GetString(), config.RedisTLSClientKeyPath.GetString()) if err != nil { log.Fatal("Error loading client certificate and/or key.") } tlsConfig.Certificates = []tls.Certificate{cert} } - if config.RedisTLSClientCACert.GetString() != "" { - caCert, err := os.ReadFile(config.RedisTLSClientCACert.GetString()) + if config.RedisTLSClientCACertPath.GetString() != "" { + caCert, err := os.ReadFile(config.RedisTLSClientCACertPath.GetString()) if err != nil { log.Fatal("Error loading CA certificate.") }