From 427f752990a9763b48c8aede483321968da4facc Mon Sep 17 00:00:00 2001 From: konrad Date: Sat, 8 Sep 2018 13:29:35 +0200 Subject: [PATCH] Vikunja now uses viper to handle config --- .gitignore | 3 +- Gopkg.lock | 170 ++++++++++++++++++++++++++++++++++++++++- Gopkg.toml | 4 + config.ini.sample | 14 ---- config.yml.sample | 14 ++++ main.go | 5 +- models/config.go | 67 +++++++++++----- models/config_test.go | 61 --------------- models/models.go | 15 ++-- models/models_test.go | 3 +- models/unit_tests.go | 3 + routes/api/v1/login.go | 3 +- routes/routes.go | 3 +- 13 files changed, 256 insertions(+), 109 deletions(-) delete mode 100644 config.ini.sample create mode 100644 config.yml.sample delete mode 100644 models/config_test.go diff --git a/.gitignore b/.gitignore index a4194b8175d..f2a7b12afa1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .idea/ .idea/*/* -config.ini +config.yml +config.yaml *.db Run vikunja diff --git a/Gopkg.lock b/Gopkg.lock index 58edda2f2ac..e50e4032a69 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -2,132 +2,294 @@ [[projects]] + digest = "1:a2c1d0e43bd3baaa071d1b9ed72c27d78169b2b269f71c105ac4ba34b1be4a39" name = "github.com/davecgh/go-spew" packages = ["spew"] + pruneopts = "UT" revision = "346938d642f2ec3594ed81d874461961cd0faa76" version = "v1.1.0" [[projects]] + digest = "1:6cb5bf34f3e3bb61e76d976f5bd29d245b567f208e1fd7cb8104b736a5eb649d" name = "github.com/dgrijalva/jwt-go" packages = ["."] + pruneopts = "UT" revision = "a539ee1a749a2b895533f979515ac7e6e0f5b650" [[projects]] + digest = "1:abeb38ade3f32a92943e5be54f55ed6d6e3b6602761d74b4aab4c9dd45c18abd" + name = "github.com/fsnotify/fsnotify" + packages = ["."] + pruneopts = "UT" + revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9" + version = "v1.4.7" + +[[projects]] + digest = "1:fe8a03a8222d5b913f256972933d26d24ad7c8286692a42943bc01633cc8fce3" name = "github.com/go-ini/ini" packages = ["."] + pruneopts = "UT" revision = "358ee7663966325963d4e8b2e1fbd570c5195153" version = "v1.38.1" [[projects]] + digest = "1:d2b67246c3fa959edfa1be84b407cf0a0a4cabbace0843814b1729b5af808d9e" name = "github.com/go-sql-driver/mysql" packages = ["."] + pruneopts = "UT" revision = "ee359f95877bdef36cbb602711e49b6f0becfca9" [[projects]] + digest = "1:3f854136f2da9cde22fa0dd29e74fb7c920c5d79d060847fe9b96f2d3cfab746" name = "github.com/go-xorm/builder" packages = ["."] + pruneopts = "UT" revision = "c8871c857d2555fbfbd8524f895be5386d3d8836" [[projects]] + digest = "1:ee0b218753df985dd6633b13a894a69f0c1ea385f092f4afa093d407bb165cc5" name = "github.com/go-xorm/core" packages = ["."] + pruneopts = "UT" revision = "f43c33d9a48db006417a7ac4c16b08897e3e1458" version = "v0.5.8" [[projects]] + digest = "1:8e0764e74dd6cf539d3c035772d3fd0009b89fff9889a1131139be6d871c90dd" name = "github.com/go-xorm/xorm" packages = ["."] + pruneopts = "UT" revision = "29d4a0330a00b9be468b70e3fb0f74109348c358" [[projects]] + digest = "1:c0d19ab64b32ce9fe5cf4ddceba78d5bc9807f0016db6b1183599da3dcc24d10" + name = "github.com/hashicorp/hcl" + packages = [ + ".", + "hcl/ast", + "hcl/parser", + "hcl/printer", + "hcl/scanner", + "hcl/strconv", + "hcl/token", + "json/parser", + "json/scanner", + "json/token", + ] + pruneopts = "UT" + revision = "8cb6e5b959231cc1119e43259c4a608f9c51a241" + version = "v1.0.0" + +[[projects]] + digest = "1:82c5850e702ccef3976cdfdf737725013587c64e02e5ecae57e86431163b27aa" name = "github.com/labstack/echo" packages = [ ".", - "middleware" + "middleware", ] + pruneopts = "UT" revision = "1049c9613cd371b7ea8f219404c9a821734781ed" version = "v3.1.0" [[projects]] + digest = "1:ef6158d11f87c8036114cf3d2bf5c50edb4aa0b4aab5deef26716a8bb674a9ad" name = "github.com/labstack/gommon" packages = [ "bytes", "color", "log", - "random" + "random", ] + pruneopts = "UT" revision = "57409ada9da0f2afad6664c49502f8c50fbd8476" version = "0.2.3" [[projects]] + digest = "1:c568d7727aa262c32bdf8a3f7db83614f7af0ed661474b24588de635c20024c7" + name = "github.com/magiconair/properties" + packages = ["."] + pruneopts = "UT" + revision = "c2353362d570a7bfa228149c62842019201cfb71" + version = "v1.8.0" + +[[projects]] + digest = "1:a36a1febe1240bb79a208390ad17e1080555b0031a9ed42a41eae173cca3fd74" name = "github.com/mattn/go-colorable" packages = ["."] + pruneopts = "UT" revision = "ad5389df28cdac544c99bd7b9161a0b5b6ca9d1b" [[projects]] + digest = "1:d4d17353dbd05cb52a2a52b7fe1771883b682806f68db442b436294926bbfafb" name = "github.com/mattn/go-isatty" packages = ["."] + pruneopts = "UT" revision = "a5cdd64afdee435007ee3e9f6ed4684af949d568" [[projects]] + digest = "1:3cafc6a5a1b8269605d9df4c6956d43d8011fc57f266ca6b9d04da6c09dee548" name = "github.com/mattn/go-sqlite3" packages = ["."] + pruneopts = "UT" revision = "25ecb14adfc7543176f7d85291ec7dba82c6f7e4" version = "v1.9.0" [[projects]] + digest = "1:645110e089152bd0f4a011a2648fbb0e4df5977be73ca605781157ac297f50c4" + name = "github.com/mitchellh/mapstructure" + packages = ["."] + pruneopts = "UT" + revision = "fa473d140ef3c6adf42d6b391fe76707f1f243c8" + version = "v1.0.0" + +[[projects]] + digest = "1:95741de3af260a92cc5c7f3f3061e85273f5a81b5db20d4bd68da74bd521675e" + name = "github.com/pelletier/go-toml" + packages = ["."] + pruneopts = "UT" + revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194" + version = "v1.2.0" + +[[projects]] + digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe" name = "github.com/pmezard/go-difflib" packages = ["difflib"] + pruneopts = "UT" revision = "792786c7400a136282c1664665ae0a8db921c6c2" version = "v1.0.0" [[projects]] + digest = "1:6a4a11ba764a56d2758899ec6f3848d24698d48442ebce85ee7a3f63284526cd" + name = "github.com/spf13/afero" + packages = [ + ".", + "mem", + ] + pruneopts = "UT" + revision = "d40851caa0d747393da1ffb28f7f9d8b4eeffebd" + version = "v1.1.2" + +[[projects]] + digest = "1:516e71bed754268937f57d4ecb190e01958452336fa73dbac880894164e91c1f" + name = "github.com/spf13/cast" + packages = ["."] + pruneopts = "UT" + revision = "8965335b8c7107321228e3e3702cab9832751bac" + version = "v1.2.0" + +[[projects]] + digest = "1:68ea4e23713989dc20b1bded5d9da2c5f9be14ff9885beef481848edd18c26cb" + name = "github.com/spf13/jwalterweatherman" + packages = ["."] + pruneopts = "UT" + revision = "4a4406e478ca629068e7768fc33f3f044173c0a6" + version = "v1.0.0" + +[[projects]] + digest = "1:dab83a1bbc7ad3d7a6ba1a1cc1760f25ac38cdf7d96a5cdd55cd915a4f5ceaf9" + name = "github.com/spf13/pflag" + packages = ["."] + pruneopts = "UT" + revision = "9a97c102cda95a86cec2345a6f09f55a939babf5" + version = "v1.0.2" + +[[projects]] + digest = "1:6e30a27eac59a148b3f7a32e0ba54706b31dcde5a42f63b22cb47873b62fa343" + name = "github.com/spf13/viper" + packages = ["."] + pruneopts = "UT" + revision = "8fb642006536c8d3760c99d4fa2389f5e2205631" + version = "v1.2.0" + +[[projects]] + digest = "1:a7496c8d47f794d15a6e41f8ada426d4a41c038fac9bd75c1abc30faacf469c9" name = "github.com/stretchr/testify" packages = ["assert"] + pruneopts = "UT" revision = "87b1dfb5b2fa649f52695dd9eae19abe404a4308" [[projects]] branch = "master" + digest = "1:c468422f334a6b46a19448ad59aaffdfc0a36b08fdcc1c749a0b29b6453d7e59" name = "github.com/valyala/bytebufferpool" packages = ["."] + pruneopts = "UT" revision = "e746df99fe4a3986f4d4f79e13c1e0117ce9c2f7" [[projects]] branch = "master" + digest = "1:268b8bce0064e8c057d7b913605459f9a26dcab864c0886a56d196540fbf003f" name = "github.com/valyala/fasttemplate" packages = ["."] + pruneopts = "UT" revision = "dcecefd839c4193db0d35b88ec65b4c12d360ab0" [[projects]] + digest = "1:456c96b87c9481d98aac8ef9862053a8fc97b981d26f6cd8d63de783dd24acec" name = "golang.org/x/crypto" packages = [ "acme", "acme/autocert", "bcrypt", - "blowfish" + "blowfish", ] + pruneopts = "UT" revision = "9419663f5a44be8b34ca85f08abc5fe1be11f8a3" [[projects]] + digest = "1:f1275b0d1ed7d43eeb7a0464a148258f04e66a4783514d5c790d4e970cc7df6d" name = "golang.org/x/sys" packages = ["unix"] + pruneopts = "UT" revision = "314a259e304ff91bd6985da2a7149bbf91237993" [[projects]] + digest = "1:8029e9743749d4be5bc9f7d42ea1659471767860f0cdc34d37c3111bd308a295" + name = "golang.org/x/text" + packages = [ + "internal/gen", + "internal/triegen", + "internal/ucd", + "transform", + "unicode/cldr", + "unicode/norm", + ] + pruneopts = "UT" + revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" + version = "v0.3.0" + +[[projects]] + digest = "1:59c645bd5db5ec4a889a1ac62ce9cb3c4483cc24c66907ea75de2516d6fe4716" name = "gopkg.in/testfixtures.v2" packages = ["."] + pruneopts = "UT" revision = "1d98c34adfb14dbedeef37127968233b5d960f02" version = "v2.4.5" [[projects]] + digest = "1:73e6fda93622790d2371344759df06ff5ff2fac64a6b6e8832b792e7402956e7" name = "gopkg.in/yaml.v2" packages = ["."] + pruneopts = "UT" revision = "d670f9405373e636a5a2765eea47fac0c9bc91a4" version = "v2.0.0" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "aec97fcf68fb5a8fdc8e80f6aeab7b4301c46eec4f911c8e79d2206a806424bd" + input-imports = [ + "github.com/dgrijalva/jwt-go", + "github.com/go-ini/ini", + "github.com/go-sql-driver/mysql", + "github.com/go-xorm/core", + "github.com/go-xorm/xorm", + "github.com/labstack/echo", + "github.com/labstack/echo/middleware", + "github.com/mattn/go-sqlite3", + "github.com/spf13/viper", + "github.com/stretchr/testify/assert", + "golang.org/x/crypto/bcrypt", + "gopkg.in/testfixtures.v2", + ] solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 60469cf809f..2602200261b 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -48,3 +48,7 @@ [prune] go-tests = true unused-packages = true + +[[constraint]] + name = "github.com/spf13/viper" + version = "1.2.0" diff --git a/config.ini.sample b/config.ini.sample deleted file mode 100644 index c7bccc9324a..00000000000 --- a/config.ini.sample +++ /dev/null @@ -1,14 +0,0 @@ -[General] -JWTSecret = blablaGEHEMIN§)!§ -; The interface on which to run the webserver -Interface = :8080 - -[Database] -Type = mysql -User = root -Password = supersecret -Host = 127.0.0.1 -Database = vikunja -ShowQueries = false -; When using sqlite, this is the path where to store the data -; Path = ./vikunja.db \ No newline at end of file diff --git a/config.yml.sample b/config.yml.sample new file mode 100644 index 00000000000..a8dbee86fc0 --- /dev/null +++ b/config.yml.sample @@ -0,0 +1,14 @@ +service: + JWTSecret: "blablaGEHEMIN§)!§" + # The interface on which to run the webserver + interface: ":8080" + +database: + type: "sqlite" + user: "root" + password: "supersecret" + host: "127.0.0.1" + database: "vikunja" + showqueries: "true" + # When using sqlite, this is the path where to store the data + Path: "./vikunja.db" diff --git a/main.go b/main.go index c60e0bc4369..b27c2b516df 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "context" "fmt" + "github.com/spf13/viper" "os" "os/signal" "time" @@ -17,7 +18,7 @@ var Version = "0.1" func main() { // Init Config - err := models.SetConfig() + err := models.InitConfig() if err != nil { fmt.Println(err) os.Exit(1) @@ -38,7 +39,7 @@ func main() { routes.RegisterRoutes(e) // Start server go func() { - if err := e.Start(models.Config.Interface); err != nil { + if err := e.Start(viper.GetString("service.interface")); err != nil { e.Logger.Info("shutting down...") } }() diff --git a/models/config.go b/models/config.go index e2f997f3cc7..22403660b82 100644 --- a/models/config.go +++ b/models/config.go @@ -1,28 +1,57 @@ package models import ( - "github.com/go-ini/ini" + "crypto/rand" + "fmt" + "github.com/spf13/viper" "os" + "strings" ) -// ConfigStruct holds the config struct -type ConfigStruct struct { - Database struct { - Type string - Host string - User string - Password string - Database string - Path string - ShowQueries bool +func InitConfig() (err error) { + + // Set defaults + // Service config + random, err := random(32) + if err != nil { + return err } - JWTLoginSecret []byte - Interface string + viper.SetDefault("service.JWTSecret", random) + viper.SetDefault("service.interface", ":3456") + // Database + viper.SetDefault("database.type", "sqlite") + viper.SetDefault("database.host", "localhost") + viper.SetDefault("database.user", "vikunja") + viper.SetDefault("database.password", "") + viper.SetDefault("database.database", "vikunja") + viper.SetDefault("database.path", "./vikunja.db") + viper.SetDefault("database.showqueries", false) + + // Init checking for environment variables + viper.SetEnvPrefix("vikunja") + viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + viper.AutomaticEnv() + + // Load the config file + viper.AddConfigPath(".") + viper.SetConfigName("config") + err = viper.ReadInConfig() + if err != nil { + return + } + + return } -// Config holds the configuration for the program -var Config = new(ConfigStruct) +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 +} // SetConfig initianlises the config and publishes it for other functions to use func SetConfig() (err error) { @@ -33,25 +62,25 @@ func SetConfig() (err error) { } // Load the config - cfg, err := ini.Load("config.ini") + //cfg, err := ini.Load("config.ini") if err != nil { return err } // Map the config to our struct - err = cfg.MapTo(Config) + //err = cfg.MapTo(Config) if err != nil { return err } // Set default value for interface to listen on - Config.Interface = cfg.Section("General").Key("Interface").String() + /*Config.Interface = cfg.Section("General").Key("Interface").String() if Config.Interface == "" { Config.Interface = ":8080" } // JWT secret - Config.JWTLoginSecret = []byte(cfg.Section("General").Key("JWTSecret").String()) + Config.JWTLoginSecret = []byte(cfg.Section("General").Key("JWTSecret").String())*/ return nil } diff --git a/models/config_test.go b/models/config_test.go deleted file mode 100644 index 000253e3d7b..00000000000 --- a/models/config_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package models - -import ( - "github.com/stretchr/testify/assert" - "io/ioutil" - "os" - "testing" -) - -func TestSetConfig(t *testing.T) { - // Create test database - assert.NoError(t, PrepareTestDatabase()) - - // This should fail as it is looking for a nonexistent config - err := SetConfig() - assert.Error(t, err) - - // Write an invalid config - configString := `[General -JWTSecret = Supersecret -Interface = ; This should make it automatically to :8080 - -[Database -Type = sqlite -Path = ./library.db` - err = ioutil.WriteFile("config.ini", []byte(configString), 0644) - assert.NoError(t, err) - - // Test setConfig (should fail as we're trying to parse an invalid config) - err = SetConfig() - assert.Error(t, err) - - // Delete the invalid file - err = os.Remove("config.ini") - assert.NoError(t, err) - - // Write a fake config - configString = `[General] -JWTSecret = Supersecret -Interface = ; This should make it automatically to :8080 - -[Database] -Type = sqlite -Path = ./library.db` - err = ioutil.WriteFile("config.ini", []byte(configString), 0644) - assert.NoError(t, err) - - // Test setConfig - err = SetConfig() - assert.NoError(t, err) - - // Check for the values - assert.Equal(t, []byte("Supersecret"), Config.JWTLoginSecret) - assert.Equal(t, string(":8080"), Config.Interface) - assert.Equal(t, string("sqlite"), Config.Database.Type) - assert.Equal(t, string("./library.db"), Config.Database.Path) - - // Remove the dummy config - err = os.Remove("config.ini") - assert.NoError(t, err) -} diff --git a/models/models.go b/models/models.go index 31ec9301573..1ae238adfbd 100644 --- a/models/models.go +++ b/models/models.go @@ -6,6 +6,7 @@ import ( "github.com/go-xorm/core" "github.com/go-xorm/xorm" _ "github.com/mattn/go-sqlite3" // Because. + "github.com/spf13/viper" ) var ( @@ -16,14 +17,18 @@ var ( func getEngine() (*xorm.Engine, error) { // Use Mysql if set - if Config.Database.Type == "mysql" { - connStr := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8&parseTime=true", - Config.Database.User, Config.Database.Password, Config.Database.Host, Config.Database.Database) + if viper.GetString("database.type") == "mysql" { + connStr := fmt.Sprintf( + "%s:%s@tcp(%s)/%s?charset=utf8&parseTime=true", + viper.GetString("database.user"), + viper.GetString("database.password"), + viper.GetString("database.host"), + viper.GetString("database.database")) return xorm.NewEngine("mysql", connStr) } // Otherwise use sqlite - path := Config.Database.Path + path := viper.GetString("database.path") if path == "" { path = "./db.db" } @@ -63,7 +68,7 @@ func SetEngine() (err error) { return fmt.Errorf("sync database struct error: %v", err) } - x.ShowSQL(Config.Database.ShowQueries) + x.ShowSQL(viper.GetBool("database.showqueries")) return nil } diff --git a/models/models_test.go b/models/models_test.go index 06664fe70cf..6c78b801612 100644 --- a/models/models_test.go +++ b/models/models_test.go @@ -1,12 +1,13 @@ package models import ( + "github.com/spf13/viper" "github.com/stretchr/testify/assert" "testing" ) func TestSetEngine(t *testing.T) { - Config.Database.Path = "file::memory:?cache=shared" + viper.Set("database.path", "file::memory:?cache=shared") err := SetEngine() assert.NoError(t, err) } diff --git a/models/unit_tests.go b/models/unit_tests.go index 98cf649c9f1..00f73f89877 100644 --- a/models/unit_tests.go +++ b/models/unit_tests.go @@ -19,6 +19,9 @@ func MainTest(m *testing.M, pathToRoot string) { os.Exit(1) } + // Create test database + PrepareTestDatabase() + os.Exit(m.Run()) } diff --git a/routes/api/v1/login.go b/routes/api/v1/login.go index d98080a1ffb..15d67238cf8 100644 --- a/routes/api/v1/login.go +++ b/routes/api/v1/login.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "github.com/dgrijalva/jwt-go" "github.com/labstack/echo" + "github.com/spf13/viper" "net/http" "time" ) @@ -57,7 +58,7 @@ func Login(c echo.Context) error { claims["avatar"] = hex.EncodeToString(avatar[:]) // Generate encoded token and send it as response. - t, err := token.SignedString(models.Config.JWTLoginSecret) + t, err := token.SignedString([]byte(viper.GetString("service.JWTSecret"))) if err != nil { return err } diff --git a/routes/routes.go b/routes/routes.go index 25d5d0a89ca..c7c237aa579 100644 --- a/routes/routes.go +++ b/routes/routes.go @@ -34,6 +34,7 @@ import ( apiv1 "code.vikunja.io/api/routes/api/v1" _ "code.vikunja.io/api/routes/api/v1/swagger" // for docs generation "code.vikunja.io/api/routes/crud" + "github.com/spf13/viper" ) // NewEcho registers a new Echo instance @@ -67,7 +68,7 @@ func RegisterRoutes(e *echo.Echo) { // ===== Routes with Authetification ===== // Authetification - a.Use(middleware.JWT(models.Config.JWTLoginSecret)) + a.Use(middleware.JWT([]byte(viper.GetString("service.JWTSecret")))) a.POST("/tokenTest", apiv1.CheckToken) listHandler := &crud.WebHandler{