b8788c239e
MCP Docker / build-and-push (push) Has been cancelled
- Remove telemetry: disabled all phone-home (installation notify, false positives, behavior tracking, upgrade tips) - Version branding: removed 'ce-' prefix, product name changed to '长亭雷池 WAF' - Detection engine enhancement: strict preset enables all 17 modules with aggressive configs - Multi-user RBAC: admin/operator/viewer roles with password + TOTP 2FA - Rate limiting: nginx limit_req per website (RPS, burst, action) - JS Challenge: browser fingerprint verification page with cookie-based bypass - Security fixes: removed InsecureSkipVerify, hardcoded credentials, NO_AUTH backdoor
94 lines
2.4 KiB
Go
94 lines
2.4 KiB
Go
package middleware
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/gin-contrib/sessions"
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"chaitin.cn/patronus/safeline-2/management/webserver/api/response"
|
|
"chaitin.cn/patronus/safeline-2/management/webserver/model"
|
|
"chaitin.cn/patronus/safeline-2/management/webserver/pkg/constants"
|
|
"chaitin.cn/patronus/safeline-2/management/webserver/pkg/database"
|
|
)
|
|
|
|
func AuthRequired(c *gin.Context) {
|
|
session := sessions.Default(c)
|
|
|
|
user := session.Get(constants.DefaultSessionUserKey)
|
|
if user == nil {
|
|
response.Error(c, response.ErrorLoginRequired, http.StatusUnauthorized)
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
// Load user from database to get current role/status
|
|
db := database.GetDB()
|
|
var userModel model.User
|
|
res := db.First(&userModel, user)
|
|
if res.RowsAffected == 0 {
|
|
response.Error(c, response.ErrorLoginRequired, http.StatusUnauthorized)
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
// Check if user is still enabled
|
|
if !userModel.IsEnabled {
|
|
session.Clear()
|
|
session.Save()
|
|
response.Error(c, response.JSONBody{Err: "account_disabled", Msg: "Account has been disabled"}, http.StatusForbidden)
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
// Store user info in context for downstream handlers
|
|
c.Set("user_id", int(userModel.ID))
|
|
c.Set("user_role", userModel.Role)
|
|
c.Set("username", userModel.Username)
|
|
|
|
// extend session expired time
|
|
session.Options(sessions.Options{
|
|
Path: "/",
|
|
MaxAge: 3600 * 24 * 7,
|
|
})
|
|
|
|
if err := session.Save(); err != nil {
|
|
response.Error(c, response.JSONBody{Err: response.ErrInternalError, Msg: "Error occurred when creating sessions"}, http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
c.Next()
|
|
}
|
|
|
|
// RequireRole returns a middleware that checks if the user has one of the required roles.
|
|
func RequireRole(roles ...string) gin.HandlerFunc {
|
|
roleSet := make(map[string]bool)
|
|
for _, r := range roles {
|
|
roleSet[r] = true
|
|
}
|
|
return func(c *gin.Context) {
|
|
userRole, exists := c.Get("user_role")
|
|
if !exists {
|
|
response.Error(c, response.ErrorLoginRequired, http.StatusUnauthorized)
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
role, ok := userRole.(string)
|
|
if !ok || !roleSet[role] {
|
|
response.Error(c, response.JSONBody{Err: "forbidden", Msg: "Insufficient permissions"}, http.StatusForbidden)
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
c.Next()
|
|
}
|
|
}
|
|
|
|
func ReadOnly(c *gin.Context) {
|
|
if c.Request.Method != "GET" && c.Request.Method != "HEAD" && c.Request.Method != "OPTIONS" {
|
|
response.Error(c, response.ErrorReadOnly, http.StatusBadRequest)
|
|
c.Abort()
|
|
}
|
|
}
|