- OAuth认证系统(Gitea + Lua扩展) - Git自动化操作(本地/SSH远程) - 实时进度WebSocket推送 - 现代化Tab界面UI - Cobra CLI命令行(init/version/serve) - 完整构建系统(Makefile + Taskfile) - UPX压缩支持(体积减少70%)
112 lines
3.1 KiB
Go
112 lines
3.1 KiB
Go
package oauth
|
|
|
|
import (
|
|
"cs-bridge/internal/auth"
|
|
"cs-bridge/internal/config"
|
|
"cs-bridge/pkg/httpclient"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/url"
|
|
"time"
|
|
)
|
|
|
|
type Gitea struct {
|
|
cfg config.Provider
|
|
redirectURI string
|
|
}
|
|
|
|
// Name implements [Provider].
|
|
func (g Gitea) Name() string {
|
|
return "gitea"
|
|
}
|
|
|
|
// AuthURL implements [Provider].
|
|
func (g Gitea) AuthURL(state string) (string, error) {
|
|
u, _ := url.Parse(g.cfg.BaseURL + g.cfg.AuthorizeURL)
|
|
q := u.Query()
|
|
q.Set("client_id", g.cfg.ClientID)
|
|
q.Set("redirect_uri", g.redirectURI)
|
|
q.Set("response_type", "code")
|
|
q.Set("scope", "read:user")
|
|
q.Set("state", state)
|
|
u.RawQuery = q.Encode()
|
|
return u.String(), nil
|
|
}
|
|
|
|
// Exchange implements [Provider].
|
|
func (g Gitea) Exchange(code string) (string, error) {
|
|
resp, err := httpclient.Default.R().
|
|
SetHeader("Accept", "application/json").
|
|
SetFormData(map[string]string{
|
|
"client_id": g.cfg.ClientID,
|
|
"client_secret": g.cfg.ClientSecret,
|
|
"code": code,
|
|
"grant_type": "authorization_code",
|
|
"redirect_uri": g.redirectURI,
|
|
}).
|
|
Post(fmt.Sprintf("%s%s", g.cfg.BaseURL, g.cfg.TokenURL))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
var out struct {
|
|
AccessToken string `json:"access_token"`
|
|
TokenType string `json:"token_type"`
|
|
ExpiresIn string `json:"expires_in"`
|
|
RefreshToken string `json:"refresh_token"`
|
|
}
|
|
json.NewDecoder(resp.Body).Decode(&out)
|
|
|
|
return out.AccessToken, nil
|
|
}
|
|
|
|
// UserInfo implements [Provider].
|
|
func (g Gitea) UserInfo(token string) (auth.Identify, error) {
|
|
resp, err := httpclient.Default.R().
|
|
SetHeader("Authorization", fmt.Sprintf("bearer %s", token)).
|
|
Get(fmt.Sprintf("%s%s", g.cfg.BaseURL, g.cfg.UserURL))
|
|
if err != nil {
|
|
return auth.Identify{}, err
|
|
}
|
|
var raw raw
|
|
json.NewDecoder(resp.Body).Decode(&raw)
|
|
return auth.Identify{
|
|
Provider: g.Name(),
|
|
UserId: fmt.Sprint(raw.ID),
|
|
Username: raw.Login,
|
|
Avatar: raw.AvatarURL,
|
|
}, nil
|
|
}
|
|
|
|
func NewGitea(cfg config.Provider, redirectURI string) Gitea {
|
|
return Gitea{
|
|
cfg: cfg,
|
|
redirectURI: redirectURI,
|
|
}
|
|
}
|
|
|
|
type raw struct {
|
|
ID int `json:"id"`
|
|
Login string `json:"login"`
|
|
LoginName string `json:"login_name"`
|
|
SourceID int `json:"source_id"`
|
|
FullName string `json:"full_name"`
|
|
Email string `json:"email"`
|
|
AvatarURL string `json:"avatar_url"`
|
|
HTMLURL string `json:"html_url"`
|
|
Language string `json:"language"`
|
|
IsAdmin bool `json:"is_admin"`
|
|
LastLogin time.Time `json:"last_login"`
|
|
Created time.Time `json:"created"`
|
|
Restricted bool `json:"restricted"`
|
|
Active bool `json:"active"`
|
|
ProhibitLogin bool `json:"prohibit_login"`
|
|
Location string `json:"location"`
|
|
Website string `json:"website"`
|
|
Description string `json:"description"`
|
|
Visibility string `json:"visibility"`
|
|
FollowersCount int `json:"followers_count"`
|
|
FollowingCount int `json:"following_count"`
|
|
StarredReposCount int `json:"starred_repos_count"`
|
|
Username string `json:"username"`
|
|
}
|