Compare commits

...

2 Commits

Author SHA1 Message Date
0f1c8e327e Mod permission middleware to only request database once
All checks were successful
Build Backend (NixCN CMS) TeamCity build finished
Build Frontend (NixCN CMS) TeamCity build finished
Signed-off-by: Asai Neko <sugar@sne.moe>
2026-01-06 10:40:48 +08:00
ddffb0da23 Add permission middleware
Signed-off-by: Asai Neko <sugar@sne.moe>
2026-01-06 10:36:51 +08:00
7 changed files with 64 additions and 46 deletions

View File

@@ -14,14 +14,12 @@ func JWTAuth(required bool) gin.HandlerFunc {
authtoken := new(authtoken.Token) authtoken := new(authtoken.Token)
uid, err := authtoken.HeaderVerify(auth) uid, err := authtoken.HeaderVerify(auth)
if err != nil { if err != nil {
c.JSON(401, gin.H{"status": err.Error()}) c.AbortWithStatusJSON(401, gin.H{"status": err.Error()})
c.Abort()
return return
} }
if required == true && uid == "" { if required == true && uid == "" {
c.JSON(401, gin.H{"status": "unauthorized"}) c.AbortWithStatusJSON(401, gin.H{"status": "unauthorized"})
c.Abort()
return return
} }

46
middleware/permission.go Normal file
View File

@@ -0,0 +1,46 @@
package middleware
import (
"nixcn-cms/data"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
func Permission(requiredLevel uint) gin.HandlerFunc {
return func(c *gin.Context) {
var permissionLevel uint
permissionLevelPrev, ok := c.Get("permission_level")
if !ok {
userIdOrig, ok := c.Get("user_id")
if !ok || userIdOrig.(string) == "" {
c.AbortWithStatusJSON(401, gin.H{"status": "missing user id"})
return
}
userId, err := uuid.Parse(userIdOrig.(string))
if err != nil {
c.AbortWithStatusJSON(500, gin.H{"status": "error parsing user id"})
return
}
userData, err := new(data.User).GetByUserId(userId)
if err != nil {
c.AbortWithStatusJSON(404, gin.H{"status": "user not found"})
return
}
permissionLevel = userData.PermissionLevel
c.Set("permission_level", userData.PermissionLevel)
} else {
permissionLevel = permissionLevelPrev.(uint)
}
if permissionLevel < requiredLevel {
c.AbortWithStatusJSON(403, gin.H{"status": "permission denied"})
return
}
c.Next()
}
}

View File

@@ -43,29 +43,13 @@ func Checkin(c *gin.Context) {
} }
func CheckinSubmit(c *gin.Context) { func CheckinSubmit(c *gin.Context) {
userIdOrig, ok := c.Get("user_id")
if userIdOrig.(string) == "" || !ok {
c.JSON(401, gin.H{"status": "unauthorized"})
}
userId, err := uuid.Parse(userIdOrig.(string))
if err != nil {
c.JSON(500, gin.H{"status": "failed to parse uuid"})
}
userData := new(data.User)
userData.GetByUserId(userId)
if userData.PermissionLevel <= 20 {
c.JSON(403, gin.H{"status": "access denied"})
return
}
var req struct { var req struct {
ChekinCode string `json:"checkin_code"` ChekinCode string `json:"checkin_code"`
} }
c.ShouldBindJSON(&req) c.ShouldBindJSON(&req)
attendanceData := new(data.Attendance) attendanceData := new(data.Attendance)
err = attendanceData.VerifyCheckinCode(req.ChekinCode) err := attendanceData.VerifyCheckinCode(req.ChekinCode)
if err != nil { if err != nil {
c.JSON(400, gin.H{"status": "error verify checkin code"}) c.JSON(400, gin.H{"status": "error verify checkin code"})
return return

View File

@@ -19,18 +19,12 @@ func Full(c *gin.Context) {
return return
} }
userData := new(data.User) userData, err := new(data.User).GetByUserId(userId)
user, err := userData.GetByUserId(userId)
if err != nil { if err != nil {
c.JSON(404, gin.H{"status": "user not found"}) c.JSON(404, gin.H{"status": "user not found"})
return return
} }
if user.PermissionLevel < 50 {
c.JSON(403, gin.H{"status": "permission denied"})
return
}
data, err := userData.GetFullTable() data, err := userData.GetFullTable()
if err != nil { if err != nil {
c.JSON(500, gin.H{"status": "database error"}) c.JSON(500, gin.H{"status": "database error"})

View File

@@ -7,12 +7,12 @@ import (
) )
func Handler(r *gin.RouterGroup) { func Handler(r *gin.RouterGroup) {
r.Use(middleware.JWTAuth(true)) r.Use(middleware.JWTAuth(true), middleware.Permission(10))
r.GET("/info", Info) r.GET("/info", Info)
r.GET("/checkin", Checkin) r.GET("/checkin", Checkin)
r.POST("/checkin/submit", CheckinSubmit) r.POST("/checkin/submit", CheckinSubmit, middleware.Permission(20))
r.PATCH("/update", Update) r.PATCH("/update", Update)
r.GET("/list", List) r.GET("/list", List)
r.GET("/query", Query) r.GET("/query", Query)
r.POST("/full", Full) r.POST("/full", Full, middleware.Permission(50))
} }

View File

@@ -8,8 +8,6 @@ import (
) )
func List(c *gin.Context) { func List(c *gin.Context) {
data := new(data.User)
// Get limit and offset from query // Get limit and offset from query
limit, ok := c.GetQuery("limit") limit, ok := c.GetQuery("limit")
if !ok { if !ok {
@@ -34,7 +32,7 @@ func List(c *gin.Context) {
} }
// Get user list from search engine // Get user list from search engine
list, err := data.FastListUsers(limitNum, offsetNum) list, err := new(data.User).FastListUsers(limitNum, offsetNum)
if err != nil { if err != nil {
c.JSON(500, gin.H{"status": "failed list users from meilisearch"}) c.JSON(500, gin.H{"status": "failed list users from meilisearch"})
} }

View File

@@ -10,7 +10,6 @@ import (
func Update(c *gin.Context) { func Update(c *gin.Context) {
// New user model // New user model
user := new(data.User)
userIdOrig, ok := c.Get("user_id") userIdOrig, ok := c.Get("user_id")
if !ok { if !ok {
c.JSON(403, gin.H{"status": "userid error"}) c.JSON(403, gin.H{"status": "userid error"})
@@ -19,34 +18,33 @@ func Update(c *gin.Context) {
userId, err := uuid.Parse(userIdOrig.(string)) userId, err := uuid.Parse(userIdOrig.(string))
if err != nil { if err != nil {
c.JSON(500, gin.H{"status": "failed to parse uuid"}) c.JSON(500, gin.H{"status": "failed to parse uuid"})
return
} }
var ReqInfo data.User var ReqInfo data.User
c.BindJSON(&ReqInfo) c.BindJSON(&ReqInfo)
// Get user info // Get user info
user.GetByUserId(userId) userData, err := new(data.User).GetByUserId(userId)
if err != nil {
// Reject permission 0 user c.JSON(500, gin.H{"status": "failed to find user"})
if user.PermissionLevel == 0 {
c.JSON(403, gin.H{"status": "premission denied"})
return return
} }
user.Avatar = ReqInfo.Avatar userData.Avatar = ReqInfo.Avatar
user.Email = ReqInfo.Email userData.Email = ReqInfo.Email
user.Nickname = ReqInfo.Nickname userData.Nickname = ReqInfo.Nickname
user.Subtitle = ReqInfo.Subtitle userData.Subtitle = ReqInfo.Subtitle
if ReqInfo.Bio != "" { if ReqInfo.Bio != "" {
if !cryptography.IsBase64Std(ReqInfo.Bio) { if !cryptography.IsBase64Std(ReqInfo.Bio) {
c.JSON(400, gin.H{"status": "invalid base64"}) c.JSON(400, gin.H{"status": "invalid base64"})
} }
} }
user.Bio = ReqInfo.Bio userData.Bio = ReqInfo.Bio
// Update user info // Update user info
user.UpdateByUserID(userId) userData.UpdateByUserID(userId)
c.JSON(200, gin.H{"status": "success"}) c.JSON(200, gin.H{"status": "success"})
} }