website/pkg/config/variable.go

168 lines
4.1 KiB
Go

package config
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"code.nonshy.com/nonshy/website/pkg/encryption/keygen"
"code.nonshy.com/nonshy/website/pkg/log"
"github.com/google/uuid"
)
// Version of the config format - when new fields are added, it will attempt
// to write the settings.toml to disk so new defaults populate.
var currentVersion = 2
// Current loaded settings.json
var Current = DefaultVariable()
// Variable configuration attributes (loaded from settings.json).
type Variable struct {
Version int
BaseURL string
AdminEmail string
CronAPIKey string
Mail Mail
Redis Redis
Database Database
BareRTC BareRTC
Maintenance Maintenance
Encryption Encryption
UseXForwardedFor bool
}
// DefaultVariable returns the default settings.json data.
func DefaultVariable() Variable {
return Variable{
BaseURL: "http://localhost:8080",
Mail: Mail{
Enabled: false,
Host: "localhost",
Port: 25,
From: "no-reply@localhost",
},
Redis: Redis{
Host: "localhost",
Port: 6379,
},
Database: Database{
SQLite: "database.sqlite",
Postgres: "host=localhost user=nonshy password=nonshy dbname=nonshy port=5679 sslmode=disable TimeZone=America/Los_Angeles",
},
CronAPIKey: uuid.New().String(),
}
}
// LoadSettings loads the settings.json file or, if not existing, creates it with the default settings.
func LoadSettings() {
var writeSettings bool
if _, err := os.Stat(SettingsPath); !os.IsNotExist(err) {
log.Info("Loading settings from %s", SettingsPath)
content, err := ioutil.ReadFile(SettingsPath)
if err != nil {
panic(fmt.Sprintf("LoadSettings: couldn't read settings.json: %s", err))
}
var v Variable
err = json.Unmarshal(content, &v)
if err != nil {
panic(fmt.Sprintf("LoadSettings: couldn't parse settings.json: %s", err))
}
Current = v
} else {
WriteSettings()
log.Warn("NOTICE: Created default settings.json file - review it and configure mail servers and database!")
}
// If there is no DB configured, exit now.
if !Current.Database.IsSQLite && !Current.Database.IsPostgres {
log.Error("No database configured in settings.json. Choose SQLite or Postgres and update the DB connector string!")
os.Exit(1)
}
// Initialize the AES encryption key.
if len(Current.Encryption.AESKey) == 0 {
log.Warn("NOTICE: rolling a random 32-byte (256-bit) AES encryption key for the settings file")
aesKey, err := keygen.NewAESKey()
if err != nil {
log.Error("Couldn't generate AES key: %s", err)
os.Exit(1)
}
Current.Encryption.AESKey = aesKey
writeSettings = true
}
// Have we added new config fields? Save the settings.json.
if Current.Version != currentVersion || writeSettings {
log.Warn("New options are available for your settings.json file. Your settings will be re-saved now.")
Current.Version = currentVersion
if err := WriteSettings(); err != nil {
log.Error("Couldn't write your settings.json file: %s", err)
}
}
}
// WriteSettings will commit the settings.json to disk.
func WriteSettings() error {
log.Error("Note: initial settings.json was written to disk.")
var buf bytes.Buffer
enc := json.NewEncoder(&buf)
enc.SetIndent("", " ")
err := enc.Encode(Current)
if err != nil {
panic(fmt.Sprintf("WriteSettings: couldn't marshal settings: %s", err))
}
return ioutil.WriteFile(SettingsPath, buf.Bytes(), 0600)
}
// Mail settings.
type Mail struct {
Enabled bool
Host string // localhost
Port int // 25
From string // noreply@localhost
Username string // SMTP credentials
Password string
}
// Redis settings.
type Redis struct {
Host string
Port int
DB int
}
// Database settings.
type Database struct {
IsSQLite bool
IsPostgres bool
SQLite string
Postgres string
}
// BareRTC chat room settings.
type BareRTC struct {
JWTSecret string
URL string
}
// Maintenance mode settings.
type Maintenance struct {
PauseSignup bool
PauseLogin bool
PauseChat bool
PauseInteraction bool
}
// Encryption settings.
type Encryption struct {
AESKey []byte
}