diff --git a/cmd/internal/db/queries.go b/cmd/internal/db/queries.go index 720036c..c1dc28e 100644 --- a/cmd/internal/db/queries.go +++ b/cmd/internal/db/queries.go @@ -6,6 +6,7 @@ import ( "github.com/siestaw/laterna/server/cmd/internal/logger" "github.com/siestaw/laterna/server/cmd/internal/models" "github.com/siestaw/laterna/server/cmd/utils" + "golang.org/x/crypto/bcrypt" ) func CreateController(target int) (string, int, error) { @@ -50,6 +51,19 @@ func ResetAdmin() { } } +func IsAdmin(token string) bool { + stmt := DB.QueryRow("SELECT token_hash FROM controllers WHERE id = 0") + + var hashToken string + err := stmt.Scan(&hashToken) + if err != nil { + logger.DBLogger.Printf("Error retrieving admin hash: %v", err) + return false + } + err = bcrypt.CompareHashAndPassword([]byte(hashToken), []byte(token)) + return err == nil +} + func ControllerExists(id int) bool { row := DB.QueryRow("SELECT COUNT(1) FROM controllers WHERE id = ?", id) diff --git a/cmd/internal/http/server.go b/cmd/internal/http/server.go index 17da1de..e37ceb0 100644 --- a/cmd/internal/http/server.go +++ b/cmd/internal/http/server.go @@ -1,22 +1,19 @@ package http import ( - "encoding/json" "fmt" "net/http" - "time" "github.com/siestaw/laterna/server/cmd/internal/config" "github.com/siestaw/laterna/server/cmd/internal/db" "github.com/siestaw/laterna/server/cmd/internal/logger" - "github.com/siestaw/laterna/server/cmd/internal/models" - "github.com/siestaw/laterna/server/cmd/utils" + "github.com/siestaw/laterna/server/cmd/internal/routes" ) func StartHTTPServer() { router := http.NewServeMux() - router.HandleFunc("GET /api/v1/id/{ID}", getCurrent) - router.HandleFunc("PUT /api/v1/id/{ID}", setCurrent) + routes.RegisterUserRoutes(router) + routes.RegisterAdminRoutes(router) if !db.ControllerExists(0) { adminToken := db.CreateAdmin() @@ -32,63 +29,3 @@ func StartHTTPServer() { logger.HTTPLogger.Printf("HTTP Server running on :%v", port) http.ListenAndServe(fmt.Sprintf(":%d", port), router) } - -func getCurrent(w http.ResponseWriter, r *http.Request) { - idStr := r.PathValue("ID") - id, err := utils.IDtoInt(idStr) - if err != nil { - utils.HTTPErrorHandling(w, r, http.StatusBadRequest, err.Error()) - return - } - - state, err := db.ViewColor(id) - if err != nil { - utils.HTTPErrorHandling(w, r, http.StatusBadRequest, "Lamp not found") - return - } - - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(state) - defer r.Body.Close() -} - -func setCurrent(w http.ResponseWriter, r *http.Request) { - idStr := r.PathValue("ID") - id, err := utils.IDtoInt(idStr) - if err != nil { - utils.HTTPErrorHandling(w, r, http.StatusBadRequest, err.Error()) - return - } - currentState, err := db.ViewColor(id) - if err != nil { - utils.HTTPErrorHandling(w, r, http.StatusInternalServerError, "Failed to get current lamp color") - return - } - - if time.Since(currentState.UpdatedAt).Seconds() < config.AppConfig.HTTP.Cooldown { - utils.HTTPErrorHandling(w, r, http.StatusTooManyRequests, "Slow down!") - return - } - - var req models.LampUpdateRequest - if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - logger.HTTPLogger.Print(err) - utils.HTTPErrorHandling(w, r, http.StatusBadRequest, "Invalid JSON") - return - } - - err = db.SetColor(id, req.Color) - if err != nil { - logger.HTTPLogger.Printf("Could not update lamp %d: %s", id, err) - utils.HTTPErrorHandling(w, r, http.StatusInternalServerError, err.Error()) - return - } - - updatedState := currentState - updatedState.Color = req.Color - updatedState.UpdatedAt = time.Now() - - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(updatedState) - defer r.Body.Close() -} diff --git a/cmd/internal/routes/admin.go b/cmd/internal/routes/admin.go new file mode 100644 index 0000000..0396c10 --- /dev/null +++ b/cmd/internal/routes/admin.go @@ -0,0 +1,21 @@ +package routes + +import ( + "net/http" + + "github.com/siestaw/laterna/server/cmd/internal/db" + "github.com/siestaw/laterna/server/cmd/utils" +) + +func RegisterAdminRoutes(mux *http.ServeMux) { + mux.HandleFunc("POST /api/v1/admin/controllers", createController) +} + +func createController(w http.ResponseWriter, r *http.Request) { + auth := r.Header.Get("Authorization") + if !db.IsAdmin(auth) { + utils.HTTPErrorHandling(w, r, http.StatusUnauthorized, "Invalid token") + return + } + +} diff --git a/cmd/internal/routes/user.go b/cmd/internal/routes/user.go new file mode 100644 index 0000000..7a319cd --- /dev/null +++ b/cmd/internal/routes/user.go @@ -0,0 +1,78 @@ +package routes + +import ( + "encoding/json" + "net/http" + "time" + + "github.com/siestaw/laterna/server/cmd/internal/config" + "github.com/siestaw/laterna/server/cmd/internal/db" + "github.com/siestaw/laterna/server/cmd/internal/logger" + "github.com/siestaw/laterna/server/cmd/internal/models" + "github.com/siestaw/laterna/server/cmd/utils" +) + +func RegisterUserRoutes(mux *http.ServeMux) { + mux.HandleFunc("GET /api/v1/id/{ID}", getCurrent) + mux.HandleFunc("PUT /api/v1/id/{ID}", setCurrent) +} + +func getCurrent(w http.ResponseWriter, r *http.Request) { + idStr := r.PathValue("ID") + id, err := utils.IDtoInt(idStr) + if err != nil { + utils.HTTPErrorHandling(w, r, http.StatusBadRequest, err.Error()) + return + } + + state, err := db.ViewColor(id) + if err != nil { + utils.HTTPErrorHandling(w, r, http.StatusBadRequest, "Lamp not found") + return + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(state) + defer r.Body.Close() +} + +func setCurrent(w http.ResponseWriter, r *http.Request) { + idStr := r.PathValue("ID") + id, err := utils.IDtoInt(idStr) + if err != nil { + utils.HTTPErrorHandling(w, r, http.StatusBadRequest, err.Error()) + return + } + currentState, err := db.ViewColor(id) + if err != nil { + utils.HTTPErrorHandling(w, r, http.StatusInternalServerError, "Failed to get current lamp color") + return + } + + if time.Since(currentState.UpdatedAt).Seconds() < config.AppConfig.HTTP.Cooldown { + utils.HTTPErrorHandling(w, r, http.StatusTooManyRequests, "Slow down!") + return + } + + var req models.LampUpdateRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + logger.HTTPLogger.Print(err) + utils.HTTPErrorHandling(w, r, http.StatusBadRequest, "Invalid JSON") + return + } + + err = db.SetColor(id, req.Color) + if err != nil { + logger.HTTPLogger.Printf("Could not update lamp %d: %s", id, err) + utils.HTTPErrorHandling(w, r, http.StatusInternalServerError, err.Error()) + return + } + + updatedState := currentState + updatedState.Color = req.Color + updatedState.UpdatedAt = time.Now() + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(updatedState) + defer r.Body.Close() +}