ecodash/src/main/config.go
2023-05-01 19:25:16 +02:00

137 lines
3.5 KiB
Go

package main
import (
"crypto/sha256"
"database/sql"
"encoding/json"
"errors"
"fmt"
"os"
"reflect"
"regexp"
"strings"
"time"
"github.com/gofiber/fiber/v2"
_ "github.com/mattn/go-sqlite3"
)
type Config struct {
db *sql.DB
HomeAssistant HomeAssistant `json:"home_assistant"`
Sensors Sensors `json:"sensors"`
Administrator Administrator `json:"administrator"`
Dashboard Dashboard `json:"dashboard"`
}
type HomeAssistant struct {
InstallationDate time.Time `json:"installation_date"`
BaseURL string `json:"base_url"`
APIKey string `json:"api_key"`
}
type Sensors struct {
PolledSmartEnergySummation string `json:"polled_smart_energy_summation"`
FossilPercentage string `json:"fossil_percentage"`
}
type Administrator struct {
Username string `json:"username"`
PasswordHash string `json:"password_hash"`
}
type Dashboard struct {
Name string `json:"name"`
Theme string `json:"theme"`
FooterLinks []Link `json:"footer_links"`
HeaderLinks []Link `json:"header_links"`
}
var errBadHAFormat = errors.New("HomeAssistant base URL is badly formatted")
func formatURL(url string) (string, error) {
// the URL we want is: protocol://hostname[:port] without a final /
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
url = "http://" + url
}
url = strings.TrimSuffix(url, "/")
test := regexp.MustCompile(`(?m)https?://[^/]*`).ReplaceAllString(url, "")
if test != "" {
return "", errBadHAFormat
}
return url, nil
}
func loadConfig() (config *Config, isFirstRun bool, err error) {
db, err := sql.Open("sqlite3", "./database.db")
if err != nil {
return &Config{}, false, err
}
_, err = db.Exec(`CREATE TABLE IF NOT EXISTS "cache" (
"time" NUMERIC NOT NULL,
"green_energy_percentage" REAL NOT NULL,
"energy_consumption" REAL NOT NULL,
PRIMARY KEY("time")
);`)
if err != nil {
return &Config{}, false, err
}
defaultConfig := &Config{}
defaultConfig.Dashboard.Theme = "default"
defaultConfig.Dashboard.Name = "EcoDash"
defaultConfig.Dashboard.HeaderLinks = append(defaultConfig.Dashboard.HeaderLinks, Link{
Label: "Admin",
Destination: "/admin",
}, Link{
Label: "EcoDash",
Destination: "https://ecodash.xyz",
NewTab: true,
Primary: true,
})
defaultConfig.db = db
data, err := os.ReadFile("config.json")
if err != nil {
// if the data file doesn't exist, we consider it a first run
if os.IsNotExist(err) {
return defaultConfig, true, nil
}
return &Config{}, false, err
}
// if the data file is empty, we consider it as a first run
if len(data) == 0 {
return defaultConfig, true, nil
}
conf := &Config{}
err = json.Unmarshal(data, &conf)
if err != nil {
return &Config{}, false, err
}
conf.db = db
return conf, false, nil
}
// just a little utility function to SHA256 strings (for hashing passwords).
func hash(toHash string) string {
return fmt.Sprintf("%x", sha256.Sum256([]byte(toHash)))
}
func (config *Config) isAuthorized(c *fiber.Ctx) bool {
if config.Administrator.PasswordHash == "" {
return true
}
return c.Cookies("admin_username") == config.Administrator.Username && c.Cookies("admin_password_hash") == config.Administrator.PasswordHash
}
func (config *Config) Equals(c *Config) bool {
return reflect.DeepEqual(c.HomeAssistant, config.HomeAssistant) &&
reflect.DeepEqual(c.Sensors, config.Sensors) &&
reflect.DeepEqual(c.Administrator, config.Administrator) &&
reflect.DeepEqual(c.Dashboard, config.Dashboard)
}