Skip to content

Commit

Permalink
fix(backend): more refactoring in backend packages
Browse files Browse the repository at this point in the history
  • Loading branch information
Björn Urban committed Oct 1, 2023
1 parent d7a0639 commit ddbac29
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 108 deletions.
24 changes: 10 additions & 14 deletions backend/cmd/kubevoyage/main.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package main

import (
"github.com/B-Urb/KubeVoyage/internal/app"
"github.com/B-Urb/KubeVoyage/internal/handlers"
"github.com/B-Urb/KubeVoyage/internal/models"
"github.com/rs/cors"
"gorm.io/gorm"
"log"
Expand All @@ -14,25 +14,22 @@ import (
var db *gorm.DB

func main() {
app, err := NewApp()
app, err := application.NewApp() // Assuming NewApp is in the same package
if err != nil {
log.Fatalf("Failed to initialize app: %v", err)
// Handle error
}

handler := handlers.NewHandler(app.DB)
app.Migrate()

handler := setupServer(app)
mux := setupServer(handler)

log.Println("Starting server on :8080")
log.Fatal(http.ListenAndServe(":8080", handler))
log.Fatal(http.ListenAndServe(":8080", mux))
}
func setupServer(app *App) http.Handler {
func setupServer(handle *handlers.Handler) http.Handler {
mux := http.NewServeMux()

// Migrate the schema
db.AutoMigrate(&models.User{}, &models.Site{}, &models.UserSite{})
//generateTestData()

handler := cors.Default().Handler(mux)

// Serve static files
Expand Down Expand Up @@ -62,19 +59,18 @@ func setupServer(app *App) http.Handler {
handlers.HandleRequests(w, r, db)
})
mux.HandleFunc("/api/register", func(w http.ResponseWriter, r *http.Request) {
handlers.HandleRegister(w, r, db)
handle.HandleRegister(w, r)
})
mux.HandleFunc("/api/login", func(w http.ResponseWriter, r *http.Request) {
handlers.HandleLogin(w, r, db)
handle.HandleLogin(w, r)
})
mux.HandleFunc("/api/authenticate", func(w http.ResponseWriter, r *http.Request) {
handlers.HandleAuthenticate(w, r, db)
handle.HandleAuthenticate(w, r)
})
mux.HandleFunc("/api/request", func(w http.ResponseWriter, r *http.Request) {
handlers.HandleRequestSite(w, r, db)
})

handler := cors.Default().Handler(mux)
return handler
}

Expand Down
1 change: 1 addition & 0 deletions backend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module github.com/B-Urb/KubeVoyage

go 1.21


require (
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/rs/cors v1.10.0
Expand Down
36 changes: 8 additions & 28 deletions backend/internal/app/app.go
Original file line number Diff line number Diff line change
@@ -1,50 +1,30 @@
package main
package application

import (
"fmt"
"github.com/B-Urb/KubeVoyage/internal/database"
"github.com/B-Urb/KubeVoyage/internal/models"
"gorm.io/gorm"
"log"
"os"
)

type App struct {
DB *gorm.DB
JWTKey []byte
BaseURL string
DB *gorm.DB
}

func NewApp() (*App, error) {
db, err := initializeDatabase()
db, err := database.InitializeDatabase()
if err != nil {
return nil, fmt.Errorf("failed to initialize database: %v", err)
}

jwtKey, err := getEnvOrError("JWT_SECRET_KEY")
if err != nil {
log.Fatalf("Error reading JWT_SECRET_KEY: %v", err)
}

baseURL, err := getEnvOrError("BASE_URL")
if err != nil {
log.Fatalf("Error reading BASE_URL: %v", err)
}

return &App{
DB: db,
JWTKey: []byte(jwtKey),
BaseURL: baseURL,
DB: db,
}, nil
}

func (app *App) Migrate() {
app.DB.AutoMigrate(&models.User{}, &models.Site{}, &models.UserSite{})
}

func getEnvOrError(key string) (string, error) {
value := os.Getenv(key)
if value == "" {
return "", fmt.Errorf("environment variable %s not set", key)
err := app.DB.AutoMigrate(models.User{}, models.Site{}, models.UserSite{})
if err != nil {
return
}
return value, nil
}
22 changes: 7 additions & 15 deletions backend/internal/database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,41 @@ package database

import (
"fmt"
"github.com/B-Urb/KubeVoyage/internal/util"
"gorm.io/driver/mysql"
"gorm.io/driver/postgres"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"os"
)

func InitializeDatabase() (*gorm.DB, error) {
// Read environment variables
dbType, err := getEnvOrError("DB_TYPE")
dbType, err := util.GetEnvOrError("DB_TYPE")
if err != nil {
return nil, err
}

dbHost, err := getEnvOrError("DB_HOST")
dbHost, err := util.GetEnvOrError("DB_HOST")
if err != nil {
return nil, err
}

dbPort, err := getEnvOrError("DB_PORT")
dbPort, err := util.GetEnvOrError("DB_PORT")
if err != nil {
return nil, err
}

dbUser, err := getEnvOrError("DB_USER")
dbUser, err := util.GetEnvOrError("DB_USER")
if err != nil {
return nil, err
}

dbPassword, err := getEnvOrError("DB_PASSWORD")
dbPassword, err := util.GetEnvOrError("DB_PASSWORD")
if err != nil {
return nil, err
}

dbName, err := getEnvOrError("DB_NAME")
dbName, err := util.GetEnvOrError("DB_NAME")
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -64,11 +64,3 @@ func InitializeDatabase() (*gorm.DB, error) {

return db, nil
}

func getEnvOrError(key string) (string, error) {
value := os.Getenv(key)
if value == "" {
return "", fmt.Errorf("Environment variable %s not set", key)
}
return value, nil
}
3 changes: 0 additions & 3 deletions backend/internal/go.mod

This file was deleted.

56 changes: 39 additions & 17 deletions backend/internal/handlers/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"errors"
"fmt"
"github.com/B-Urb/KubeVoyage/internal/models"
"github.com/B-Urb/KubeVoyage/internal/util"
"github.com/dgrijalva/jwt-go"
"golang.org/x/crypto/scrypt"
"gorm.io/gorm"
"log"
Expand All @@ -16,9 +18,26 @@ import (
"time"
)

var jwtKey = []byte("your_secret_key")
type Handler struct {
db *gorm.DB
JWTKey []byte
BaseURL string
}

func NewHandler(db *gorm.DB) *Handler {
jwtKey, err := util.GetEnvOrError("JWT_SECRET_KEY")
if err != nil {
log.Fatalf("Error reading JWT_SECRET_KEY: %v", err)
}

func (app *App) HandleLogin(w http.ResponseWriter, r *http.Request) {
baseURL, err := util.GetEnvOrError("BASE_URL")
if err != nil {
log.Fatalf("Error reading BASE_URL: %v", err)
}
return &Handler{db: db, JWTKey: []byte(jwtKey), BaseURL: baseURL}
}

func (h *Handler) HandleLogin(w http.ResponseWriter, r *http.Request) {
var inputUser models.User
var dbUser models.User

Expand All @@ -30,7 +49,7 @@ func (app *App) HandleLogin(w http.ResponseWriter, r *http.Request) {
}

// Fetch the user from the database
result := db.Where("email = ?", inputUser.Email).First(&dbUser)
result := h.db.Where("email = ?", inputUser.Email).First(&dbUser)
if result.Error != nil {
sendJSONError(w, "User not found", http.StatusNotFound)
return
Expand All @@ -54,7 +73,7 @@ func (app *App) HandleLogin(w http.ResponseWriter, r *http.Request) {
})

// Sign and get the complete encoded token as a string using the secret
tokenString, err := token.SignedString(jwtKey)
tokenString, err := token.SignedString(h.JWTKey)
if err != nil {
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
Expand All @@ -79,10 +98,13 @@ func (app *App) HandleLogin(w http.ResponseWriter, r *http.Request) {
}
// Here, you'd typically generate a JWT or session token and send it back to the client.
// For simplicity, we'll just send a success message.
w.Write([]byte("Login successful"))
_, err = w.Write([]byte("Login successful"))
if err != nil {
return
}
}

func (app *App) HandleRegister(w http.ResponseWriter, r *http.Request) {
func (h *Handler) HandleRegister(w http.ResponseWriter, r *http.Request) {
var user models.User

// Parse the request body
Expand All @@ -107,7 +129,7 @@ func (app *App) HandleRegister(w http.ResponseWriter, r *http.Request) {
}
user.Password = base64.StdEncoding.EncodeToString(hash)
var existingUser models.User
if err := db.Where("email = ?", user.Email).First(&existingUser).Error; err != nil {
if err := h.db.Where("email = ?", user.Email).First(&existingUser).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
sendJSONError(w, "Database error", http.StatusInternalServerError)
return
Expand All @@ -117,19 +139,19 @@ func (app *App) HandleRegister(w http.ResponseWriter, r *http.Request) {
return
}
// Save the user to the database
result := db.Create(&user)
result := h.db.Create(&user)
if result.Error != nil {
sendJSONError(w, result.Error.Error(), http.StatusInternalServerError)
return
}

sendJSONSuccess(w, "", http.StatusCreated)
}
func (app *App) HandleAuthenticate(w http.ResponseWriter, r *http.Request) {
func (h *Handler) HandleAuthenticate(w http.ResponseWriter, r *http.Request) {
// 1. Extract the user's email from the session or JWT token.
userEmail, err := app.getUserEmailFromToken(r)
userEmail, err := h.getUserEmailFromToken(r)
if err != nil {
app.logError(w, "Failed to get user email from token", err, http.StatusUnauthorized)
h.logError(w, "Failed to get user email from token", err, http.StatusUnauthorized)
return
}

Expand All @@ -138,14 +160,14 @@ func (app *App) HandleAuthenticate(w http.ResponseWriter, r *http.Request) {
if siteURL == "" {
siteURL = r.URL.Query().Get("redirect")
if siteURL == "" {
app.logError(w, "Redirect URL missing from both header and URL parameter", nil, http.StatusBadRequest)
h.logError(w, "Redirect URL missing from both header and URL parameter", nil, http.StatusBadRequest)
return
}
}

// 3. Query the database to check if the user has an "authorized" state for the given site.
var userSite models.UserSite
err = app.DB.Joins("JOIN users ON users.id = user_sites.user_id").
err = h.db.Joins("JOIN users ON users.id = user_sites.user_id").
Joins("JOIN sites ON sites.id = user_sites.site_id").
Where("users.email = ? AND sites.url = ? AND user_sites.state = ?", userEmail, siteURL, "authorized").
First(&userSite).Error
Expand All @@ -156,13 +178,13 @@ func (app *App) HandleAuthenticate(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/request?redirect="+url.QueryEscape(siteURL), http.StatusSeeOther)
return
}
app.logError(w, "Database error while checking user authorization", err, http.StatusInternalServerError)
h.logError(w, "Database error while checking user authorization", err, http.StatusInternalServerError)
return
}
http.Redirect(w, r, siteURL, http.StatusSeeOther)
}

func (app *App) logError(w http.ResponseWriter, message string, err error, statusCode int) {
func (h *Handler) logError(w http.ResponseWriter, message string, err error, statusCode int) {
logMessage := message
if err != nil {
logMessage = fmt.Sprintf("%s: %v", message, err)
Expand All @@ -171,7 +193,7 @@ func (app *App) logError(w http.ResponseWriter, message string, err error, statu
http.Error(w, message, statusCode)
}

func getUserEmailFromToken(r *http.Request) (string, error) {
func (h *Handler) getUserEmailFromToken(r *http.Request) (string, error) {
cookie, err := r.Cookie("auth_token")
if err != nil {
return "", fmt.Errorf("Authentication cookie missing")
Expand All @@ -181,7 +203,7 @@ func getUserEmailFromToken(r *http.Request) (string, error) {
claims := &jwt.MapClaims{}

_, err = jwt.ParseWithClaims(tokenStr, claims, func(token *jwt.Token) (interface{}, error) {
return jwtKey, nil
return h.JWTKey, nil
})

if err != nil {
Expand Down
33 changes: 33 additions & 0 deletions backend/internal/test/test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package test

//func generateTestData() {
// // Insert test data for Users
// users := []models.User{
// {Email: "[email protected]", Password: "password1", Role: "admin"},
// {Email: "[email protected]", Password: "password2", Role: "user"},
// {Email: "[email protected]", Password: "password3", Role: "user"},
// }
// for _, user := range users {
// db.Create(&user)
// }
//
// // Insert test data for Sites
// sites := []models.Site{
// {URL: "https://site1.com"},
// {URL: "https://site2.com"},
// {URL: "https://site3.com"},
// }
// for _, site := range sites {
// db.Create(&site)
// }
//
// // Insert test data for UserSite
// userSites := []models.UserSite{
// {UserID: 1, SiteID: 1, State: "authorized"},
// {UserID: 2, SiteID: 2, State: "requested"},
// {UserID: 3, SiteID: 3, State: "authorized"},
// }
// for _, userSite := range userSites {
// db.Create(&userSite)
// }
//}
Loading

0 comments on commit ddbac29

Please sign in to comment.