2020-02-07 17:27:45 +01:00
|
|
|
// Vikunja is a to-do list application to facilitate your life.
|
2020-01-09 18:33:22 +01:00
|
|
|
// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
|
2018-11-26 21:17:33 +01:00
|
|
|
//
|
2019-12-04 20:39:56 +01:00
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
2018-11-26 21:17:33 +01:00
|
|
|
//
|
2019-12-04 20:39:56 +01:00
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
2018-11-26 21:17:33 +01:00
|
|
|
//
|
2019-12-04 20:39:56 +01:00
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2018-11-26 21:17:33 +01:00
|
|
|
|
2018-10-31 13:42:38 +01:00
|
|
|
package config
|
2018-06-10 11:11:41 +02:00
|
|
|
|
|
|
|
import (
|
2018-09-08 13:29:35 +02:00
|
|
|
"crypto/rand"
|
|
|
|
"fmt"
|
2019-07-06 22:12:26 +02:00
|
|
|
"log"
|
2018-11-02 11:01:28 +01:00
|
|
|
"os"
|
2020-03-20 22:21:44 +01:00
|
|
|
"path"
|
2018-11-02 11:01:28 +01:00
|
|
|
"path/filepath"
|
2018-09-08 13:29:35 +02:00
|
|
|
"strings"
|
2019-07-06 22:12:26 +02:00
|
|
|
"time"
|
|
|
|
|
2020-06-30 09:55:46 +02:00
|
|
|
"4d63.com/tz"
|
2019-07-06 22:12:26 +02:00
|
|
|
"github.com/spf13/viper"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Key is used as a config key
|
|
|
|
type Key string
|
|
|
|
|
|
|
|
// These constants hold all config value keys
|
|
|
|
const (
|
2020-04-13 22:30:09 +02:00
|
|
|
// #nosec
|
2020-01-26 20:10:31 +01:00
|
|
|
ServiceJWTSecret Key = `service.JWTSecret`
|
|
|
|
ServiceInterface Key = `service.interface`
|
|
|
|
ServiceFrontendurl Key = `service.frontendurl`
|
|
|
|
ServiceEnableCaldav Key = `service.enablecaldav`
|
|
|
|
ServiceRootpath Key = `service.rootpath`
|
|
|
|
ServiceMaxItemsPerPage Key = `service.maxitemsperpage`
|
|
|
|
ServiceEnableMetrics Key = `service.enablemetrics`
|
|
|
|
ServiceMotd Key = `service.motd`
|
|
|
|
ServiceEnableLinkSharing Key = `service.enablelinksharing`
|
|
|
|
ServiceEnableRegistration Key = `service.enableregistration`
|
|
|
|
ServiceEnableTaskAttachments Key = `service.enabletaskattachments`
|
2020-02-08 13:48:49 +01:00
|
|
|
ServiceTimeZone Key = `service.timezone`
|
2020-02-19 22:57:56 +01:00
|
|
|
ServiceEnableTaskComments Key = `service.enabletaskcomments`
|
2020-05-29 17:15:59 +02:00
|
|
|
ServiceEnableTotp Key = `service.enabletotp`
|
2020-06-19 20:47:15 +02:00
|
|
|
ServiceSentryDsn Key = `service.sentrydsn`
|
2019-07-06 22:12:26 +02:00
|
|
|
|
2020-07-18 18:53:56 +02:00
|
|
|
LegalImprintURL Key = `legal.imprinturl`
|
|
|
|
LegalPrivacyURL Key = `legal.privacyurl`
|
|
|
|
|
2019-07-06 22:12:26 +02:00
|
|
|
DatabaseType Key = `database.type`
|
|
|
|
DatabaseHost Key = `database.host`
|
|
|
|
DatabaseUser Key = `database.user`
|
|
|
|
DatabasePassword Key = `database.password`
|
|
|
|
DatabaseDatabase Key = `database.database`
|
|
|
|
DatabasePath Key = `database.path`
|
|
|
|
DatabaseMaxOpenConnections Key = `database.maxopenconnections`
|
|
|
|
DatabaseMaxIdleConnections Key = `database.maxidleconnections`
|
|
|
|
DatabaseMaxConnectionLifetime Key = `database.maxconnectionlifetime`
|
2020-02-16 22:42:04 +01:00
|
|
|
DatabaseSslMode Key = `database.sslmode`
|
2019-07-06 22:12:26 +02:00
|
|
|
|
|
|
|
CacheEnabled Key = `cache.enabled`
|
|
|
|
CacheType Key = `cache.type`
|
|
|
|
CacheMaxElementSize Key = `cache.maxelementsize`
|
|
|
|
|
|
|
|
MailerEnabled Key = `mailer.enabled`
|
|
|
|
MailerHost Key = `mailer.host`
|
|
|
|
MailerPort Key = `mailer.port`
|
|
|
|
MailerUsername Key = `mailer.username`
|
|
|
|
MailerPassword Key = `mailer.password`
|
|
|
|
MailerSkipTLSVerify Key = `mailer.skiptlsverify`
|
|
|
|
MailerFromEmail Key = `mailer.fromemail`
|
|
|
|
MailerQueuelength Key = `mailer.queuelength`
|
|
|
|
MailerQueueTimeout Key = `mailer.queuetimeout`
|
2020-07-14 17:30:39 +02:00
|
|
|
MailerForceSSL Key = `mailer.forcessl`
|
2019-07-06 22:12:26 +02:00
|
|
|
|
|
|
|
RedisEnabled Key = `redis.enabled`
|
|
|
|
RedisHost Key = `redis.host`
|
|
|
|
RedisPassword Key = `redis.password`
|
|
|
|
RedisDB Key = `redis.db`
|
|
|
|
|
2020-04-12 19:29:24 +02:00
|
|
|
LogEnabled Key = `log.enabled`
|
|
|
|
LogStandard Key = `log.standard`
|
2020-04-12 22:32:21 +02:00
|
|
|
LogLevel Key = `log.level`
|
2020-04-12 19:29:24 +02:00
|
|
|
LogDatabase Key = `log.database`
|
|
|
|
LogDatabaseLevel Key = `log.databaselevel`
|
|
|
|
LogHTTP Key = `log.http`
|
|
|
|
LogEcho Key = `log.echo`
|
|
|
|
LogPath Key = `log.path`
|
2019-07-21 23:27:30 +02:00
|
|
|
|
|
|
|
RateLimitEnabled Key = `ratelimit.enabled`
|
|
|
|
RateLimitKind Key = `ratelimit.kind`
|
|
|
|
RateLimitPeriod Key = `ratelimit.period`
|
|
|
|
RateLimitLimit Key = `ratelimit.limit`
|
|
|
|
RateLimitStore Key = `ratelimit.store`
|
2019-10-16 22:52:29 +02:00
|
|
|
|
|
|
|
FilesBasePath Key = `files.basepath`
|
|
|
|
FilesMaxSize Key = `files.maxsize`
|
2020-01-19 17:52:16 +01:00
|
|
|
|
|
|
|
MigrationWunderlistEnable Key = `migration.wunderlist.enable`
|
|
|
|
MigrationWunderlistClientID Key = `migration.wunderlist.clientid`
|
|
|
|
MigrationWunderlistClientSecret Key = `migration.wunderlist.clientsecret`
|
|
|
|
MigrationWunderlistRedirectURL Key = `migration.wunderlist.redirecturl`
|
2020-05-23 22:50:54 +02:00
|
|
|
MigrationTodoistEnable Key = `migration.todoist.enable`
|
|
|
|
MigrationTodoistClientID Key = `migration.todoist.clientid`
|
|
|
|
MigrationTodoistClientSecret Key = `migration.todoist.clientsecret`
|
|
|
|
MigrationTodoistRedirectURL Key = `migration.todoist.redirecturl`
|
2020-01-26 20:09:54 +01:00
|
|
|
|
|
|
|
CorsEnable Key = `cors.enable`
|
|
|
|
CorsOrigins Key = `cors.origins`
|
|
|
|
CorsMaxAge Key = `cors.maxage`
|
2020-03-01 22:10:25 +01:00
|
|
|
|
|
|
|
AvatarGravaterExpiration Key = `avatar.gravatarexpiration`
|
2020-05-26 22:07:55 +02:00
|
|
|
|
|
|
|
BackgroundsEnabled Key = `backgrounds.enabled`
|
2020-06-11 19:31:37 +02:00
|
|
|
BackgroundsUploadEnabled Key = `backgrounds.providers.upload.enabled`
|
2020-05-26 22:07:55 +02:00
|
|
|
BackgroundsUnsplashEnabled Key = `backgrounds.providers.unsplash.enabled`
|
|
|
|
BackgroundsUnsplashAccessToken Key = `backgrounds.providers.unsplash.accesstoken`
|
|
|
|
BackgroundsUnsplashApplicationID Key = `backgrounds.providers.unsplash.applicationid`
|
2020-10-10 18:53:59 +02:00
|
|
|
|
|
|
|
KeyvalueType Key = `keyvalue.type`
|
2018-06-10 11:11:41 +02:00
|
|
|
)
|
|
|
|
|
2019-07-06 22:12:26 +02:00
|
|
|
// GetString returns a string config value
|
|
|
|
func (k Key) GetString() string {
|
|
|
|
return viper.GetString(string(k))
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetBool returns a bool config value
|
|
|
|
func (k Key) GetBool() bool {
|
|
|
|
return viper.GetBool(string(k))
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetInt returns an int config value
|
|
|
|
func (k Key) GetInt() int {
|
|
|
|
return viper.GetInt(string(k))
|
|
|
|
}
|
|
|
|
|
2019-07-21 23:27:30 +02:00
|
|
|
// GetInt64 returns an int64 config value
|
|
|
|
func (k Key) GetInt64() int64 {
|
|
|
|
return viper.GetInt64(string(k))
|
|
|
|
}
|
|
|
|
|
2019-07-06 22:12:26 +02:00
|
|
|
// GetDuration returns a duration config value
|
|
|
|
func (k Key) GetDuration() time.Duration {
|
|
|
|
return viper.GetDuration(string(k))
|
|
|
|
}
|
|
|
|
|
2020-01-26 20:09:54 +01:00
|
|
|
// GetStringSlice returns a string slice from a config option
|
|
|
|
func (k Key) GetStringSlice() []string {
|
|
|
|
return viper.GetStringSlice(string(k))
|
|
|
|
}
|
|
|
|
|
2020-06-27 19:04:01 +02:00
|
|
|
var timezone *time.Location
|
|
|
|
|
|
|
|
// GetTimeZone returns the time zone configured for vikunja
|
|
|
|
// It is a separate function and not done through viper because that makes handling
|
|
|
|
// it way easier, especially when testing.
|
|
|
|
func GetTimeZone() *time.Location {
|
|
|
|
if timezone == nil {
|
2020-06-30 09:55:46 +02:00
|
|
|
loc, err := tz.LoadLocation(ServiceTimeZone.GetString())
|
2020-06-27 19:04:01 +02:00
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("Error parsing time zone: %s", err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
timezone = loc
|
|
|
|
}
|
|
|
|
return timezone
|
|
|
|
}
|
|
|
|
|
2019-07-06 22:12:26 +02:00
|
|
|
// Set sets a value
|
|
|
|
func (k Key) Set(i interface{}) {
|
|
|
|
viper.Set(string(k), i)
|
|
|
|
}
|
|
|
|
|
|
|
|
// sets the default config value
|
|
|
|
func (k Key) setDefault(i interface{}) {
|
|
|
|
viper.SetDefault(string(k), i)
|
|
|
|
}
|
|
|
|
|
2019-10-16 22:52:29 +02:00
|
|
|
// InitDefaultConfig sets default config values
|
|
|
|
// This is an extra function so we can call it when initializing tests without initializing the full config
|
|
|
|
func InitDefaultConfig() {
|
2018-09-08 13:29:35 +02:00
|
|
|
// Service config
|
|
|
|
random, err := random(32)
|
|
|
|
if err != nil {
|
2019-07-06 22:12:26 +02:00
|
|
|
log.Fatal(err.Error())
|
2018-06-10 11:11:41 +02:00
|
|
|
}
|
|
|
|
|
2018-10-27 11:33:28 +02:00
|
|
|
// Service
|
2019-07-06 22:12:26 +02:00
|
|
|
ServiceJWTSecret.setDefault(random)
|
|
|
|
ServiceInterface.setDefault(":3456")
|
|
|
|
ServiceFrontendurl.setDefault("")
|
|
|
|
ServiceEnableCaldav.setDefault(true)
|
2018-12-18 17:01:46 +01:00
|
|
|
|
2018-11-02 11:01:28 +01:00
|
|
|
ex, err := os.Executable()
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
exPath := filepath.Dir(ex)
|
2019-07-06 22:12:26 +02:00
|
|
|
ServiceRootpath.setDefault(exPath)
|
2019-10-23 23:11:40 +02:00
|
|
|
ServiceMaxItemsPerPage.setDefault(50)
|
2019-07-06 22:12:26 +02:00
|
|
|
ServiceEnableMetrics.setDefault(false)
|
2019-07-16 00:54:38 +02:00
|
|
|
ServiceMotd.setDefault("")
|
2019-08-31 22:56:41 +02:00
|
|
|
ServiceEnableLinkSharing.setDefault(true)
|
2019-12-31 00:27:02 +01:00
|
|
|
ServiceEnableRegistration.setDefault(true)
|
2020-01-26 20:10:31 +01:00
|
|
|
ServiceEnableTaskAttachments.setDefault(true)
|
2020-02-08 13:48:49 +01:00
|
|
|
ServiceTimeZone.setDefault("GMT")
|
2020-02-19 22:57:56 +01:00
|
|
|
ServiceEnableTaskComments.setDefault(true)
|
2020-05-29 17:15:59 +02:00
|
|
|
ServiceEnableTotp.setDefault(true)
|
2019-07-16 00:54:38 +02:00
|
|
|
|
2018-09-08 13:29:35 +02:00
|
|
|
// Database
|
2019-07-06 22:12:26 +02:00
|
|
|
DatabaseType.setDefault("sqlite")
|
|
|
|
DatabaseHost.setDefault("localhost")
|
|
|
|
DatabaseUser.setDefault("vikunja")
|
|
|
|
DatabasePassword.setDefault("")
|
|
|
|
DatabaseDatabase.setDefault("vikunja")
|
|
|
|
DatabasePath.setDefault("./vikunja.db")
|
|
|
|
DatabaseMaxOpenConnections.setDefault(100)
|
|
|
|
DatabaseMaxIdleConnections.setDefault(50)
|
|
|
|
DatabaseMaxConnectionLifetime.setDefault(10000)
|
2020-02-16 22:42:04 +01:00
|
|
|
DatabaseSslMode.setDefault("disable")
|
2019-05-25 07:49:52 +02:00
|
|
|
|
2018-09-13 19:53:03 +02:00
|
|
|
// Cacher
|
2019-07-06 22:12:26 +02:00
|
|
|
CacheEnabled.setDefault(false)
|
|
|
|
CacheType.setDefault("memory")
|
|
|
|
CacheMaxElementSize.setDefault(1000)
|
2018-10-27 11:33:28 +02:00
|
|
|
// Mailer
|
2019-07-06 22:12:26 +02:00
|
|
|
MailerEnabled.setDefault(false)
|
|
|
|
MailerHost.setDefault("")
|
|
|
|
MailerPort.setDefault("587")
|
|
|
|
MailerUsername.setDefault("user")
|
|
|
|
MailerPassword.setDefault("")
|
|
|
|
MailerSkipTLSVerify.setDefault(false)
|
|
|
|
MailerFromEmail.setDefault("mail@vikunja")
|
|
|
|
MailerQueuelength.setDefault(100)
|
|
|
|
MailerQueueTimeout.setDefault(30)
|
2020-07-14 17:30:39 +02:00
|
|
|
MailerForceSSL.setDefault(false)
|
2018-12-12 23:50:35 +01:00
|
|
|
// Redis
|
2019-07-06 22:12:26 +02:00
|
|
|
RedisEnabled.setDefault(false)
|
|
|
|
RedisHost.setDefault("localhost:6379")
|
|
|
|
RedisPassword.setDefault("")
|
|
|
|
RedisDB.setDefault(0)
|
2019-01-25 12:40:54 +01:00
|
|
|
// Logger
|
2019-07-06 22:12:26 +02:00
|
|
|
LogEnabled.setDefault(true)
|
|
|
|
LogStandard.setDefault("stdout")
|
2020-04-12 22:32:21 +02:00
|
|
|
LogLevel.setDefault("INFO")
|
2019-11-24 19:17:59 +01:00
|
|
|
LogDatabase.setDefault("off")
|
2020-04-12 22:32:21 +02:00
|
|
|
LogDatabaseLevel.setDefault("WARNING")
|
2019-07-06 22:12:26 +02:00
|
|
|
LogHTTP.setDefault("stdout")
|
|
|
|
LogEcho.setDefault("off")
|
|
|
|
LogPath.setDefault(ServiceRootpath.GetString() + "/logs")
|
2019-07-21 23:27:30 +02:00
|
|
|
// Rate Limit
|
|
|
|
RateLimitEnabled.setDefault(false)
|
|
|
|
RateLimitKind.setDefault("user")
|
|
|
|
RateLimitLimit.setDefault(100)
|
|
|
|
RateLimitPeriod.setDefault(60)
|
|
|
|
RateLimitStore.setDefault("memory")
|
2019-10-16 22:52:29 +02:00
|
|
|
// Files
|
|
|
|
FilesBasePath.setDefault("files")
|
2019-10-18 17:30:25 +02:00
|
|
|
FilesMaxSize.setDefault("20MB")
|
2020-01-26 20:09:54 +01:00
|
|
|
// Cors
|
|
|
|
CorsEnable.setDefault(true)
|
|
|
|
CorsOrigins.setDefault([]string{"*"})
|
|
|
|
CorsMaxAge.setDefault(0)
|
2020-02-17 18:29:17 +01:00
|
|
|
// Migration
|
|
|
|
MigrationWunderlistEnable.setDefault(false)
|
2020-05-23 22:50:54 +02:00
|
|
|
MigrationTodoistEnable.setDefault(false)
|
2020-03-01 22:10:25 +01:00
|
|
|
// Avatar
|
|
|
|
AvatarGravaterExpiration.setDefault(3600)
|
2020-05-26 22:07:55 +02:00
|
|
|
// List Backgrounds
|
2020-06-23 22:53:23 +02:00
|
|
|
BackgroundsEnabled.setDefault(true)
|
|
|
|
BackgroundsUploadEnabled.setDefault(true)
|
2020-05-26 22:07:55 +02:00
|
|
|
BackgroundsUnsplashEnabled.setDefault(false)
|
2020-10-10 18:53:59 +02:00
|
|
|
// Key Value
|
|
|
|
KeyvalueType.setDefault("memory")
|
2019-10-16 22:52:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// InitConfig initializes the config, sets defaults etc.
|
|
|
|
func InitConfig() {
|
|
|
|
|
|
|
|
// Set defaults
|
|
|
|
InitDefaultConfig()
|
2018-09-08 13:29:35 +02:00
|
|
|
|
|
|
|
// Init checking for environment variables
|
|
|
|
viper.SetEnvPrefix("vikunja")
|
|
|
|
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
|
|
|
viper.AutomaticEnv()
|
|
|
|
|
|
|
|
// Load the config file
|
2019-07-06 22:12:26 +02:00
|
|
|
viper.AddConfigPath(ServiceRootpath.GetString())
|
2019-01-20 18:13:21 +01:00
|
|
|
viper.AddConfigPath("/etc/vikunja/")
|
2020-03-20 22:21:44 +01:00
|
|
|
|
|
|
|
homeDir, err := os.UserHomeDir()
|
|
|
|
if err != nil {
|
2020-04-02 21:38:16 +02:00
|
|
|
log.Printf("No home directory found, not using config from ~/.config/vikunja/. Error was: %s\n", err.Error())
|
2020-04-02 21:13:42 +02:00
|
|
|
} else {
|
|
|
|
viper.AddConfigPath(path.Join(homeDir, ".config", "vikunja"))
|
2020-03-20 22:21:44 +01:00
|
|
|
}
|
|
|
|
|
2018-09-08 13:29:35 +02:00
|
|
|
viper.AddConfigPath(".")
|
|
|
|
viper.SetConfigName("config")
|
2020-03-20 22:21:44 +01:00
|
|
|
err = viper.ReadInConfig()
|
2018-09-08 13:29:35 +02:00
|
|
|
if err != nil {
|
2019-07-06 22:12:26 +02:00
|
|
|
log.Println(err.Error())
|
2020-04-02 21:38:16 +02:00
|
|
|
log.Println("Using default config.")
|
2020-03-20 22:21:44 +01:00
|
|
|
return
|
2018-09-08 13:29:35 +02:00
|
|
|
}
|
2020-03-20 22:21:44 +01:00
|
|
|
|
2020-10-10 18:53:59 +02:00
|
|
|
if CacheType.GetString() == "keyvalue" {
|
|
|
|
CacheType.Set(KeyvalueType.GetString())
|
|
|
|
}
|
|
|
|
|
|
|
|
if RateLimitStore.GetString() == "keyvalue" {
|
|
|
|
RateLimitStore.Set(KeyvalueType.GetString())
|
|
|
|
}
|
|
|
|
|
2020-04-02 21:38:16 +02:00
|
|
|
log.Printf("Using config file: %s", viper.ConfigFileUsed())
|
2018-06-10 11:11:41 +02:00
|
|
|
}
|
|
|
|
|
2018-09-08 13:29:35 +02:00
|
|
|
func random(length int) (string, error) {
|
|
|
|
b := make([]byte, length)
|
|
|
|
if _, err := rand.Read(b); err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Sprintf("%X", b), nil
|
|
|
|
}
|