1
0
Fork 0
cmdui/backend/api/github/github.go

92 lines
2.3 KiB
Go

package github
import (
"bytes"
"context"
"encoding/json"
"io/ioutil"
"net/http"
"net/url"
"github.com/juju/errors"
"github.com/localhots/cmdui/backend/config"
)
type User struct {
ID uint `json:"id"`
Login string `json:"login"`
Name string `json:"name"`
Picture string `json:"avatar_url"`
}
const (
authorizeURL = "https://github.com/login/oauth/authorize"
accessTokenURL = "https://github.com/login/oauth/access_token"
userDetailsURL = "https://api.github.com/user"
)
func RedirectToLogin(w http.ResponseWriter, r *http.Request) {
urlStr := authorizeURL + "?" + url.Values{
"client_id": {config.Get().Github.ClientID},
"scope": {"user"},
}.Encode()
http.Redirect(w, r, urlStr, http.StatusTemporaryRedirect)
}
func ExchangeCode(ctx context.Context, code string) (accessToken string, err error) {
cfg := config.Get()
reqBody := bytes.NewBufferString(url.Values{
"client_id": {cfg.Github.ClientID},
"client_secret": {cfg.Github.ClientSecret},
"code": {code},
}.Encode())
req, err := http.NewRequest(http.MethodPost, accessTokenURL, reqBody)
if err != nil {
return "", errors.Annotate(err, "Failed to create a code exchange request")
}
// Passing client request context
req = req.WithContext(ctx)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", errors.Annotate(err, "Failed to perform code exchange request")
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", errors.Annotate(err, "Failed to read access token response")
}
uri, err := url.ParseQuery(string(respBody))
if err != nil {
return "", errors.Annotate(err, "Failed to parse access token response")
}
return uri.Get("access_token"), nil
}
func AuthDetails(accessToken string) (User, error) {
var u User
reqURL := userDetailsURL + "?" + url.Values{
"access_token": {accessToken},
}.Encode()
resp, err := http.Get(reqURL)
if err != nil {
return u, errors.Annotate(err, "Failed to fetch authenticated user details")
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return u, errors.Annotate(err, "Failed to read authenticated user details")
}
if err := json.Unmarshal(body, &u); err != nil {
return u, errors.Annotate(err, "Failed to parse authenticated user details")
}
return u, nil
}