0
0
mirror of https://github.com/vx3r/wg-gen-web.git synced 2025-04-02 16:46:52 +00:00
wg-gen-web/auth/github/github.go
2024-05-04 00:41:23 -07:00

148 lines
3.5 KiB
Go

package github
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"time"
"github.com/vx3r/wg-gen-web/model"
"golang.org/x/oauth2"
oauth2Github "golang.org/x/oauth2/github"
)
// Github in order to implement interface, struct is required
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{"read:user", "user:email", "read:org"},
Endpoint: oauth2Github.Endpoint,
}
return nil
}
// Check if current user is in given org
func (o *Github) CheckMembership(oauth2Token *oauth2.Token, org string, teams []string) (bool, error) {
// we have the token, lets get user information
user, err := o.UserInfo(oauth2Token)
if err != nil {
return false, err
}
client := &http.Client{}
// If teams is empty, check for org membership
if len(teams) == 0 {
url := fmt.Sprintf("https://api.github.com/orgs/%s/members/%s", org, user.Name)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return false, err
}
req.Header.Set("Authorization", fmt.Sprintf("token %s", oauth2Token.AccessToken))
resp, err := client.Do(req)
if err == nil && resp.StatusCode == 204 {
return true, nil
}
return false, err
}
// If team slice is not empty, check for team membership
// GET /orgs/{org}/teams/{team_slug}/memberships/{username}
for _, team := range teams {
url := fmt.Sprintf("https://api.github.com/orgs/%s/teams/%s/memberships/%s", org, team, user.Name)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return false, err
}
req.Header.Set("Authorization", fmt.Sprintf("token %s", oauth2Token.AccessToken))
resp, err := client.Do(req)
if err == nil && resp.StatusCode == 200 {
return true, nil
}
}
return false, err
}
// 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["login"]; ok && val != nil {
user.Name = val.(string)
}
if val, ok := data["email"]; ok && val != nil {
user.Email = 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
}