loginsrv

Unnamed repository; edit this file 'description' to name the repository.
git clone git@jamesshield.xyz:repos/loginsrv.git
Log | Files | Refs | README | LICENSE

bitbucket.go (3809B)


      1 package oauth2
      2 
      3 import (
      4 	"encoding/json"
      5 	"fmt"
      6 	"io/ioutil"
      7 	"net/http"
      8 	"strings"
      9 
     10 	"github.com/tarent/loginsrv/model"
     11 )
     12 
     13 var bitbucketAPI = "https://api.bitbucket.org/2.0"
     14 
     15 // Using the avatar url to be able to fetch 128px image. By default BitbucketAPI return 32px image.
     16 var bitbucketAvatarURL = "https://bitbucket.org/account/%v/avatar/128/"
     17 
     18 func init() {
     19 	RegisterProvider(providerBitbucket)
     20 }
     21 
     22 // bitbucketUser is used for parsing the github response
     23 type bitbucketUser struct {
     24 	Username    string `json:"username,omitempty"`
     25 	DisplayName string `json:"display_name,omitempty"`
     26 	Email       string `json:"email,omitempty"`
     27 }
     28 
     29 // emails is used to parse user email information
     30 type emails struct {
     31 	Page    int `json:"page,omitempty"`
     32 	PageLen int `json:"pagelen,omitempty"`
     33 	Size    int `json:"size,omitempty"`
     34 	Values  []email
     35 }
     36 
     37 // email used to parse one user's email
     38 type email struct {
     39 	Email       string `json:"email,omitempty"`
     40 	IsConfirmed bool   `json:"is_confirmed,omitempty"`
     41 	IsPrimary   bool   `json:"is_primary,omitempty"`
     42 	Links       struct {
     43 		Self struct {
     44 			Href string
     45 		}
     46 	} `json:"links,omitempty"`
     47 	Type string `json:"type,omitempty"`
     48 }
     49 
     50 // getPrimaryEmailAddress retrieve the primary email address of the user
     51 func (e *emails) getPrimaryEmailAddress() string {
     52 	for _, val := range e.Values {
     53 		if val.IsPrimary {
     54 			return val.Email
     55 		}
     56 	}
     57 	return ""
     58 }
     59 
     60 // getBitbucketEmails Retrieves bitbucket user emails from the Bitbucket API emails service
     61 func getBitbucketEmails(token TokenInfo) (emails, error) {
     62 	emailUrl := fmt.Sprintf("%v/user/emails?access_token=%v", bitbucketAPI, token.AccessToken)
     63 	userEmails := emails{}
     64 	resp, err := http.Get(emailUrl)
     65 
     66 	if err != nil {
     67 		return emails{}, err
     68 	}
     69 	defer resp.Body.Close()
     70 
     71 	if !strings.Contains(resp.Header.Get("Content-Type"), "application/json") {
     72 		return emails{}, fmt.Errorf("wrong content-type on bitbucket get user emails: %v", resp.Header.Get("Content-Type"))
     73 	}
     74 
     75 	if resp.StatusCode != 200 {
     76 		return emails{}, fmt.Errorf("got http status %v on bitbucket get user emails", resp.StatusCode)
     77 	}
     78 
     79 	b, err := ioutil.ReadAll(resp.Body)
     80 	if err != nil {
     81 		return emails{}, fmt.Errorf("error reading bitbucket get user emails: %v", err)
     82 	}
     83 
     84 	err = json.Unmarshal(b, &userEmails)
     85 
     86 	if err != nil {
     87 		return emails{}, fmt.Errorf("error parsing bitbucket get user emails: %v", err)
     88 	}
     89 
     90 	return userEmails, nil
     91 }
     92 
     93 var providerBitbucket = Provider{
     94 	Name:     "bitbucket",
     95 	AuthURL:  "https://bitbucket.org/site/oauth2/authorize",
     96 	TokenURL: "https://bitbucket.org/site/oauth2/access_token",
     97 	GetUserInfo: func(token TokenInfo) (model.UserInfo, string, error) {
     98 		gu := bitbucketUser{}
     99 		url := fmt.Sprintf("%v/user?access_token=%v", bitbucketAPI, token.AccessToken)
    100 		resp, err := http.Get(url)
    101 		if err != nil {
    102 			return model.UserInfo{}, "", err
    103 		}
    104 		defer resp.Body.Close()
    105 
    106 		if !strings.Contains(resp.Header.Get("Content-Type"), "application/json") {
    107 			return model.UserInfo{}, "", fmt.Errorf("wrong content-type on bitbucket get user info: %v", resp.Header.Get("Content-Type"))
    108 		}
    109 
    110 		if resp.StatusCode != 200 {
    111 			return model.UserInfo{}, "", fmt.Errorf("got http status %v on bitbucket get user info", resp.StatusCode)
    112 		}
    113 
    114 		b, err := ioutil.ReadAll(resp.Body)
    115 		if err != nil {
    116 			return model.UserInfo{}, "", fmt.Errorf("error reading bitbucket get user info: %v", err)
    117 		}
    118 
    119 		err = json.Unmarshal(b, &gu)
    120 
    121 		if err != nil {
    122 			return model.UserInfo{}, "", fmt.Errorf("error parsing bitbucket get user info: %v", err)
    123 		}
    124 
    125 		userEmails, err := getBitbucketEmails(token)
    126 
    127 		return model.UserInfo{
    128 			Sub:     gu.Username,
    129 			Picture: fmt.Sprintf(bitbucketAvatarURL, gu.Username),
    130 			Name:    gu.DisplayName,
    131 			Email:   userEmails.getPrimaryEmailAddress(),
    132 			Origin:  "bitbucket",
    133 		}, string(b), nil
    134 	},
    135 }