From f35e63e3f314b57231380cbd35e7efa33266be7c Mon Sep 17 00:00:00 2001 From: wozulong <> Date: Wed, 20 Mar 2024 16:54:38 +0800 Subject: [PATCH] limit 'LINUX DO' trust level now available Signed-off-by: wozulong <> --- .github/workflows/docker-image-amd64.yml | 2 +- .github/workflows/docker-image-arm64.yml | 2 +- common/constants.go | 1 + controller/linuxdo.go | 20 ++++++++++++++++++-- controller/misc.go | 1 + controller/user.go | 1 + middleware/auth.go | 19 +++++++++++++++++++ model/cache.go | 24 ++++++++++++++++++++++++ model/option.go | 3 +++ model/user.go | 13 +++++++++++++ web/src/components/PersonalSetting.js | 2 +- web/src/components/SystemSetting.js | 15 +++++++++++++++ web/src/pages/User/EditUser.js | 6 ++++-- 13 files changed, 102 insertions(+), 7 deletions(-) diff --git a/.github/workflows/docker-image-amd64.yml b/.github/workflows/docker-image-amd64.yml index 5abd780..103380e 100644 --- a/.github/workflows/docker-image-amd64.yml +++ b/.github/workflows/docker-image-amd64.yml @@ -43,7 +43,7 @@ jobs: uses: docker/metadata-action@v4 with: images: | - linux-do/new-api + pengzhile/new-api ghcr.io/${{ github.repository }} - name: Build and push Docker images diff --git a/.github/workflows/docker-image-arm64.yml b/.github/workflows/docker-image-arm64.yml index 8c9a0b2..8873f01 100644 --- a/.github/workflows/docker-image-arm64.yml +++ b/.github/workflows/docker-image-arm64.yml @@ -49,7 +49,7 @@ jobs: uses: docker/metadata-action@v4 with: images: | - linux-do/new-api + pengzhile/new-api ghcr.io/${{ github.repository }} - name: Build and push Docker images diff --git a/common/constants.go b/common/constants.go index 2c5e43a..a702126 100644 --- a/common/constants.go +++ b/common/constants.go @@ -85,6 +85,7 @@ var GitHubClientSecret = "" var LinuxDoClientId = "" var LinuxDoClientSecret = "" +var LinuxDoMinLevel = 0 var WeChatServerAddress = "" var WeChatServerToken = "" diff --git a/controller/linuxdo.go b/controller/linuxdo.go index de4c982..768ad93 100644 --- a/controller/linuxdo.go +++ b/controller/linuxdo.go @@ -80,6 +80,9 @@ func getLinuxDoUserInfoByCode(code string) (*LinuxDoUser, error) { if linuxdoUser.ID == 0 { return nil, errors.New("返回值非法,用户字段为空,请稍后重试!") } + if linuxdoUser.TrustLevel < common.LinuxDoMinLevel { + return nil, errors.New("用户 LINUX DO 信任等级不足!") + } return &linuxdoUser, nil } @@ -116,7 +119,8 @@ func LinuxDoOAuth(c *gin.Context) { return } user := model.User{ - LinuxDoId: strconv.Itoa(linuxdoUser.ID), + LinuxDoId: strconv.Itoa(linuxdoUser.ID), + LinuxDoLevel: linuxdoUser.TrustLevel, } if model.IsLinuxDoIdAlreadyTaken(user.LinuxDoId) { err := user.FillUserByLinuxDoId() @@ -127,6 +131,16 @@ func LinuxDoOAuth(c *gin.Context) { }) return } + + user.LinuxDoLevel = linuxdoUser.TrustLevel + err = user.Update(false) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "success": false, + "message": err.Error(), + }) + return + } } else { if common.RegisterEnabled { affCode := c.Query("aff") @@ -185,7 +199,8 @@ func LinuxDoBind(c *gin.Context) { return } user := model.User{ - LinuxDoId: strconv.Itoa(linuxdoUser.ID), + LinuxDoId: strconv.Itoa(linuxdoUser.ID), + LinuxDoLevel: linuxdoUser.TrustLevel, } if model.IsLinuxDoIdAlreadyTaken(user.LinuxDoId) { c.JSON(http.StatusOK, gin.H{ @@ -207,6 +222,7 @@ func LinuxDoBind(c *gin.Context) { return } user.LinuxDoId = strconv.Itoa(linuxdoUser.ID) + user.LinuxDoLevel = linuxdoUser.TrustLevel err = user.Update(false) if err != nil { c.JSON(http.StatusOK, gin.H{ diff --git a/controller/misc.go b/controller/misc.go index fc524a9..bf72a36 100644 --- a/controller/misc.go +++ b/controller/misc.go @@ -63,6 +63,7 @@ func GetStatus(c *gin.Context) { "default_collapse_sidebar": common.DefaultCollapseSidebar, "enable_online_topup": common.PayAddress != "" && common.EpayId != "" && common.EpayKey != "", "mj_notify_enabled": constant.MjNotifyEnabled, + "version": common.Version, }, }) return diff --git a/controller/user.go b/controller/user.go index d3b1371..b002855 100644 --- a/controller/user.go +++ b/controller/user.go @@ -65,6 +65,7 @@ func setupLogin(user *model.User, c *gin.Context) { session.Set("username", user.Username) session.Set("role", user.Role) session.Set("status", user.Status) + session.Set("linuxdo_enable", user.LinuxDoId == "" || user.LinuxDoLevel >= common.LinuxDoMinLevel) err := session.Save() if err != nil { c.JSON(http.StatusOK, gin.H{ diff --git a/middleware/auth.go b/middleware/auth.go index 4b865c2..fc6098d 100644 --- a/middleware/auth.go +++ b/middleware/auth.go @@ -15,6 +15,7 @@ func authHelper(c *gin.Context, minRole int) { role := session.Get("role") id := session.Get("id") status := session.Get("status") + linuxDoEnable := session.Get("linuxdo_enable") if username == nil { // Check access token accessToken := c.Request.Header.Get("Authorization") @@ -33,6 +34,7 @@ func authHelper(c *gin.Context, minRole int) { role = user.Role id = user.Id status = user.Status + linuxDoEnable = user.LinuxDoId == "" || user.LinuxDoLevel >= common.LinuxDoMinLevel } else { c.JSON(http.StatusOK, gin.H{ "success": false, @@ -50,6 +52,14 @@ func authHelper(c *gin.Context, minRole int) { c.Abort() return } + if nil != linuxDoEnable && !linuxDoEnable.(bool) { + c.JSON(http.StatusOK, gin.H{ + "success": false, + "message": "用户 LINUX DO 信任等级不足", + }) + c.Abort() + return + } if role.(int) < minRole { c.JSON(http.StatusOK, gin.H{ "success": false, @@ -112,6 +122,15 @@ func TokenAuth() func(c *gin.Context) { abortWithOpenAiMessage(c, http.StatusForbidden, "用户已被封禁") return } + linuxDoEnabled, err := model.CacheIsLinuxDoEnabled(token.UserId) + if err != nil { + abortWithOpenAiMessage(c, http.StatusInternalServerError, err.Error()) + return + } + if !linuxDoEnabled { + abortWithOpenAiMessage(c, http.StatusForbidden, "用户 LINUX DO 信任等级不足") + return + } c.Set("id", token.UserId) c.Set("token_id", token.Id) c.Set("token_name", token.Name) diff --git a/model/cache.go b/model/cache.go index 8294e73..a0449bc 100644 --- a/model/cache.go +++ b/model/cache.go @@ -204,6 +204,30 @@ func CacheIsUserEnabled(userId int) (bool, error) { return userEnabled, err } +func CacheIsLinuxDoEnabled(userId int) (bool, error) { + if !common.RedisEnabled { + return IsLinuxDoEnabled(userId) + } + enabled, err := common.RedisGet(fmt.Sprintf("linuxdo_enabled:%d", userId)) + if err == nil { + return enabled == "1", nil + } + + linuxDoEnabled, err := IsLinuxDoEnabled(userId) + if err != nil { + return false, err + } + enabled = "0" + if linuxDoEnabled { + enabled = "1" + } + err = common.RedisSet(fmt.Sprintf("linuxdo_enabled:%d", userId), enabled, time.Duration(UserId2StatusCacheSeconds)*time.Second) + if err != nil { + common.SysError("Redis set linuxdo enabled error: " + err.Error()) + } + return linuxDoEnabled, err +} + var group2model2channels map[string]map[string][]*Channel var channelsIDM map[int]*Channel var channelSyncLock sync.RWMutex diff --git a/model/option.go b/model/option.go index faea053..746794a 100644 --- a/model/option.go +++ b/model/option.go @@ -69,6 +69,7 @@ func InitOptionMap() { common.OptionMap["GitHubClientSecret"] = "" common.OptionMap["LinuxDoClientId"] = "" common.OptionMap["LinuxDoClientSecret"] = "" + common.OptionMap["LinuxDoMinLevel"] = strconv.Itoa(common.LinuxDoMinLevel) common.OptionMap["TelegramBotToken"] = "" common.OptionMap["TelegramBotName"] = "" common.OptionMap["WeChatServerAddress"] = "" @@ -230,6 +231,8 @@ func updateOptionMap(key string, value string) (err error) { common.LinuxDoClientId = value case "LinuxDoClientSecret": common.LinuxDoClientSecret = value + case "LinuxDoMinLevel": + common.LinuxDoMinLevel, _ = strconv.Atoi(value) case "Footer": common.Footer = value case "SystemName": diff --git a/model/user.go b/model/user.go index 9c9d42e..36c0962 100644 --- a/model/user.go +++ b/model/user.go @@ -22,6 +22,7 @@ type User struct { Email string `json:"email" gorm:"index" validate:"max=50"` GitHubId string `json:"github_id" gorm:"column:github_id;index"` LinuxDoId string `json:"linuxdo_id" gorm:"column:linuxdo_id;index"` + LinuxDoLevel int `json:"linuxdo_level" gorm:"column:linuxdo_level;type:int;default:0"` WeChatId string `json:"wechat_id" gorm:"column:wechat_id;index"` TelegramId string `json:"telegram_id" gorm:"column:telegram_id;index"` VerificationCode string `json:"verification_code" gorm:"-:all"` // this field is only for Email verification, don't save it to database! @@ -369,6 +370,18 @@ func IsUserEnabled(userId int) (bool, error) { return user.Status == common.UserStatusEnabled, nil } +func IsLinuxDoEnabled(userId int) (bool, error) { + if userId == 0 { + return false, errors.New("user id is empty") + } + var user User + err := DB.Where("id = ?", userId).Select("linuxdo_id, linuxdo_level").Find(&user).Error + if err != nil { + return false, err + } + return user.LinuxDoId == "" || user.LinuxDoLevel >= common.LinuxDoMinLevel, nil +} + func ValidateAccessToken(token string) (user *User) { if token == "" { return nil diff --git a/web/src/components/PersonalSetting.js b/web/src/components/PersonalSetting.js index 3635200..642bc91 100644 --- a/web/src/components/PersonalSetting.js +++ b/web/src/components/PersonalSetting.js @@ -454,7 +454,7 @@ const PersonalSetting = () => {