2020-04-28 13:11:49 +02:00
|
|
|
package github
|
2020-04-30 11:14:46 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2021-04-06 14:23:23 +02:00
|
|
|
"github.com/vx3r/wg-gen-web/model"
|
2020-04-30 11:14:46 +02:00
|
|
|
"golang.org/x/oauth2"
|
|
|
|
oauth2Github "golang.org/x/oauth2/github"
|
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2020-06-10 09:52:44 +02:00
|
|
|
// Github in order to implement interface, struct is required
|
2020-04-30 11:14:46 +02:00
|
|
|
type Github struct{}
|
|
|
|
|
|
|
|
var (
|
|
|
|
oauth2Config *oauth2.Config
|
|
|
|
)
|
|
|
|
|
|
|
|
// Setup validate provider
|
|
|
|
func (o *Github) Setup() error {
|
|
|
|
oauth2Config = &oauth2.Config{
|
|
|
|
ClientID: os.Getenv("OAUTH2_CLIENT_ID"),
|
|
|
|
ClientSecret: os.Getenv("OAUTH2_CLIENT_SECRET"),
|
|
|
|
RedirectURL: os.Getenv("OAUTH2_REDIRECT_URL"),
|
|
|
|
Scopes: []string{"user"},
|
|
|
|
Endpoint: oauth2Github.Endpoint,
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// CodeUrl get url to redirect client for auth
|
|
|
|
func (o *Github) CodeUrl(state string) string {
|
|
|
|
return oauth2Config.AuthCodeURL(state)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Exchange exchange code for Oauth2 token
|
|
|
|
func (o *Github) Exchange(code string) (*oauth2.Token, error) {
|
|
|
|
oauth2Token, err := oauth2Config.Exchange(context.TODO(), code)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return oauth2Token, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// UserInfo get token user
|
|
|
|
func (o *Github) UserInfo(oauth2Token *oauth2.Token) (*model.User, error) {
|
|
|
|
// https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/
|
|
|
|
|
|
|
|
// we have the token, lets get user information
|
|
|
|
req, err := http.NewRequest("GET", "https://api.github.com/user", nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req.Header.Set("Authorization", fmt.Sprintf("token %s", oauth2Token.AccessToken))
|
|
|
|
client := &http.Client{}
|
|
|
|
resp, err := client.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if resp.StatusCode != 200 {
|
|
|
|
return nil, fmt.Errorf("http status %s expect 200 OK", resp.Status)
|
|
|
|
}
|
|
|
|
|
|
|
|
bodyBytes, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
var data map[string]interface{}
|
|
|
|
err = json.Unmarshal(bodyBytes, &data)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// get some infos about user
|
|
|
|
user := &model.User{}
|
|
|
|
|
|
|
|
if val, ok := data["name"]; ok && val != nil {
|
|
|
|
user.Name = val.(string)
|
|
|
|
}
|
|
|
|
if val, ok := data["email"]; ok && val != nil {
|
|
|
|
user.Email = val.(string)
|
|
|
|
}
|
|
|
|
if val, ok := data["html_url"]; ok && val != nil {
|
|
|
|
user.Profile = val.(string)
|
|
|
|
}
|
|
|
|
|
|
|
|
// openid specific
|
|
|
|
user.Sub = "github is not an openid provider"
|
|
|
|
user.Issuer = "https://github.com"
|
|
|
|
user.IssuedAt = time.Now().UTC()
|
|
|
|
|
|
|
|
return user, nil
|
|
|
|
}
|