2019-05-05 23:36:49 +03:00
|
|
|
package models
|
|
|
|
|
2020-05-24 18:32:26 +03:00
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"github.com/gorilla/securecookie"
|
2020-05-30 21:41:27 +03:00
|
|
|
"github.com/jinzhu/gorm"
|
2020-05-24 18:32:26 +03:00
|
|
|
"github.com/joho/godotenv"
|
2020-05-30 21:41:27 +03:00
|
|
|
migrate "github.com/rubenv/sql-migrate"
|
2020-05-24 18:32:26 +03:00
|
|
|
"gopkg.in/ini.v1"
|
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
|
|
|
"os"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
var cfg *Config
|
2020-05-24 14:41:19 +03:00
|
|
|
|
2019-05-05 23:36:49 +03:00
|
|
|
type Config struct {
|
2020-05-30 21:41:27 +03:00
|
|
|
Env string
|
|
|
|
Version string
|
|
|
|
Port int
|
|
|
|
Addr string
|
|
|
|
BasePath string
|
|
|
|
DbHost string
|
|
|
|
DbPort uint
|
|
|
|
DbUser string
|
|
|
|
DbPassword string
|
|
|
|
DbName string
|
|
|
|
DbDialect string
|
|
|
|
DbMaxConn uint
|
|
|
|
CleanUp bool
|
2020-05-28 23:36:00 +03:00
|
|
|
// this is actually a pepper (https://en.wikipedia.org/wiki/Pepper_(cryptography))
|
2020-05-25 22:42:45 +03:00
|
|
|
PasswordSalt string
|
2020-05-24 14:41:19 +03:00
|
|
|
SecureCookieHashKey string
|
|
|
|
SecureCookieBlockKey string
|
2020-05-30 13:11:21 +03:00
|
|
|
InsecureCookies bool
|
2020-05-24 14:41:19 +03:00
|
|
|
CustomLanguages map[string]string
|
|
|
|
LanguageColors map[string]string
|
|
|
|
SecureCookie *securecookie.SecureCookie
|
2019-05-05 23:36:49 +03:00
|
|
|
}
|
2020-02-20 17:39:56 +03:00
|
|
|
|
|
|
|
func (c *Config) IsDev() bool {
|
2020-05-30 13:11:21 +03:00
|
|
|
return IsDev(c.Env)
|
|
|
|
}
|
|
|
|
|
2020-05-30 21:41:27 +03:00
|
|
|
func (c *Config) GetMigrationFunc(dbDialect string) MigrationFunc {
|
|
|
|
switch dbDialect {
|
|
|
|
case "sqlite3":
|
|
|
|
return func(db *gorm.DB) error {
|
|
|
|
migrations := &migrate.FileMigrationSource{
|
|
|
|
Dir: "migrations/sqlite3",
|
|
|
|
}
|
|
|
|
|
|
|
|
migrate.SetIgnoreUnknown(true)
|
|
|
|
n, err := migrate.Exec(db.DB(), "sqlite3", migrations, migrate.Up)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Printf("applied %d migrations\n", n)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return func(db *gorm.DB) error {
|
|
|
|
db.AutoMigrate(&Alias{})
|
|
|
|
db.AutoMigrate(&Summary{})
|
|
|
|
db.AutoMigrate(&SummaryItem{})
|
|
|
|
db.AutoMigrate(&User{})
|
|
|
|
db.AutoMigrate(&Heartbeat{}).AddForeignKey("user_id", "users(id)", "RESTRICT", "RESTRICT")
|
|
|
|
db.AutoMigrate(&SummaryItem{}).AddForeignKey("summary_id", "summaries(id)", "CASCADE", "CASCADE")
|
|
|
|
db.AutoMigrate(&KeyStringValue{})
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Config) GetFixturesFunc(dbDialect string) MigrationFunc {
|
|
|
|
return func(db *gorm.DB) error {
|
|
|
|
migrations := &migrate.FileMigrationSource{
|
|
|
|
Dir: "migrations/common/fixtures",
|
|
|
|
}
|
|
|
|
|
|
|
|
migrate.SetIgnoreUnknown(true)
|
|
|
|
n, err := migrate.Exec(db.DB(), dbDialect, migrations, migrate.Up)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Printf("applied %d fixtures\n", n)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-30 13:11:21 +03:00
|
|
|
func IsDev(env string) bool {
|
|
|
|
return env == "dev" || env == "development"
|
2020-02-20 17:39:56 +03:00
|
|
|
}
|
2020-05-24 18:32:26 +03:00
|
|
|
|
|
|
|
func SetConfig(config *Config) {
|
|
|
|
cfg = config
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetConfig() *Config {
|
|
|
|
return cfg
|
|
|
|
}
|
|
|
|
|
|
|
|
func LookupFatal(key string) string {
|
|
|
|
v, ok := os.LookupEnv(key)
|
|
|
|
if !ok {
|
|
|
|
log.Fatalf("missing env variable '%s'", key)
|
|
|
|
}
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
2020-05-24 22:42:15 +03:00
|
|
|
func readVersion() string {
|
|
|
|
file, err := os.Open("version.txt")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
defer file.Close()
|
|
|
|
|
|
|
|
bytes, err := ioutil.ReadAll(file)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return string(bytes)
|
|
|
|
}
|
|
|
|
|
2020-05-24 18:32:26 +03:00
|
|
|
func readConfig() *Config {
|
|
|
|
if err := godotenv.Load(); err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2020-05-24 22:42:15 +03:00
|
|
|
version := readVersion()
|
|
|
|
|
2020-05-24 18:32:26 +03:00
|
|
|
env := LookupFatal("ENV")
|
|
|
|
dbType := LookupFatal("WAKAPI_DB_TYPE")
|
|
|
|
dbUser := LookupFatal("WAKAPI_DB_USER")
|
|
|
|
dbPassword := LookupFatal("WAKAPI_DB_PASSWORD")
|
|
|
|
dbHost := LookupFatal("WAKAPI_DB_HOST")
|
|
|
|
dbName := LookupFatal("WAKAPI_DB_NAME")
|
|
|
|
dbPortStr := LookupFatal("WAKAPI_DB_PORT")
|
2020-05-25 22:42:45 +03:00
|
|
|
passwordSalt := LookupFatal("WAKAPI_PASSWORD_SALT")
|
2020-05-24 18:32:26 +03:00
|
|
|
dbPort, err := strconv.Atoi(dbPortStr)
|
|
|
|
|
|
|
|
cfg, err := ini.Load("config.ini")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("Fail to read file: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if dbType == "" {
|
|
|
|
dbType = "mysql"
|
|
|
|
}
|
|
|
|
|
|
|
|
dbMaxConn := cfg.Section("database").Key("max_connections").MustUint(1)
|
|
|
|
addr := cfg.Section("server").Key("listen").MustString("127.0.0.1")
|
2020-05-30 13:11:21 +03:00
|
|
|
insecureCookies := IsDev(env) || cfg.Section("server").Key("insecure_cookies").MustBool(false)
|
2020-05-24 18:32:26 +03:00
|
|
|
port, err := strconv.Atoi(os.Getenv("PORT"))
|
|
|
|
if err != nil {
|
|
|
|
port = cfg.Section("server").Key("port").MustInt()
|
|
|
|
}
|
|
|
|
|
|
|
|
basePath := cfg.Section("server").Key("base_path").MustString("/")
|
|
|
|
if strings.HasSuffix(basePath, "/") {
|
|
|
|
basePath = basePath[:len(basePath)-1]
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanUp := cfg.Section("app").Key("cleanup").MustBool(false)
|
|
|
|
|
|
|
|
// Read custom languages
|
|
|
|
customLangs := make(map[string]string)
|
|
|
|
languageKeys := cfg.Section("languages").Keys()
|
|
|
|
for _, k := range languageKeys {
|
|
|
|
customLangs[k.Name()] = k.MustString("unknown")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read language colors
|
|
|
|
// Source: https://raw.githubusercontent.com/ozh/github-colors/master/colors.json
|
|
|
|
var colors = make(map[string]string)
|
|
|
|
var rawColors map[string]struct {
|
|
|
|
Color string `json:"color"`
|
|
|
|
Url string `json:"url"`
|
|
|
|
}
|
|
|
|
|
|
|
|
data, err := ioutil.ReadFile("data/colors.json")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := json.Unmarshal(data, &rawColors); err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
for k, v := range rawColors {
|
|
|
|
colors[strings.ToLower(k)] = v.Color
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Read keys from env, so that users are not logged out every time the server is restarted
|
|
|
|
secureCookie := securecookie.New(
|
|
|
|
securecookie.GenerateRandomKey(64),
|
|
|
|
securecookie.GenerateRandomKey(32),
|
|
|
|
)
|
|
|
|
|
|
|
|
return &Config{
|
2020-05-30 21:41:27 +03:00
|
|
|
Env: env,
|
|
|
|
Version: version,
|
|
|
|
Port: port,
|
|
|
|
Addr: addr,
|
|
|
|
BasePath: basePath,
|
|
|
|
DbHost: dbHost,
|
|
|
|
DbPort: uint(dbPort),
|
|
|
|
DbUser: dbUser,
|
|
|
|
DbPassword: dbPassword,
|
|
|
|
DbName: dbName,
|
|
|
|
DbDialect: dbType,
|
|
|
|
DbMaxConn: dbMaxConn,
|
|
|
|
CleanUp: cleanUp,
|
|
|
|
InsecureCookies: insecureCookies,
|
|
|
|
SecureCookie: secureCookie,
|
|
|
|
PasswordSalt: passwordSalt,
|
|
|
|
CustomLanguages: customLangs,
|
|
|
|
LanguageColors: colors,
|
2020-05-24 18:32:26 +03:00
|
|
|
}
|
|
|
|
}
|