Rework admin console authentication and UI
This commit is contained in:
@@ -22,6 +22,64 @@ func BindAdminDependencies(rtmpSrv *stream.RTMPServer) {
|
||||
adminRTMP = rtmpSrv
|
||||
}
|
||||
|
||||
func AdminLogin(c *gin.Context) {
|
||||
var req LoginRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
var user model.User
|
||||
if err := db.DB.Where("username = ?", strings.TrimSpace(req.Username)).First(&user).Error; err != nil {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid username or password"})
|
||||
return
|
||||
}
|
||||
|
||||
if !utils.CheckPasswordHash(req.Password, user.Password) {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid username or password"})
|
||||
return
|
||||
}
|
||||
|
||||
if !user.Enabled {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "Account is disabled"})
|
||||
return
|
||||
}
|
||||
|
||||
if user.Role != "admin" {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "Admin access required"})
|
||||
return
|
||||
}
|
||||
|
||||
token, err := utils.GenerateToken(user.ID, user.Username, user.Role)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create admin session"})
|
||||
return
|
||||
}
|
||||
|
||||
c.SetCookie(adminSessionCookieName, token, 86400, "/", "", false, true)
|
||||
monitor.Auditf("admin=%s signed in", user.Username)
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"username": user.Username,
|
||||
"role": user.Role,
|
||||
})
|
||||
}
|
||||
|
||||
func AdminLogout(c *gin.Context) {
|
||||
operator, _ := c.Get("username")
|
||||
c.SetCookie(adminSessionCookieName, "", -1, "/", "", false, true)
|
||||
monitor.Auditf("admin=%v signed out", operator)
|
||||
c.JSON(http.StatusOK, gin.H{"message": "signed out"})
|
||||
}
|
||||
|
||||
func GetAdminSession(c *gin.Context) {
|
||||
username, _ := c.Get("username")
|
||||
role, _ := c.Get("role")
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"username": username,
|
||||
"role": role,
|
||||
})
|
||||
}
|
||||
|
||||
func GetAdminOverview(c *gin.Context) {
|
||||
stats := monitor.GetSnapshot()
|
||||
chatStats := chat.StatsSnapshot{}
|
||||
@@ -83,10 +141,6 @@ func ListAdminLogs(c *gin.Context) {
|
||||
}
|
||||
|
||||
func StreamAdminLogs(c *gin.Context) {
|
||||
if !authorizeAdminTokenFromQuery(c) {
|
||||
return
|
||||
}
|
||||
|
||||
c.Header("Content-Type", "text/event-stream")
|
||||
c.Header("Cache-Control", "no-cache")
|
||||
c.Header("Connection", "keep-alive")
|
||||
@@ -114,39 +168,6 @@ func StreamAdminLogs(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func authorizeAdminTokenFromQuery(c *gin.Context) bool {
|
||||
token := strings.TrimSpace(c.Query("token"))
|
||||
if token == "" {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "token is required"})
|
||||
return false
|
||||
}
|
||||
|
||||
claims, err := utils.ParseToken(token)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid token"})
|
||||
return false
|
||||
}
|
||||
|
||||
userID, err := strconv.ParseUint(claims.Subject, 10, 32)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid token subject"})
|
||||
return false
|
||||
}
|
||||
|
||||
var user model.User
|
||||
if err := db.DB.First(&user, uint(userID)).Error; err != nil {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "user not found"})
|
||||
return false
|
||||
}
|
||||
|
||||
if !user.Enabled || user.Role != "admin" {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "admin access required"})
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
type updateRoleRequest struct {
|
||||
Role string `json:"role" binding:"required"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user