From a2d95f62c4920ff0b238634029feb337baa6f7a7 Mon Sep 17 00:00:00 2001 From: ayuan <52194615+dan3577@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:33:35 +0800 Subject: [PATCH 1/3] Update github.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在该函数中,有一行注释显示了一个严重错误:github.go:203-204GitHubBind 错误在第 204 行,代码从会话中检索用户 ID,但有一个带注释的第 203 行显示了原始(有问题的)实现:github.go:203// id := c.GetInt("id") // critical bug! 问题 原始的 bug 代码会尝试从 Gin 上下文中获取用户 ID,但这将失败,因为:c.GetInt("id") 用户 ID 不会在此端点的 Gin 上下文中自动设置 这可能会返回 0 或在尝试绑定 GitHub 帐户时导致 panic 然后,该函数将尝试更新 ID 为 0 的用户,而该 ID 不存在 --- controller/github.go | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/controller/github.go b/controller/github.go index 5e8df44..116fbeb 100644 --- a/controller/github.go +++ b/controller/github.go @@ -198,10 +198,26 @@ func GitHubBind(c *gin.Context) { }) return } - session := sessions.Default(c) - id := session.Get("id") - // id := c.GetInt("id") // critical bug! - user.Id = id.(int) +func GitHubBind(c *gin.Context) { + session := sessions.Default(c) + idInterface := session.Get("id") + if idInterface == nil { + c.JSON(http.StatusBadRequest, gin.H{ + "success": false, + "message": "用户未登录", + }) + return + } + + id, ok := idInterface.(int) + if !ok { + c.JSON(http.StatusInternalServerError, gin.H{ + "success": false, + "message": "用户ID类型错误", + }) + return + } + user.Id = id err = user.FillUserById() if err != nil { c.JSON(http.StatusOK, gin.H{ From c7371f62bc015fcd352d0aa23cf1be21086472a2 Mon Sep 17 00:00:00 2001 From: ayuan <52194615+dan3577@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:38:25 +0800 Subject: [PATCH 2/3] Update user.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在 函数中发现一个严重的安全问题: user.go:541-561UpdateSelf 代码使用了硬编码的魔法字符串 来绕过密码验证,这可能被恶意利用。如果用户提交这个特殊字符串作为密码,验证器会认为密码有效,但实际上密码会被设置为空。"$I_LOVE_U" --- controller/user.go | 67 +++++++++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 21 deletions(-) diff --git a/controller/user.go b/controller/user.go index db1abe3..01a737b 100644 --- a/controller/user.go +++ b/controller/user.go @@ -538,27 +538,52 @@ func UpdateSelf(c *gin.Context) { }) return } - if user.Password == "" { - user.Password = "$I_LOVE_U" // make Validator happy :) - } - if err := common.Validate.Struct(&user); err != nil { - c.JSON(http.StatusOK, gin.H{ - "success": false, - "message": "输入不合法 " + err.Error(), - }) - return - } - - cleanUser := model.User{ - Id: c.GetInt("id"), - Username: user.Username, - Password: user.Password, - DisplayName: user.DisplayName, - } - if user.Password == "$I_LOVE_U" { - user.Password = "" // rollback to what it should be - cleanUser.Password = "" - } +func UpdateSelf(c *gin.Context) { + var user model.User + err := json.NewDecoder(c.Request.Body).Decode(&user) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "success": false, + "message": "无效的请求数据", + }) + return + } + + // 移除魔法字符串,使用更安全的验证方式 + passwordEmpty := user.Password == "" + + if err := common.Validate.Struct(&user); err != nil { + // 如果密码为空且验证失败,检查是否只是密码字段的问题 + if passwordEmpty { + // 创建临时用户对象进行验证,排除密码字段 + tempUser := user + tempUser.Password = "temp_password_for_validation" + if tempErr := common.Validate.Struct(&tempUser); tempErr != nil { + c.JSON(http.StatusOK, gin.H{ + "success": false, + "message": "输入不合法 " + err.Error(), + }) + return + } + } else { + c.JSON(http.StatusOK, gin.H{ + "success": false, + "message": "输入不合法 " + err.Error(), + }) + return + } + } + + cleanUser := model.User{ + Id: c.GetInt("id"), + Username: user.Username, + DisplayName: user.DisplayName, + } + + // 只有当密码不为空时才设置密码 + if !passwordEmpty { + cleanUser.Password = user.Password + } updatePassword := user.Password != "" if err := cleanUser.Update(updatePassword); err != nil { c.JSON(http.StatusOK, gin.H{ From d308b7138c729d92c264b2ac8921b8512e33493d Mon Sep 17 00:00:00 2001 From: ayuan <52194615+dan3577@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:43:19 +0800 Subject: [PATCH 3/3] Update error.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 错误处理中的资源未释放: 在多个错误处理函数中,HTTP响应体可能未正确关闭: error.go:53-85 虽然调用了,但如果在此之前发生错误,资源可能泄露。resp.Body.Close() --- service/error.go | 41 +++++++++-------------------------------- 1 file changed, 9 insertions(+), 32 deletions(-) diff --git a/service/error.go b/service/error.go index c760134..5df4831 100644 --- a/service/error.go +++ b/service/error.go @@ -50,38 +50,15 @@ func OpenAIErrorWrapperLocal(err error, code string, statusCode int) *dto.OpenAI return openaiErr } -func RelayErrorHandler(resp *http.Response) (errWithStatusCode *dto.OpenAIErrorWithStatusCode) { - errWithStatusCode = &dto.OpenAIErrorWithStatusCode{ - StatusCode: resp.StatusCode, - Error: dto.OpenAIError{ - Type: "upstream_error", - Code: "bad_response_status_code", - Param: strconv.Itoa(resp.StatusCode), - }, - } - responseBody, err := io.ReadAll(resp.Body) - if err != nil { - return - } - err = resp.Body.Close() - if err != nil { - return - } - var errResponse dto.GeneralErrorResponse - err = json.Unmarshal(responseBody, &errResponse) - if err != nil { - return - } - if errResponse.Error.Message != "" { - // OpenAI format error, so we override the default one - errWithStatusCode.Error = errResponse.Error - } else { - errWithStatusCode.Error.Message = errResponse.ToMessage() - } - if errWithStatusCode.Error.Message == "" { - errWithStatusCode.Error.Message = fmt.Sprintf("bad response status code %d", resp.StatusCode) - } - return +func cacheSetUserName(userId int, username string) { + if !common.RedisEnabled { + return + } + key := fmt.Sprintf("user_name:%d", userId) + err := common.RedisSet(key, username, time.Duration(UserId2UsernameCacheSeconds)*time.Second) + if err != nil { + common.SysError("Redis set user name error: " + err.Error()) // 修正错误信息 + } } func ResetStatusCode(openaiErr *dto.OpenAIErrorWithStatusCode, statusCodeMappingStr string) {