From e41153647787f05938d04baff458d21d6a3a09ae Mon Sep 17 00:00:00 2001 From: Mitsu <124433727+Mizuw@users.noreply.github.com> Date: Fri, 11 Jul 2025 08:30:53 +0200 Subject: [PATCH] authentification groundworks --- cmd/internal/db/connection.go | 31 +++++++++++++++++++- cmd/internal/db/queries.go | 53 +++++++++++++++++++++++++++++++++++ cmd/internal/http/server.go | 11 +++++++- cmd/server/main.go | 2 +- cmd/utils/utils.go | 22 +++++++++++++++ go.mod | 5 +++- go.sum | 2 ++ 7 files changed, 122 insertions(+), 4 deletions(-) diff --git a/cmd/internal/db/connection.go b/cmd/internal/db/connection.go index 41a632d..94c8802 100644 --- a/cmd/internal/db/connection.go +++ b/cmd/internal/db/connection.go @@ -2,6 +2,7 @@ package db import ( "database/sql" + "flag" _ "github.com/mattn/go-sqlite3" "github.com/siestaw/laterna/server/cmd/internal/logger" @@ -18,10 +19,18 @@ func ConnectDB() { } logger.DBLogger.Printf("Successfully connected to the database!") InitDB() + + resetAdmin := flag.Bool("resetAdminToken", false, "recreate the admin token") + flag.Parse() + + if *resetAdmin { + ResetAdmin() + } } func InitDB() { - _, err := DB.Exec(` + // Legacy purposes, DELETE + _, err := DB.Exec(` CREATE TABLE IF NOT EXISTS lamp_state ( id TEXT PRIMARY KEY, color TEXT NOT NULL, @@ -32,4 +41,24 @@ func InitDB() { if err != nil { logger.DBLogger.Fatalf("An error occured while initializing the database: %v", err) } + + _, err = DB.Exec(` + CREATE TABLE IF NOT EXISTS controllers ( + id INTEGER PRIMARY KEY, + token_hash TEXT NOT NULL, + color TEXT, + updated_at DATETIME + );`) + if err != nil { + logger.DBLogger.Fatalf("An error occured while initializing the database: %v", err) + } + + _, err = DB.Exec(` + CREATE TABLE IF NOT EXISTS permissions ( + controller_id INTEGER, + target_id INTEGER + );`) + if err != nil { + logger.DBLogger.Fatalf("An error occured while initializing the database: %v", err) + } } diff --git a/cmd/internal/db/queries.go b/cmd/internal/db/queries.go index 0811fa4..720036c 100644 --- a/cmd/internal/db/queries.go +++ b/cmd/internal/db/queries.go @@ -8,6 +8,59 @@ import ( "github.com/siestaw/laterna/server/cmd/utils" ) +func CreateController(target int) (string, int, error) { + token, _ := utils.GenerateToken() + hash, _ := utils.HashToken(token) + + var maxID int + stmt := DB.QueryRow("SELECT COALESCE(MAX(id), 0) FROM controllers") + stmt.Scan(&maxID) + id := maxID + 1 + + _, err := DB.Exec("INSERT INTO controllers VALUES (?, ?, '#FFFFFF', CURRENT_TIMESTAMP)", id, hash) + if err != nil { + logger.DBLogger.Printf("Failed to create a new controller: %v", err) + return "", id, err + } + + _, err = DB.Exec("INSERT INTO permissions VALUES (?, ?) ", id, target) + if err != nil { + logger.DBLogger.Printf("Failed to set permissions for %d: %v", id, err) + return token, id, err + } + return token, id, nil +} + +func CreateAdmin() string { + token, _ := utils.GenerateToken() + hash, _ := utils.HashToken(token) + + _, err := DB.Exec("INSERT INTO controllers (id, token_hash) VALUES (0, ?)", hash) + if err != nil { + logger.DBLogger.Fatalf("Error creating admin user: %s", err) + } + + return token +} + +func ResetAdmin() { + _, err := DB.Exec("DELETE FROM controllers WHERE id = 0") + if err != nil { + logger.DBLogger.Printf("An error occured while resetting the admin account: %s", err) + } +} + +func ControllerExists(id int) bool { + row := DB.QueryRow("SELECT COUNT(1) FROM controllers WHERE id = ?", id) + + var count int + err := row.Scan(&count) + if err != nil { + logger.DBLogger.Printf("ControllerExists: %v", err) + } + return count > 0 +} + func ViewColor(id int) (*models.LampState, error) { row := DB.QueryRow("SELECT * FROM lamp_state WHERE id = ?", id) diff --git a/cmd/internal/http/server.go b/cmd/internal/http/server.go index 845097c..17da1de 100644 --- a/cmd/internal/http/server.go +++ b/cmd/internal/http/server.go @@ -15,10 +15,19 @@ import ( func StartHTTPServer() { router := http.NewServeMux() - router.HandleFunc("GET /api/v1/id/{ID}", getCurrent) router.HandleFunc("PUT /api/v1/id/{ID}", setCurrent) + if !db.ControllerExists(0) { + adminToken := db.CreateAdmin() + fmt.Println("IMPORTANT") + fmt.Println("- - - - - - - - - - - - - - - - - - ") + fmt.Println("ADMIN TOKEN:") + fmt.Printf("%s\n", adminToken) + fmt.Println("REGENERATE THE TOKEN BY RUNNING WITH -resetAdminToken") + fmt.Println("- - - - - - - - - - - - - - - - - - ") + } + port := config.AppConfig.HTTP.Port logger.HTTPLogger.Printf("HTTP Server running on :%v", port) http.ListenAndServe(fmt.Sprintf(":%d", port), router) diff --git a/cmd/server/main.go b/cmd/server/main.go index 11484c3..5512a21 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -11,6 +11,6 @@ func main() { config.AppConfig = config.LoadConfig("config.json") logger.InitLoggers() - go db.ConnectDB() + db.ConnectDB() http.StartHTTPServer() } diff --git a/cmd/utils/utils.go b/cmd/utils/utils.go index d0a2ddc..03e14b0 100644 --- a/cmd/utils/utils.go +++ b/cmd/utils/utils.go @@ -1,6 +1,8 @@ package utils import ( + "crypto/rand" + "encoding/hex" "encoding/json" "errors" "net/http" @@ -9,6 +11,7 @@ import ( "time" "github.com/siestaw/laterna/server/cmd/internal/models" + "golang.org/x/crypto/bcrypt" ) func IDtoInt(id string) (int, error) { @@ -21,12 +24,31 @@ func IDtoInt(id string) (int, error) { } return idInt, nil } + func IsValidHexColor(color string) bool { pattern := `^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$` match, _ := regexp.MatchString(pattern, color) return match } +func GenerateToken() (string, error) { + bytes := make([]byte, 32) + if _, err := rand.Read(bytes); err != nil { + return "", err + } + return hex.EncodeToString(bytes), nil +} + +func HashToken(token string) (string, error) { + hash, err := bcrypt.GenerateFromPassword([]byte(token), bcrypt.DefaultCost) + return string(hash), err +} + +func ValidateToken(providedToken string, storedHash string) bool { + err := bcrypt.CompareHashAndPassword([]byte(storedHash), []byte(providedToken)) + return err == nil +} + func HTTPErrorHandling(w http.ResponseWriter, r *http.Request, status int, message string) { timestamp := time.Now().Format("2006-01-02_15-04-05") errResp := models.HTTPError{ diff --git a/go.mod b/go.mod index b137c03..606f288 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,7 @@ module github.com/siestaw/laterna/server go 1.24.4 -require github.com/mattn/go-sqlite3 v1.14.28 +require ( + github.com/mattn/go-sqlite3 v1.14.28 + golang.org/x/crypto v0.40.0 +) diff --git a/go.sum b/go.sum index 42e5bac..510b999 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,4 @@ github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A= github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=