package auth import ( "CatsOfMastodonBotGo/internal/config" "bytes" "encoding/json" "io" "log/slog" "net/http" "net/url" ) type GiteaOAuth2Handler struct { ClientID string ClientSecret string InstanceUrl string } var GiteaOauth2HandlerInstance *GiteaOAuth2Handler func InitGiteaOauth2Token() { GiteaOauth2HandlerInstance = &GiteaOAuth2Handler{ ClientID: config.Config.GiteaOauthClientID, ClientSecret: config.Config.GiteaOauthClientSecret, InstanceUrl: config.Config.GiteaOauthInstance, } } func (g *GiteaOAuth2Handler) GetGiteaLoginURL(redirectHost string) (string, error) { if g.InstanceUrl == "" { return "", nil } if redirectHost == "" { slog.Error("Redirect host not provided") return "", nil } authUrl := g.InstanceUrl + "/login/oauth/authorize?client_id=" + g.ClientID + "&redirect_uri=" + "http://" + redirectHost + "/admin/oauth/gitea/callback&scope=openid&response_type=code&response_mode=form_post" return authUrl, nil } func (g *GiteaOAuth2Handler) GetGiteaUserEmailByCode(code string) (string, error) { if g.InstanceUrl == "" { slog.Error("Instance URL not provided") return "", nil } // No need to verify since we are accesing the gitea once and only for the email accessToken, err := g.getGiteaAccessTokenByCode(code) if err != nil { return "", err } userInfoUrl := g.InstanceUrl + "/login/oauth/userinfo" slog.Info(userInfoUrl) req, err := http.NewRequest("POST", userInfoUrl, nil) if err != nil { return "", err } req.Header.Set("Authorization", "Bearer "+accessToken) req.Header.Set("Accept", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { return "", err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return "", err } var userInfo struct { Email string `json:"email"` } if err := json.Unmarshal(body, &userInfo); err != nil { return "", err } return userInfo.Email, nil } func (g *GiteaOAuth2Handler) getGiteaAccessTokenByCode(code string) (string, error) { form := url.Values{} form.Add("client_id", g.ClientID) form.Add("client_secret", g.ClientSecret) form.Add("code", code) form.Add("grant_type", "authorization_code") req, err := http.NewRequest("POST", g.InstanceUrl+"/login/oauth/access_token", bytes.NewBufferString(form.Encode())) if err != nil { return "", err } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { return "", err } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) var tokenResp struct { AccessToken string `json:"access_token"` } if err := json.Unmarshal(body, &tokenResp); err != nil { return "", err } return tokenResp.AccessToken, nil }