Files
llama-link/internal/api/handlers/admin/login.go
T
darroyo de5f7ca4ee
CI / test (push) Failing after 12m28s
Cleanup: remove dead auth middleware and fix security log leak
- Remove dead AdminOnly() and AdminTokenAuth() middleware (unused since JWT switch)
- Remove dead RequireScope() middleware (also unused)
- Fix seed.go: only log password when auto-generated (was logging every time)
- Fix seed.go: use admin.Username (normalized) instead of raw username in log
- Simplify generateRandomPassword: 12 bytes (24 hex chars) instead of 24 bytes then truncate
- Me handler: use claims.Subject (UUID) for lookup instead of username
- Remove unused /logout endpoint (stateless JWT)
2026-07-31 17:26:31 -04:00

70 lines
1.9 KiB
Go

package admin
import (
"net/http"
"time"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"github.com/llamalink/llamalink/internal/auth"
"github.com/llamalink/llamalink/internal/db"
)
type LoginHandler struct {
db *gorm.DB
jwtService *auth.AdminJWTService
}
func NewLoginHandler(db *gorm.DB, jwtService *auth.AdminJWTService) *LoginHandler {
return &LoginHandler{db: db, jwtService: jwtService}
}
type LoginRequest struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required,min=8"`
}
func (h *LoginHandler) Login(c *gin.Context) {
var req LoginRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": gin.H{"code": "validation_error", "message": "username and password are required (password min 8 chars)"}})
return
}
var user db.AdminUser
if err := h.db.Where("username = ?", req.Username).First(&user).Error; err != nil {
if err == gorm.ErrRecordNotFound {
c.JSON(http.StatusUnauthorized, gin.H{"error": gin.H{"code": "invalid_credentials", "message": "Invalid username or password"}})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": gin.H{"code": "internal_error", "message": "Internal server error"}})
return
}
if err := auth.ValidateAdminPassword(&user, req.Password); err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": gin.H{"code": "invalid_credentials", "message": "Invalid username or password"}})
return
}
token, expiresAt, err := h.jwtService.IssueToken(&user)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": gin.H{"code": "internal_error", "message": "Failed to issue session token"}})
return
}
h.db.Model(&user).Update("last_login_at", time.Now())
c.JSON(http.StatusOK, gin.H{
"token": token,
"expires_at": expiresAt.Unix(),
"user": gin.H{
"id": user.ID,
"username": user.Username,
"is_active": user.IsActive,
},
})
}