package server import ( "database/sql" "fmt" "net/http" "os" "strings" "time" "github.com/gin-gonic/gin" "github.com/google/uuid" "golang.org/x/crypto/bcrypt" "gophergate/internal/db" "gophergate/internal/models" "gophergate/internal/utils" "log/slog" "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/disk" "github.com/shirou/gopsutil/v3/load" "github.com/shirou/gopsutil/v3/mem" "github.com/shirou/gopsutil/v3/process" ) type ApiResponse struct { Success bool `json:"success"` Data interface{} `json:"data,omitempty"` Error string `json:"error,omitempty"` } func SuccessResponse(data interface{}) ApiResponse { return ApiResponse{Success: true, Data: data} } func ErrorResponse(err string) ApiResponse { return ApiResponse{Success: false, Error: err} } func (s *Server) adminAuthMiddleware() gin.HandlerFunc { return func(c *gin.Context) { token := strings.TrimPrefix(c.GetHeader("Authorization"), "Bearer ") if token == "" { c.AbortWithStatusJSON(http.StatusUnauthorized, ErrorResponse("Not authenticated")) return } session, _, err := s.sessions.ValidateSession(token) if err != nil { c.AbortWithStatusJSON(http.StatusUnauthorized, ErrorResponse("Session expired or invalid")) return } if session.Role != "admin" { c.AbortWithStatusJSON(http.StatusForbidden, ErrorResponse("Admin access required")) return } c.Set("session", session) c.Next() } } type LoginRequest struct { Username string `json:"username" binding:"required"` Password string `json:"password" binding:"required"` } func (s *Server) handleLogin(c *gin.Context) { var req LoginRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, ErrorResponse("Invalid request")) return } var user db.User err := s.database.Get(&user, "SELECT username, password_hash, display_name, role, must_change_password FROM users WHERE username = ?", req.Username) if err != nil { c.JSON(http.StatusUnauthorized, ErrorResponse("Invalid username or password")) return } if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(req.Password)); err != nil { c.JSON(http.StatusUnauthorized, ErrorResponse("Invalid username or password")) return } displayName := user.Username if user.DisplayName != nil { displayName = *user.DisplayName } token, err := s.sessions.CreateSession(user.Username, displayName, user.Role) if err != nil { c.JSON(http.StatusInternalServerError, ErrorResponse("Failed to create session")) return } c.JSON(http.StatusOK, SuccessResponse(gin.H{ "token": token, "must_change_password": user.MustChangePassword, "user": user, })) } func (s *Server) handleAuthStatus(c *gin.Context) { token := strings.TrimPrefix(c.GetHeader("Authorization"), "Bearer ") session, _, err := s.sessions.ValidateSession(token) if err != nil { c.JSON(http.StatusUnauthorized, ErrorResponse("Not authenticated")) return } c.JSON(http.StatusOK, SuccessResponse(gin.H{ "authenticated": true, "user": gin.H{ "username": session.Username, "role": session.Role, "display_name": session.DisplayName, }, })) } type ChangePasswordRequest struct { CurrentPassword string `json:"current_password" binding:"required"` NewPassword string `json:"new_password" binding:"required"` } func (s *Server) handleChangePassword(c *gin.Context) { token := strings.TrimPrefix(c.GetHeader("Authorization"), "Bearer ") session, _, err := s.sessions.ValidateSession(token) if err != nil { c.JSON(http.StatusUnauthorized, ErrorResponse("Not authenticated")) return } var req ChangePasswordRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, ErrorResponse("Invalid request")) return } var user db.User err = s.database.Get(&user, "SELECT password_hash FROM users WHERE username = ?", session.Username) if err != nil { c.JSON(http.StatusInternalServerError, ErrorResponse("User not found")) return } if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(req.CurrentPassword)); err != nil { c.JSON(http.StatusUnauthorized, ErrorResponse("Current password incorrect")) return } newHash, err := bcrypt.GenerateFromPassword([]byte(req.NewPassword), 12) if err != nil { c.JSON(http.StatusInternalServerError, ErrorResponse("Failed to hash new password")) return } _, err = s.database.Exec("UPDATE users SET password_hash = ?, must_change_password = 0 WHERE username = ?", string(newHash), session.Username) if err != nil { c.JSON(http.StatusInternalServerError, ErrorResponse("Failed to update password")) return } c.JSON(http.StatusOK, SuccessResponse(gin.H{"message": "Password updated successfully"})) } func (s *Server) handleLogout(c *gin.Context) { token := strings.TrimPrefix(c.GetHeader("Authorization"), "Bearer ") if err := s.sessions.RevokeSession(token); err != nil { fmt.Printf("Error revoking session: %v\n", err) } c.JSON(http.StatusOK, SuccessResponse(gin.H{"message": "Logged out"})) }