mirror of
https://github.com/kaaninchen/Laterna.git
synced 2026-09-17 19:12:48 +00:00
authentification groundworks
This commit is contained in:
@@ -2,6 +2,7 @@ package db
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"flag"
|
||||||
|
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
"github.com/siestaw/laterna/server/cmd/internal/logger"
|
"github.com/siestaw/laterna/server/cmd/internal/logger"
|
||||||
@@ -18,9 +19,17 @@ func ConnectDB() {
|
|||||||
}
|
}
|
||||||
logger.DBLogger.Printf("Successfully connected to the database!")
|
logger.DBLogger.Printf("Successfully connected to the database!")
|
||||||
InitDB()
|
InitDB()
|
||||||
|
|
||||||
|
resetAdmin := flag.Bool("resetAdminToken", false, "recreate the admin token")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if *resetAdmin {
|
||||||
|
ResetAdmin()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitDB() {
|
func InitDB() {
|
||||||
|
// Legacy purposes, DELETE
|
||||||
_, err := DB.Exec(`
|
_, err := DB.Exec(`
|
||||||
CREATE TABLE IF NOT EXISTS lamp_state (
|
CREATE TABLE IF NOT EXISTS lamp_state (
|
||||||
id TEXT PRIMARY KEY,
|
id TEXT PRIMARY KEY,
|
||||||
@@ -32,4 +41,24 @@ func InitDB() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
logger.DBLogger.Fatalf("An error occured while initializing the database: %v", err)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,59 @@ import (
|
|||||||
"github.com/siestaw/laterna/server/cmd/utils"
|
"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) {
|
func ViewColor(id int) (*models.LampState, error) {
|
||||||
row := DB.QueryRow("SELECT * FROM lamp_state WHERE id = ?", id)
|
row := DB.QueryRow("SELECT * FROM lamp_state WHERE id = ?", id)
|
||||||
|
|
||||||
|
|||||||
@@ -15,10 +15,19 @@ import (
|
|||||||
|
|
||||||
func StartHTTPServer() {
|
func StartHTTPServer() {
|
||||||
router := http.NewServeMux()
|
router := http.NewServeMux()
|
||||||
|
|
||||||
router.HandleFunc("GET /api/v1/id/{ID}", getCurrent)
|
router.HandleFunc("GET /api/v1/id/{ID}", getCurrent)
|
||||||
router.HandleFunc("PUT /api/v1/id/{ID}", setCurrent)
|
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
|
port := config.AppConfig.HTTP.Port
|
||||||
logger.HTTPLogger.Printf("HTTP Server running on :%v", port)
|
logger.HTTPLogger.Printf("HTTP Server running on :%v", port)
|
||||||
http.ListenAndServe(fmt.Sprintf(":%d", port), router)
|
http.ListenAndServe(fmt.Sprintf(":%d", port), router)
|
||||||
|
|||||||
+1
-1
@@ -11,6 +11,6 @@ func main() {
|
|||||||
config.AppConfig = config.LoadConfig("config.json")
|
config.AppConfig = config.LoadConfig("config.json")
|
||||||
logger.InitLoggers()
|
logger.InitLoggers()
|
||||||
|
|
||||||
go db.ConnectDB()
|
db.ConnectDB()
|
||||||
http.StartHTTPServer()
|
http.StartHTTPServer()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -9,6 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/siestaw/laterna/server/cmd/internal/models"
|
"github.com/siestaw/laterna/server/cmd/internal/models"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func IDtoInt(id string) (int, error) {
|
func IDtoInt(id string) (int, error) {
|
||||||
@@ -21,12 +24,31 @@ func IDtoInt(id string) (int, error) {
|
|||||||
}
|
}
|
||||||
return idInt, nil
|
return idInt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsValidHexColor(color string) bool {
|
func IsValidHexColor(color string) bool {
|
||||||
pattern := `^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$`
|
pattern := `^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$`
|
||||||
match, _ := regexp.MatchString(pattern, color)
|
match, _ := regexp.MatchString(pattern, color)
|
||||||
return match
|
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) {
|
func HTTPErrorHandling(w http.ResponseWriter, r *http.Request, status int, message string) {
|
||||||
timestamp := time.Now().Format("2006-01-02_15-04-05")
|
timestamp := time.Now().Format("2006-01-02_15-04-05")
|
||||||
errResp := models.HTTPError{
|
errResp := models.HTTPError{
|
||||||
|
|||||||
@@ -2,4 +2,7 @@ module github.com/siestaw/laterna/server
|
|||||||
|
|
||||||
go 1.24.4
|
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
|
||||||
|
)
|
||||||
|
|||||||
@@ -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 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A=
|
||||||
github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
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=
|
||||||
|
|||||||
Reference in New Issue
Block a user