This commit refactors the logging mechanism across the application by replacing direct logger calls with a centralized logging approach using the `common` package. Key changes include: - Replaced instances of `logger.SysLog` and `logger.FatalLog` with `common.SysLog` and `common.FatalLog` for consistent logging practices. - Updated resource initialization error handling to utilize the new logging structure, enhancing maintainability and readability. - Minor adjustments to improve code clarity and organization throughout various modules. This change aims to streamline logging and improve the overall architecture of the codebase.
240 lines
5.5 KiB
Go
240 lines
5.5 KiB
Go
package controller
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"one-api/common"
|
|
"one-api/model"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/gin-contrib/sessions"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type GitHubOAuthResponse struct {
|
|
AccessToken string `json:"access_token"`
|
|
Scope string `json:"scope"`
|
|
TokenType string `json:"token_type"`
|
|
}
|
|
|
|
type GitHubUser struct {
|
|
Login string `json:"login"`
|
|
Name string `json:"name"`
|
|
Email string `json:"email"`
|
|
}
|
|
|
|
func getGitHubUserInfoByCode(code string) (*GitHubUser, error) {
|
|
if code == "" {
|
|
return nil, errors.New("无效的参数")
|
|
}
|
|
values := map[string]string{"client_id": common.GitHubClientId, "client_secret": common.GitHubClientSecret, "code": code}
|
|
jsonData, err := json.Marshal(values)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
req, err := http.NewRequest("POST", "https://github.com/login/oauth/access_token", bytes.NewBuffer(jsonData))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Accept", "application/json")
|
|
client := http.Client{
|
|
Timeout: 5 * time.Second,
|
|
}
|
|
res, err := client.Do(req)
|
|
if err != nil {
|
|
common.SysLog(err.Error())
|
|
return nil, errors.New("无法连接至 GitHub 服务器,请稍后重试!")
|
|
}
|
|
defer res.Body.Close()
|
|
var oAuthResponse GitHubOAuthResponse
|
|
err = json.NewDecoder(res.Body).Decode(&oAuthResponse)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
req, err = http.NewRequest("GET", "https://api.github.com/user", nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", oAuthResponse.AccessToken))
|
|
res2, err := client.Do(req)
|
|
if err != nil {
|
|
common.SysLog(err.Error())
|
|
return nil, errors.New("无法连接至 GitHub 服务器,请稍后重试!")
|
|
}
|
|
defer res2.Body.Close()
|
|
var githubUser GitHubUser
|
|
err = json.NewDecoder(res2.Body).Decode(&githubUser)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if githubUser.Login == "" {
|
|
return nil, errors.New("返回值非法,用户字段为空,请稍后重试!")
|
|
}
|
|
return &githubUser, nil
|
|
}
|
|
|
|
func GitHubOAuth(c *gin.Context) {
|
|
session := sessions.Default(c)
|
|
state := c.Query("state")
|
|
if state == "" || session.Get("oauth_state") == nil || state != session.Get("oauth_state").(string) {
|
|
c.JSON(http.StatusForbidden, gin.H{
|
|
"success": false,
|
|
"message": "state is empty or not same",
|
|
})
|
|
return
|
|
}
|
|
username := session.Get("username")
|
|
if username != nil {
|
|
GitHubBind(c)
|
|
return
|
|
}
|
|
|
|
if !common.GitHubOAuthEnabled {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": false,
|
|
"message": "管理员未开启通过 GitHub 登录以及注册",
|
|
})
|
|
return
|
|
}
|
|
code := c.Query("code")
|
|
githubUser, err := getGitHubUserInfoByCode(code)
|
|
if err != nil {
|
|
common.ApiError(c, err)
|
|
return
|
|
}
|
|
user := model.User{
|
|
GitHubId: githubUser.Login,
|
|
}
|
|
// IsGitHubIdAlreadyTaken is unscoped
|
|
if model.IsGitHubIdAlreadyTaken(user.GitHubId) {
|
|
// FillUserByGitHubId is scoped
|
|
err := user.FillUserByGitHubId()
|
|
if err != nil {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": false,
|
|
"message": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
// if user.Id == 0 , user has been deleted
|
|
if user.Id == 0 {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": false,
|
|
"message": "用户已注销",
|
|
})
|
|
return
|
|
}
|
|
} else {
|
|
if common.RegisterEnabled {
|
|
user.Username = "github_" + strconv.Itoa(model.GetMaxUserId()+1)
|
|
if githubUser.Name != "" {
|
|
user.DisplayName = githubUser.Name
|
|
} else {
|
|
user.DisplayName = "GitHub User"
|
|
}
|
|
user.Email = githubUser.Email
|
|
user.Role = common.RoleCommonUser
|
|
user.Status = common.UserStatusEnabled
|
|
affCode := session.Get("aff")
|
|
inviterId := 0
|
|
if affCode != nil {
|
|
inviterId, _ = model.GetUserIdByAffCode(affCode.(string))
|
|
}
|
|
|
|
if err := user.Insert(inviterId); err != nil {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": false,
|
|
"message": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
} else {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": false,
|
|
"message": "管理员关闭了新用户注册",
|
|
})
|
|
return
|
|
}
|
|
}
|
|
|
|
if user.Status != common.UserStatusEnabled {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"message": "用户已被封禁",
|
|
"success": false,
|
|
})
|
|
return
|
|
}
|
|
setupLogin(&user, c)
|
|
}
|
|
|
|
func GitHubBind(c *gin.Context) {
|
|
if !common.GitHubOAuthEnabled {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": false,
|
|
"message": "管理员未开启通过 GitHub 登录以及注册",
|
|
})
|
|
return
|
|
}
|
|
code := c.Query("code")
|
|
githubUser, err := getGitHubUserInfoByCode(code)
|
|
if err != nil {
|
|
common.ApiError(c, err)
|
|
return
|
|
}
|
|
user := model.User{
|
|
GitHubId: githubUser.Login,
|
|
}
|
|
if model.IsGitHubIdAlreadyTaken(user.GitHubId) {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": false,
|
|
"message": "该 GitHub 账户已被绑定",
|
|
})
|
|
return
|
|
}
|
|
session := sessions.Default(c)
|
|
id := session.Get("id")
|
|
// id := c.GetInt("id") // critical bug!
|
|
user.Id = id.(int)
|
|
err = user.FillUserById()
|
|
if err != nil {
|
|
common.ApiError(c, err)
|
|
return
|
|
}
|
|
user.GitHubId = githubUser.Login
|
|
err = user.Update(false)
|
|
if err != nil {
|
|
common.ApiError(c, err)
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": true,
|
|
"message": "bind",
|
|
})
|
|
return
|
|
}
|
|
|
|
func GenerateOAuthCode(c *gin.Context) {
|
|
session := sessions.Default(c)
|
|
state := common.GetRandomString(12)
|
|
affCode := c.Query("aff")
|
|
if affCode != "" {
|
|
session.Set("aff", affCode)
|
|
}
|
|
session.Set("oauth_state", state)
|
|
err := session.Save()
|
|
if err != nil {
|
|
common.ApiError(c, err)
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": true,
|
|
"message": "",
|
|
"data": state,
|
|
})
|
|
}
|