mirror of
https://github.com/linux-do/new-api.git
synced 2025-09-17 16:06:38 +08:00
266 lines
5.7 KiB
Go
266 lines
5.7 KiB
Go
package controller
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"one-api/common"
|
|
"one-api/model"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gin-contrib/sessions"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type LinuxdoUser struct {
|
|
Id int `json:"id"`
|
|
Username string `json:"username"`
|
|
Name string `json:"name"`
|
|
Active bool `json:"active"`
|
|
TrustLevel int `json:"trust_level"`
|
|
Silenced bool `json:"silenced"`
|
|
}
|
|
|
|
func LinuxDoBind(c *gin.Context) {
|
|
if !common.LinuxDOOAuthEnabled {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": false,
|
|
"message": "管理员未开启通过 Linux DO 登录以及注册",
|
|
})
|
|
return
|
|
}
|
|
|
|
code := c.Query("code")
|
|
linuxdoUser, err := getLinuxdoUserInfoByCode(code, c)
|
|
if err != nil {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": false,
|
|
"message": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
|
|
user := model.User{
|
|
LinuxDOId: strconv.Itoa(linuxdoUser.Id),
|
|
}
|
|
|
|
if model.IsLinuxDOIdAlreadyTaken(user.LinuxDOId) {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": false,
|
|
"message": "该 Linux DO 账户已被绑定",
|
|
})
|
|
return
|
|
}
|
|
|
|
session := sessions.Default(c)
|
|
id := session.Get("id")
|
|
user.Id = id.(int)
|
|
|
|
err = user.FillUserById()
|
|
if err != nil {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": false,
|
|
"message": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
|
|
user.LinuxDOId = strconv.Itoa(linuxdoUser.Id)
|
|
err = user.Update(false)
|
|
if err != nil {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": false,
|
|
"message": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": true,
|
|
"message": "bind",
|
|
})
|
|
}
|
|
|
|
func getLinuxdoUserInfoByCode(code string, c *gin.Context) (*LinuxdoUser, error) {
|
|
if code == "" {
|
|
return nil, errors.New("invalid code")
|
|
}
|
|
|
|
// Get access token using Basic auth
|
|
tokenEndpoint := "https://connect.linux.do/oauth2/token"
|
|
credentials := common.LinuxDOClientId + ":" + common.LinuxDOClientSecret
|
|
basicAuth := "Basic " + base64.StdEncoding.EncodeToString([]byte(credentials))
|
|
|
|
// Get redirect URI from request
|
|
scheme := "http"
|
|
if c.Request.TLS != nil {
|
|
scheme = "https"
|
|
}
|
|
redirectURI := fmt.Sprintf("%s://%s/api/oauth/linuxdo", scheme, c.Request.Host)
|
|
|
|
data := url.Values{}
|
|
data.Set("grant_type", "authorization_code")
|
|
data.Set("code", code)
|
|
data.Set("redirect_uri", redirectURI)
|
|
|
|
req, err := http.NewRequest("POST", tokenEndpoint, strings.NewReader(data.Encode()))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
req.Header.Set("Authorization", basicAuth)
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
req.Header.Set("Accept", "application/json")
|
|
|
|
client := http.Client{Timeout: 5 * time.Second}
|
|
res, err := client.Do(req)
|
|
if err != nil {
|
|
return nil, errors.New("failed to connect to Linux DO server")
|
|
}
|
|
defer res.Body.Close()
|
|
|
|
var tokenRes struct {
|
|
AccessToken string `json:"access_token"`
|
|
Message string `json:"message"`
|
|
}
|
|
if err := json.NewDecoder(res.Body).Decode(&tokenRes); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if tokenRes.AccessToken == "" {
|
|
return nil, fmt.Errorf("failed to get access token: %s", tokenRes.Message)
|
|
}
|
|
|
|
// Get user info
|
|
userEndpoint := "https://connect.linux.do/api/user"
|
|
req, err = http.NewRequest("GET", userEndpoint, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
req.Header.Set("Authorization", "Bearer "+tokenRes.AccessToken)
|
|
req.Header.Set("Accept", "application/json")
|
|
|
|
res2, err := client.Do(req)
|
|
if err != nil {
|
|
return nil, errors.New("failed to get user info from Linux DO")
|
|
}
|
|
defer res2.Body.Close()
|
|
|
|
var linuxdoUser LinuxdoUser
|
|
if err := json.NewDecoder(res2.Body).Decode(&linuxdoUser); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if linuxdoUser.Id == 0 {
|
|
return nil, errors.New("invalid user info returned")
|
|
}
|
|
|
|
return &linuxdoUser, nil
|
|
}
|
|
|
|
func LinuxdoOAuth(c *gin.Context) {
|
|
session := sessions.Default(c)
|
|
|
|
errorCode := c.Query("error")
|
|
if errorCode != "" {
|
|
errorDescription := c.Query("error_description")
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": false,
|
|
"message": errorDescription,
|
|
})
|
|
return
|
|
}
|
|
|
|
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 {
|
|
LinuxDoBind(c)
|
|
return
|
|
}
|
|
|
|
if !common.LinuxDOOAuthEnabled {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": false,
|
|
"message": "管理员未开启通过 Linux DO 登录以及注册",
|
|
})
|
|
return
|
|
}
|
|
|
|
code := c.Query("code")
|
|
linuxdoUser, err := getLinuxdoUserInfoByCode(code, c)
|
|
if err != nil {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": false,
|
|
"message": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
|
|
user := model.User{
|
|
LinuxDOId: strconv.Itoa(linuxdoUser.Id),
|
|
}
|
|
|
|
// Check if user exists
|
|
if model.IsLinuxDOIdAlreadyTaken(user.LinuxDOId) {
|
|
err := user.FillUserByLinuxDOId()
|
|
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 = "linuxdo_" + strconv.Itoa(model.GetMaxUserId()+1)
|
|
user.DisplayName = linuxdoUser.Name
|
|
user.Role = common.RoleCommonUser
|
|
user.Status = common.UserStatusEnabled
|
|
|
|
if err := user.Insert(0); 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)
|
|
}
|