| | package controller
|
| |
|
| | import (
|
| | "bytes"
|
| | "encoding/json"
|
| | "errors"
|
| | "fmt"
|
| | "net/http"
|
| | "strconv"
|
| | "time"
|
| |
|
| | "github.com/QuantumNous/new-api/common"
|
| | "github.com/QuantumNous/new-api/model"
|
| |
|
| | "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: 20 * 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,
|
| | }
|
| |
|
| | if model.IsGitHubIdAlreadyTaken(user.GitHubId) {
|
| |
|
| | err := user.FillUserByGitHubId()
|
| | if err != nil {
|
| | c.JSON(http.StatusOK, gin.H{
|
| | "success": false,
|
| | "message": err.Error(),
|
| | })
|
| | return
|
| | }
|
| |
|
| | 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")
|
| |
|
| | 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,
|
| | })
|
| | }
|
| |
|