2015-05-21 06:23:48 +03:00
package providers
import (
"encoding/json"
2015-06-06 21:15:43 +03:00
"fmt"
2015-05-21 06:23:48 +03:00
"io/ioutil"
"net/http"
"net/url"
)
type GitHubProvider struct {
* ProviderData
Org string
Team string
}
func NewGitHubProvider ( p * ProviderData ) * GitHubProvider {
p . ProviderName = "GitHub"
if p . LoginUrl . String ( ) == "" {
p . LoginUrl = & url . URL {
Scheme : "https" ,
Host : "github.com" ,
Path : "/login/oauth/authorize" ,
}
}
if p . RedeemUrl . String ( ) == "" {
p . RedeemUrl = & url . URL {
Scheme : "https" ,
Host : "github.com" ,
Path : "/login/oauth/access_token" ,
}
}
if p . ValidateUrl . String ( ) == "" {
p . ValidateUrl = & url . URL {
Scheme : "https" ,
Host : "api.github.com" ,
Path : "/user/emails" ,
}
}
if p . Scope == "" {
p . Scope = "user:email"
}
return & GitHubProvider { ProviderData : p }
}
func ( p * GitHubProvider ) SetOrgTeam ( org , team string ) {
p . Org = org
p . Team = team
if org != "" || team != "" {
p . Scope += " read:org"
}
}
2015-06-06 21:03:59 +03:00
func ( p * GitHubProvider ) hasOrg ( accessToken string ) ( bool , error ) {
// https://developer.github.com/v3/orgs/#list-your-organizations
var orgs [ ] struct {
Login string ` json:"login" `
}
params := url . Values {
"access_token" : { accessToken } ,
2015-06-06 21:15:43 +03:00
"limit" : { "100" } ,
2015-06-06 21:03:59 +03:00
}
2015-06-06 21:15:43 +03:00
endpoint := "https://api.github.com/user/orgs?" + params . Encode ( )
req , _ := http . NewRequest ( "GET" , endpoint , nil )
2015-06-06 21:03:59 +03:00
req . Header . Set ( "Accept" , "application/vnd.github.moondragon+json" )
resp , err := http . DefaultClient . Do ( req )
if err != nil {
return false , err
}
body , err := ioutil . ReadAll ( resp . Body )
resp . Body . Close ( )
if err != nil {
return false , err
}
2015-06-06 21:15:43 +03:00
if resp . StatusCode != 200 {
return false , fmt . Errorf ( "got %d from %q %s" , resp . StatusCode , endpoint , body )
}
2015-06-06 21:03:59 +03:00
if err := json . Unmarshal ( body , & orgs ) ; err != nil {
return false , err
}
for _ , org := range orgs {
if p . Org == org . Login {
return true , nil
}
}
return false , nil
}
2015-05-21 06:23:48 +03:00
func ( p * GitHubProvider ) hasOrgAndTeam ( accessToken string ) ( bool , error ) {
2015-06-06 21:03:59 +03:00
// https://developer.github.com/v3/orgs/teams/#list-user-teams
2015-05-21 06:23:48 +03:00
var teams [ ] struct {
Name string ` json:"name" `
Slug string ` json:"slug" `
Org struct {
Login string ` json:"login" `
} ` json:"organization" `
}
params := url . Values {
"access_token" : { accessToken } ,
2015-06-06 21:15:43 +03:00
"limit" : { "100" } ,
2015-05-21 06:23:48 +03:00
}
2015-06-06 21:15:43 +03:00
endpoint := "https://api.github.com/user/teams?" + params . Encode ( )
req , _ := http . NewRequest ( "GET" , endpoint , nil )
2015-05-21 06:23:48 +03:00
req . Header . Set ( "Accept" , "application/vnd.github.moondragon+json" )
resp , err := http . DefaultClient . Do ( req )
if err != nil {
return false , err
}
body , err := ioutil . ReadAll ( resp . Body )
resp . Body . Close ( )
if err != nil {
return false , err
}
2015-06-06 21:15:43 +03:00
if resp . StatusCode != 200 {
return false , fmt . Errorf ( "got %d from %q %s" , resp . StatusCode , endpoint , body )
}
2015-05-21 06:23:48 +03:00
if err := json . Unmarshal ( body , & teams ) ; err != nil {
2015-06-06 21:15:43 +03:00
return false , fmt . Errorf ( "%s unmarshaling %s" , err , body )
2015-05-21 06:23:48 +03:00
}
for _ , team := range teams {
if p . Org == team . Org . Login {
if p . Team == "" || p . Team == team . Slug {
return true , nil
}
}
}
return false , nil
}
func ( p * GitHubProvider ) GetEmailAddress ( body [ ] byte , access_token string ) ( string , error ) {
var emails [ ] struct {
Email string ` json:"email" `
Primary bool ` json:"primary" `
}
// if we require an Org or Team, check that first
2015-06-06 21:03:59 +03:00
if p . Org != "" {
if p . Team != "" {
if ok , err := p . hasOrgAndTeam ( access_token ) ; err != nil || ! ok {
return "" , err
}
} else {
if ok , err := p . hasOrg ( access_token ) ; err != nil || ! ok {
return "" , err
}
2015-05-21 06:23:48 +03:00
}
}
2015-06-06 21:03:59 +03:00
params := url . Values {
"access_token" : { access_token } ,
}
2015-06-06 21:15:43 +03:00
endpoint := "https://api.github.com/user/emails?" + params . Encode ( )
resp , err := http . DefaultClient . Get ( endpoint )
2015-05-21 06:23:48 +03:00
if err != nil {
return "" , err
}
body , err = ioutil . ReadAll ( resp . Body )
resp . Body . Close ( )
if err != nil {
return "" , err
}
2015-06-06 21:15:43 +03:00
if resp . StatusCode != 200 {
return "" , fmt . Errorf ( "got %d from %q %s" , resp . StatusCode , endpoint , body )
}
2015-05-21 06:23:48 +03:00
if err := json . Unmarshal ( body , & emails ) ; err != nil {
2015-06-06 21:15:43 +03:00
return "" , fmt . Errorf ( "%s unmarshaling %s" , err , body )
2015-05-21 06:23:48 +03:00
}
for _ , email := range emails {
if email . Primary {
return email . Email , nil
}
}
return "" , nil
}
func ( p * GitHubProvider ) ValidateToken ( access_token string ) bool {
return validateToken ( p , access_token , nil )
}