This commit is contained in:
Daniil Gentili 2023-05-01 19:39:12 +02:00
parent 345adcf479
commit d5c467c691
Signed by: danog
GPG key ID: 8C1BE3B34B230CA7
10 changed files with 880 additions and 71 deletions

View file

@ -1,4 +1,4 @@
package main
package ecodash
import (
"context"

View file

@ -1,11 +1,9 @@
package main
package ecodash
import (
"crypto/sha256"
"database/sql"
"encoding/json"
"errors"
"fmt"
"os"
"reflect"
"regexp"
@ -62,7 +60,7 @@ func formatURL(url string) (string, error) {
return url, nil
}
func loadConfig() (config *Config, isFirstRun bool, err error) {
func LoadConfig() (config *Config, isFirstRun bool, err error) {
db, err := sql.Open("sqlite3", "./database.db")
if err != nil {
return &Config{}, false, err
@ -116,12 +114,7 @@ func loadConfig() (config *Config, isFirstRun bool, err error) {
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 {
func (config *Config) IsAuthorized(c *fiber.Ctx) bool {
if config.Administrator.PasswordHash == "" {
return true
}

View file

@ -1,4 +1,4 @@
package main
package ecodash
import (
"database/sql"
@ -14,7 +14,7 @@ type HistoryEntry struct {
}
type History []HistoryEntry
func (config *Config) updateHistory() {
func (config *Config) UpdateHistory() {
greenEnergyPercentage, err := config.historyAverageAndConvertToGreen(config.Sensors.FossilPercentage, time.Now())
if err != nil {
return

View file

@ -1,4 +1,4 @@
package main
package ecodash
import (
"encoding/json"
@ -8,9 +8,9 @@ import (
"html/template"
"math"
"os"
"strconv"
"time"
"git.massivebox.net/ecodash/ecodash/src/tools"
"github.com/gofiber/fiber/v2"
)
@ -36,23 +36,23 @@ func (config *Config) getTemplateDefaults() fiber.Map {
}
}
func (config *Config) templateDefaultsMap() fiber.Map {
func (config *Config) TemplateDefaultsMap() fiber.Map {
return fiber.Map{
"Default": config.getTemplateDefaults(),
}
}
func (config *Config) adminEndpoint(c *fiber.Ctx) error {
func (config *Config) AdminEndpoint(c *fiber.Ctx) error {
if c.Method() == "POST" {
if config.isAuthorized(c) { // here the user is submitting the form to change configuration
if config.IsAuthorized(c) { // here the user is submitting the form to change configuration
err := config.saveAdminForm(c)
if err != nil {
return config.renderAdminPanel(c, Warning{
return config.RenderAdminPanel(c, Warning{
Header: "An error occurred!",
Body: html.EscapeString(err.Error()),
})
}
return config.renderAdminPanel(c, Warning{
return config.RenderAdminPanel(c, Warning{
Header: "Restart needed",
Body: "In order to apply changes, please <b>restart EcoDash</b>.<br>" +
"If you're running via Docker, click <a href='./restart'>here</a> to restart automatically.",
@ -61,21 +61,21 @@ func (config *Config) adminEndpoint(c *fiber.Ctx) error {
}
// here the user is trying to authenticate
if c.FormValue("username") == config.Administrator.Username && hash(c.FormValue("password")) == config.Administrator.PasswordHash {
if c.FormValue("username") == config.Administrator.Username && tools.Hash(c.FormValue("password")) == config.Administrator.PasswordHash {
c.Cookie(&fiber.Cookie{Name: "admin_username", Value: c.FormValue("username")})
c.Cookie(&fiber.Cookie{Name: "admin_password_hash", Value: hash(c.FormValue("password"))})
return config.renderAdminPanel(c)
c.Cookie(&fiber.Cookie{Name: "admin_password_hash", Value: tools.Hash(c.FormValue("password"))})
return config.RenderAdminPanel(c)
}
return c.Render("login", fiber.Map{"Defaults": config.getTemplateDefaults(), "Failed": true}, "base")
}
if config.isAuthorized(c) {
return config.renderAdminPanel(c)
if config.IsAuthorized(c) {
return config.RenderAdminPanel(c)
}
return c.Render("login", config.templateDefaultsMap(), "base")
return c.Render("login", config.TemplateDefaultsMap(), "base")
}
func (config *Config) renderAdminPanel(c *fiber.Ctx, warning ...Warning) error {
func (config *Config) RenderAdminPanel(c *fiber.Ctx, warning ...Warning) error {
dirs, err := os.ReadDir("./templates")
if err != nil {
return err
@ -125,7 +125,7 @@ func (config *Config) saveAdminForm(c *fiber.Ctx) error {
}
if c.FormValue("keep_old_password") == "" {
form.Administrator.PasswordHash = hash(c.FormValue("password"))
form.Administrator.PasswordHash = tools.Hash(c.FormValue("password"))
} else {
form.Administrator.PasswordHash = config.Administrator.PasswordHash
}
@ -167,7 +167,7 @@ func averageExcludingCurrentDay(data []float32) float32 {
return float32(math.Floor(float64(avg)*100)) / 100
}
func (config *Config) renderIndex(c *fiber.Ctx) error {
func (config *Config) RenderIndex(c *fiber.Ctx) error {
if config.HomeAssistant.InstallationDate.IsZero() {
return c.Render("config-error", fiber.Map{
"Defaults": config.getTemplateDefaults(),
@ -203,25 +203,3 @@ func (config *Config) renderIndex(c *fiber.Ctx) error {
"PerDayUsage": perDayUsage,
}, "base")
}
func templateDivide(num1, num2 float32) template.HTML {
division := float64(num1 / num2)
powerOfTen := int(math.Floor(math.Log10(division)))
if powerOfTen >= -2 && powerOfTen <= 2 {
// #nosec G203 // We're only printing floats
return template.HTML(strconv.FormatFloat(math.Round(division*100)/100, 'f', -1, 64))
}
preComma := division / math.Pow10(powerOfTen)
// #nosec G203 // We're only printing floats
return template.HTML(fmt.Sprintf("%s * 10<sup>%d</sup>", strconv.FormatFloat(math.Round(preComma*100)/100, 'f', -1, 64), powerOfTen))
}
func templateHTMLDateFormat(date time.Time) template.HTML {
if date.IsZero() {
return ""
}
// #nosec G203 // We're only printing a date
return template.HTML(date.Format("2006-01-02"))
}

View file

@ -9,27 +9,30 @@ import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/template/html"
"github.com/robfig/cron/v3"
"git.massivebox.net/ecodash/ecodash/src/ecodash"
"git.massivebox.net/ecodash/ecodash/src/tools"
)
func main() {
config, isFirstRun, err := loadConfig()
config, isFirstRun, err := ecodash.LoadConfig()
if err != nil {
log.Fatal(err)
}
if !isFirstRun {
cr := cron.New()
_, err = cr.AddFunc("@hourly", config.updateHistory)
_, err = cr.AddFunc("@hourly", config.UpdateHistory)
if err != nil {
log.Fatal(err)
}
cr.Start()
config.updateHistory()
config.UpdateHistory()
}
engine := html.New("./templates/"+config.Dashboard.Theme, ".html")
engine.AddFunc("divide", templateDivide)
engine.AddFunc("HTMLDateFormat", templateHTMLDateFormat)
engine.AddFunc("divide", tools.TemplateDivide)
engine.AddFunc("HTMLDateFormat", tools.TemplateHTMLDateFormat)
app := fiber.New(fiber.Config{
Views: engine,
@ -40,25 +43,25 @@ func main() {
app.Get("/", func(c *fiber.Ctx) error {
if isFirstRun {
c.Cookie(&fiber.Cookie{Name: "admin_username", Value: ""})
c.Cookie(&fiber.Cookie{Name: "admin_password_hash", Value: hash("")})
return config.renderAdminPanel(c)
c.Cookie(&fiber.Cookie{Name: "admin_password_hash", Value: tools.Hash("")})
return config.RenderAdminPanel(c)
}
return config.renderIndex(c)
return config.RenderIndex(c)
})
app.Get("/accuracy-notice", func(c *fiber.Ctx) error {
return c.Render("accuracy-notice", config.templateDefaultsMap(), "base")
return c.Render("accuracy-notice", config.TemplateDefaultsMap(), "base")
})
app.All("/admin", config.adminEndpoint)
app.All("/admin", config.AdminEndpoint)
app.Get("/restart", func(c *fiber.Ctx) error {
if config.isAuthorized(c) {
if config.IsAuthorized(c) {
go func() {
time.Sleep(time.Second)
os.Exit(1)
}()
return c.Render("restart", config.templateDefaultsMap(), "base")
return c.Render("restart", config.TemplateDefaultsMap(), "base")
}
return c.Redirect("./", http.StatusTemporaryRedirect)
})

37
src/tools/tools.go Normal file
View file

@ -0,0 +1,37 @@
package tools
import (
"crypto/sha256"
"fmt"
"html/template"
"math"
"strconv"
"time"
)
// 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 TemplateDivide(num1, num2 float32) template.HTML {
division := float64(num1 / num2)
powerOfTen := int(math.Floor(math.Log10(division)))
if powerOfTen >= -2 && powerOfTen <= 2 {
// #nosec G203 // We're only printing floats
return template.HTML(strconv.FormatFloat(math.Round(division*100)/100, 'f', -1, 64))
}
preComma := division / math.Pow10(powerOfTen)
// #nosec G203 // We're only printing floats
return template.HTML(fmt.Sprintf("%s * 10<sup>%d</sup>", strconv.FormatFloat(math.Round(preComma*100)/100, 'f', -1, 64), powerOfTen))
}
func TemplateHTMLDateFormat(date time.Time) template.HTML {
if date.IsZero() {
return ""
}
// #nosec G203 // We're only printing a date
return template.HTML(date.Format("2006-01-02"))
}