package handlers import ( "errors" "net/http" "strings" "gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/repository" "github.com/gin-gonic/gin" ) // AuthGroup handles authentication routes. type AuthGroup struct { *Handlers } // Login authenticates a user by login and password, returns a token. // @Summary Login // @Description Authenticate with login and password, returns a token and permissions // @Tags auth // @Accept json // @Param request body repository.LoginRequest true "Login credentials" // @Success 200 {object} repository.LoginResponse // @Failure 400 {object} map[string]string // @Failure 401 {object} map[string]string // @Router /auth/login [post] func (ag *AuthGroup) Login(c *gin.Context) { var req repository.LoginRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"}) return } resp, err := ag.Repo.Login(req.Login, req.Password) if err != nil { if errors.Is(err, repository.ErrNotFound) { c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid credentials"}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to authenticate"}) return } c.JSON(http.StatusOK, resp) } // CreateToken creates a new user. // @Summary Create user // @Description Creates a new user with permissions // @Tags auth // @Accept json // @Param request body repository.TokenCreate true "User data" // @Success 200 {object} map[string]string // @Failure 400 {object} map[string]string // @Failure 401 {object} map[string]string // @Failure 500 {object} map[string]string // @Router /auth/token [post] func (ag *AuthGroup) CreateToken(c *gin.Context) { var tc repository.TokenCreate if err := c.ShouldBindJSON(&tc); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"}) return } if _, err := ag.Repo.CreateToken(tc); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create user"}) return } c.JSON(http.StatusOK, gin.H{"message": "user created"}) } // ValidateToken validates the current Bearer token and returns user info. // @Summary Validate token // @Description Check if the provided Bearer token is valid and return its permissions // @Tags auth // @Produce json // @Success 200 {object} repository.Tokens // @Failure 401 {object} map[string]string // @Router /auth/validate [get] func (ag *AuthGroup) ValidateToken(c *gin.Context) { tokenVal, exists := c.Get(string(tokenContextKey)) if !exists { c.JSON(http.StatusUnauthorized, gin.H{"error": "not authenticated"}) return } token, ok := tokenVal.(*repository.Tokens) if !ok { c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid token context"}) return } c.JSON(http.StatusOK, token) } // ListTokens returns all users. // @Summary List users // @Description Returns list of all users with their permissions // @Tags auth // @Produce json // @Success 200 {array} repository.Tokens // @Failure 500 {object} map[string]string // @Router /auth/tokens [get] func (ag *AuthGroup) ListTokens(c *gin.Context) { tokens, err := ag.Repo.ListTokens() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list users"}) return } c.JSON(http.StatusOK, tokens) } // DeleteToken deletes a user by login from URL path. // @Summary Delete user // @Description Deletes a user by their login // @Tags auth // @Param login path string true "Login of the user to delete" // @Success 200 {object} map[string]string // @Failure 400 {object} map[string]string // @Failure 500 {object} map[string]string // @Router /auth/tokens/:login [delete] func (ag *AuthGroup) DeleteToken(c *gin.Context) { login := c.Param("login") if login == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "login required"}) return } if err := ag.Repo.DeleteTokenByLogin(login); err != nil { if errors.Is(err, repository.ErrNotFound) { c.JSON(http.StatusNotFound, gin.H{"error": "user not found"}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete user"}) return } c.JSON(http.StatusOK, gin.H{"message": "user deleted"}) } // DeleteMyToken deletes the current user's account. // @Summary Delete my account // @Description Deletes the current authenticated user // @Tags auth // @Success 200 {object} map[string]string // @Failure 401 {object} map[string]string // @Failure 500 {object} map[string]string // @Router /auth/token [delete] func (ag *AuthGroup) DeleteMyToken(c *gin.Context) { tokenVal, exists := c.Get(string(tokenContextKey)) if !exists { c.JSON(http.StatusUnauthorized, gin.H{"error": "not authenticated"}) return } token, ok := tokenVal.(*repository.Tokens) if !ok { c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid token context"}) return } if err := ag.Repo.DeleteToken(token.Token); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete account"}) return } c.JSON(http.StatusOK, gin.H{"message": "account deleted"}) } // getTokenFromHeader extracts the Bearer token from the Authorization header. func getTokenFromHeader(c *gin.Context) string { auth := c.GetHeader("Authorization") if auth == "" { return "" } parts := strings.SplitN(auth, " ", 2) if len(parts) != 2 || !strings.EqualFold(parts[0], "bearer") { return "" } return parts[1] }