package main import ( "crypto/sha256" "database/sql" "encoding/json" "errors" "fmt" "github.com/gofiber/fiber/v2" _ "github.com/mattn/go-sqlite3" "os" "regexp" "strings" "time" ) 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 { BaseURL string `json:"base_url"` ApiKey string `json:"api_key"` InstallationDate time.Time `json:"installation_date"` } 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"` } 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 } if strings.HasSuffix(url, "/") { url = url[0 : len(url)-1] } test := regexp.MustCompile(`(?m)https?:\/\/[^/]*`).ReplaceAllString(url, "") if test != "" { return "", errors.New("HomeAssistant base URL is badly formatted") } return url, nil } func loadConfig() (config Config, err error, isFirstRun bool) { db, err := sql.Open("sqlite3", "./database.db") if err != nil { return Config{}, err, false } _, 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{}, err, false } var defaultConfig = Config{} defaultConfig.Dashboard.Theme = "default" defaultConfig.Dashboard.Name = "EcoDash" defaultConfig.Dashboard.HeaderLinks = append(defaultConfig.Dashboard.HeaderLinks, Link{ Label: "Admin", Destination: "/admin", }, Link{ Label: "Docs", Destination: "https://gitea.massivebox.net/massivebox/ecodash", 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, nil, true } return Config{}, err, false } // if the data file is empty, we consider it as a first run if string(data) == "" { return defaultConfig, nil, true } var conf Config err = json.Unmarshal(data, &conf) if err != nil { return Config{}, err, false } conf.db = db return conf, nil, false } // 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 }