Discord Oauth2 support (#4476)
* add discord auth * add vendor for discord * fix syntax error * make fmt * update version of goth in use * update markbates/goth
This commit is contained in:
		
							parent
							
								
									beab2df122
								
							
						
					
					
						commit
						5c44f751a3
					
				
					 10 changed files with 308 additions and 26 deletions
				
			
		
							
								
								
									
										8
									
								
								Gopkg.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										8
									
								
								Gopkg.lock
									
									
									
										generated
									
									
									
								
							|  | @ -588,12 +588,13 @@ | ||||||
|   revision = "e3534c89ef969912856dfa39e56b09e58c5f5daf" |   revision = "e3534c89ef969912856dfa39e56b09e58c5f5daf" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   digest = "1:4b992ec853d0ea9bac3dcf09a64af61de1a392e6cb0eef2204c0c92f4ae6b911" |   digest = "1:aa7dcd6a0db70d514821f8739d0a22e7df33b499d8d399cf15b2858d44f8319e" | ||||||
|   name = "github.com/markbates/goth" |   name = "github.com/markbates/goth" | ||||||
|   packages = [ |   packages = [ | ||||||
|     ".", |     ".", | ||||||
|     "gothic", |     "gothic", | ||||||
|     "providers/bitbucket", |     "providers/bitbucket", | ||||||
|  |     "providers/discord", | ||||||
|     "providers/dropbox", |     "providers/dropbox", | ||||||
|     "providers/facebook", |     "providers/facebook", | ||||||
|     "providers/github", |     "providers/github", | ||||||
|  | @ -603,8 +604,8 @@ | ||||||
|     "providers/twitter", |     "providers/twitter", | ||||||
|   ] |   ] | ||||||
|   pruneopts = "NUT" |   pruneopts = "NUT" | ||||||
|   revision = "bc6d8ddf751a745f37ca5567dbbfc4157bbf5da9" |   revision = "157987f620ff2fc5e1f6a1427a3685219fbf6ff4" | ||||||
|   version = "v1.47.2" |   version = "v1.49.0" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   digest = "1:c9724c929d27a14475a45b17a267dbc60671c0bc2c5c05ed21f011f7b5bc9fb5" |   digest = "1:c9724c929d27a14475a45b17a267dbc60671c0bc2c5c05ed21f011f7b5bc9fb5" | ||||||
|  | @ -1179,6 +1180,7 @@ | ||||||
|     "github.com/markbates/goth", |     "github.com/markbates/goth", | ||||||
|     "github.com/markbates/goth/gothic", |     "github.com/markbates/goth/gothic", | ||||||
|     "github.com/markbates/goth/providers/bitbucket", |     "github.com/markbates/goth/providers/bitbucket", | ||||||
|  |     "github.com/markbates/goth/providers/discord", | ||||||
|     "github.com/markbates/goth/providers/dropbox", |     "github.com/markbates/goth/providers/dropbox", | ||||||
|     "github.com/markbates/goth/providers/facebook", |     "github.com/markbates/goth/providers/facebook", | ||||||
|     "github.com/markbates/goth/providers/github", |     "github.com/markbates/goth/providers/github", | ||||||
|  |  | ||||||
|  | @ -43,6 +43,7 @@ var OAuth2Providers = map[string]OAuth2Provider{ | ||||||
| 	"gplus":         {Name: "gplus", DisplayName: "Google+", Image: "/img/auth/google_plus.png"}, | 	"gplus":         {Name: "gplus", DisplayName: "Google+", Image: "/img/auth/google_plus.png"}, | ||||||
| 	"openidConnect": {Name: "openidConnect", DisplayName: "OpenID Connect", Image: "/img/auth/openid_connect.png"}, | 	"openidConnect": {Name: "openidConnect", DisplayName: "OpenID Connect", Image: "/img/auth/openid_connect.png"}, | ||||||
| 	"twitter":       {Name: "twitter", DisplayName: "Twitter", Image: "/img/auth/twitter.png"}, | 	"twitter":       {Name: "twitter", DisplayName: "Twitter", Image: "/img/auth/twitter.png"}, | ||||||
|  | 	"discord":       {Name: "discord", DisplayName: "Discord", Image: "/img/auth/discord.png"}, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // OAuth2DefaultCustomURLMappings contains the map of default URL's for OAuth2 providers that are allowed to have custom urls
 | // OAuth2DefaultCustomURLMappings contains the map of default URL's for OAuth2 providers that are allowed to have custom urls
 | ||||||
|  |  | ||||||
|  | @ -16,6 +16,7 @@ import ( | ||||||
| 	"github.com/markbates/goth" | 	"github.com/markbates/goth" | ||||||
| 	"github.com/markbates/goth/gothic" | 	"github.com/markbates/goth/gothic" | ||||||
| 	"github.com/markbates/goth/providers/bitbucket" | 	"github.com/markbates/goth/providers/bitbucket" | ||||||
|  | 	"github.com/markbates/goth/providers/discord" | ||||||
| 	"github.com/markbates/goth/providers/dropbox" | 	"github.com/markbates/goth/providers/dropbox" | ||||||
| 	"github.com/markbates/goth/providers/facebook" | 	"github.com/markbates/goth/providers/facebook" | ||||||
| 	"github.com/markbates/goth/providers/github" | 	"github.com/markbates/goth/providers/github" | ||||||
|  | @ -172,6 +173,8 @@ func createProvider(providerName, providerType, clientID, clientSecret, openIDCo | ||||||
| 		} | 		} | ||||||
| 	case "twitter": | 	case "twitter": | ||||||
| 		provider = twitter.NewAuthenticate(clientID, clientSecret, callbackURL) | 		provider = twitter.NewAuthenticate(clientID, clientSecret, callbackURL) | ||||||
|  | 	case "discord": | ||||||
|  | 		provider = discord.New(clientID, clientSecret, callbackURL, discord.ScopeIdentify, discord.ScopeEmail) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// always set the name if provider is created so we can support multiple setups of 1 provider
 | 	// always set the name if provider is created so we can support multiple setups of 1 provider
 | ||||||
|  |  | ||||||
|  | @ -1523,6 +1523,7 @@ auths.tip.gitlab = Register a new application on https://gitlab.com/profile/appl | ||||||
| auths.tip.google_plus = Obtain OAuth2 client credentials from the Google API console at https://console.developers.google.com/ | auths.tip.google_plus = Obtain OAuth2 client credentials from the Google API console at https://console.developers.google.com/ | ||||||
| auths.tip.openid_connect = Use the OpenID Connect Discovery URL (<server>/.well-known/openid-configuration) to specify the endpoints | auths.tip.openid_connect = Use the OpenID Connect Discovery URL (<server>/.well-known/openid-configuration) to specify the endpoints | ||||||
| auths.tip.twitter = Go to https://dev.twitter.com/apps, create an application and ensure that the “Allow this application to be used to Sign in with Twitter” option is enabled | auths.tip.twitter = Go to https://dev.twitter.com/apps, create an application and ensure that the “Allow this application to be used to Sign in with Twitter” option is enabled | ||||||
|  | auths.tip.discord = Register a new application on https://discordapp.com/developers/applications/me | ||||||
| auths.edit = Edit Authentication Source | auths.edit = Edit Authentication Source | ||||||
| auths.activated = This Authentication Source is Activated | auths.activated = This Authentication Source is Activated | ||||||
| auths.new_success = The authentication '%s' has been added. | auths.new_success = The authentication '%s' has been added. | ||||||
|  |  | ||||||
							
								
								
									
										
											BIN
										
									
								
								public/img/auth/discord.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/img/auth/discord.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 1.5 KiB | 
|  | @ -108,6 +108,8 @@ | ||||||
| 				<span>{{.i18n.Tr "admin.auths.tip.openid_connect"}}</span> | 				<span>{{.i18n.Tr "admin.auths.tip.openid_connect"}}</span> | ||||||
| 				<li>Twitter</li> | 				<li>Twitter</li> | ||||||
| 				<span>{{.i18n.Tr "admin.auths.tip.twitter"}}</span> | 				<span>{{.i18n.Tr "admin.auths.tip.twitter"}}</span> | ||||||
|  | 				<li>Discord</li> | ||||||
|  | 				<span>{{.i18n.Tr "admin.auths.tip.discord"}}</span> | ||||||
| 			</div> | 			</div> | ||||||
| 		</div> | 		</div> | ||||||
| 	</div> | 	</div> | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								vendor/github.com/markbates/goth/gothic/gothic.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/markbates/goth/gothic/gothic.go
									
									
									
										generated
									
									
										vendored
									
									
								
							|  | @ -3,7 +3,7 @@ Package gothic wraps common behaviour when using Goth. This makes it quick, and | ||||||
| and running with Goth. Of course, if you want complete control over how things flow, in regards | and running with Goth. Of course, if you want complete control over how things flow, in regards | ||||||
| to the authentication process, feel free and use Goth directly. | to the authentication process, feel free and use Goth directly. | ||||||
| 
 | 
 | ||||||
| See https://github.com/markbates/goth/examples/main.go to see this in action.
 | See https://github.com/markbates/goth/blob/master/examples/main.go to see this in action.
 | ||||||
| */ | */ | ||||||
| package gothic | package gothic | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										210
									
								
								vendor/github.com/markbates/goth/providers/discord/discord.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								vendor/github.com/markbates/goth/providers/discord/discord.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,210 @@ | ||||||
|  | // Package discord implements the OAuth2 protocol for authenticating users through Discord.
 | ||||||
|  | // This package can be used as a reference implementation of an OAuth2 provider for Discord.
 | ||||||
|  | package discord | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"encoding/json" | ||||||
|  | 	"io" | ||||||
|  | 	"io/ioutil" | ||||||
|  | 
 | ||||||
|  | 	"github.com/markbates/goth" | ||||||
|  | 	"golang.org/x/oauth2" | ||||||
|  | 
 | ||||||
|  | 	"fmt" | ||||||
|  | 	"net/http" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	authURL      string = "https://discordapp.com/api/oauth2/authorize" | ||||||
|  | 	tokenURL     string = "https://discordapp.com/api/oauth2/token" | ||||||
|  | 	userEndpoint string = "https://discordapp.com/api/users/@me" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	// allows /users/@me without email
 | ||||||
|  | 	ScopeIdentify string = "identify" | ||||||
|  | 	// enables /users/@me to return an email
 | ||||||
|  | 	ScopeEmail string = "email" | ||||||
|  | 	// allows /users/@me/connections to return linked Twitch and YouTube accounts
 | ||||||
|  | 	ScopeConnections string = "connections" | ||||||
|  | 	// allows /users/@me/guilds to return basic information about all of a user's guilds
 | ||||||
|  | 	ScopeGuilds string = "guilds" | ||||||
|  | 	// allows /invites/{invite.id} to be used for joining a user's guild
 | ||||||
|  | 	ScopeJoinGuild string = "guilds.join" | ||||||
|  | 	// allows your app to join users to a group dm
 | ||||||
|  | 	ScopeGroupDMjoin string = "gdm.join" | ||||||
|  | 	// for oauth2 bots, this puts the bot in the user's selected guild by default
 | ||||||
|  | 	ScopeBot string = "bot" | ||||||
|  | 	// 	this generates a webhook that is returned in the oauth token response for authorization code grants
 | ||||||
|  | 	ScopeWebhook string = "webhook.incoming" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // New creates a new Discord provider, and sets up important connection details.
 | ||||||
|  | // You should always call `discord.New` to get a new Provider. Never try to create
 | ||||||
|  | // one manually.
 | ||||||
|  | func New(clientKey string, secret string, callbackURL string, scopes ...string) *Provider { | ||||||
|  | 	p := &Provider{ | ||||||
|  | 		ClientKey:    clientKey, | ||||||
|  | 		Secret:       secret, | ||||||
|  | 		CallbackURL:  callbackURL, | ||||||
|  | 		providerName: "discord", | ||||||
|  | 	} | ||||||
|  | 	p.config = newConfig(p, scopes) | ||||||
|  | 	return p | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Provider is the implementation of `goth.Provider` for accessing Discord
 | ||||||
|  | type Provider struct { | ||||||
|  | 	ClientKey    string | ||||||
|  | 	Secret       string | ||||||
|  | 	CallbackURL  string | ||||||
|  | 	HTTPClient   *http.Client | ||||||
|  | 	config       *oauth2.Config | ||||||
|  | 	providerName string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Name gets the name used to retrieve this provider.
 | ||||||
|  | func (p *Provider) Name() string { | ||||||
|  | 	return p.providerName | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SetName is to update the name of the provider (needed in case of multiple providers of 1 type)
 | ||||||
|  | func (p *Provider) SetName(name string) { | ||||||
|  | 	p.providerName = name | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (p *Provider) Client() *http.Client { | ||||||
|  | 	return goth.HTTPClientWithFallBack(p.HTTPClient) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Debug is no-op for the Discord package.
 | ||||||
|  | func (p *Provider) Debug(debug bool) {} | ||||||
|  | 
 | ||||||
|  | // BeginAuth asks Discord for an authentication end-point.
 | ||||||
|  | func (p *Provider) BeginAuth(state string) (goth.Session, error) { | ||||||
|  | 
 | ||||||
|  | 	url := p.config.AuthCodeURL(state, oauth2.AccessTypeOnline) | ||||||
|  | 
 | ||||||
|  | 	s := &Session{ | ||||||
|  | 		AuthURL: url, | ||||||
|  | 	} | ||||||
|  | 	return s, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // FetchUser will go to Discord and access basic info about the user.
 | ||||||
|  | func (p *Provider) FetchUser(session goth.Session) (goth.User, error) { | ||||||
|  | 
 | ||||||
|  | 	s := session.(*Session) | ||||||
|  | 
 | ||||||
|  | 	user := goth.User{ | ||||||
|  | 		AccessToken:  s.AccessToken, | ||||||
|  | 		Provider:     p.Name(), | ||||||
|  | 		RefreshToken: s.RefreshToken, | ||||||
|  | 		ExpiresAt:    s.ExpiresAt, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if user.AccessToken == "" { | ||||||
|  | 		// data is not yet retrieved since accessToken is still empty
 | ||||||
|  | 		return user, fmt.Errorf("%s cannot get user information without accessToken", p.providerName) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	req, err := http.NewRequest("GET", userEndpoint, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return user, err | ||||||
|  | 	} | ||||||
|  | 	req.Header.Set("Accept", "application/json") | ||||||
|  | 	req.Header.Set("Authorization", "Bearer "+s.AccessToken) | ||||||
|  | 	resp, err := p.Client().Do(req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		if resp != nil { | ||||||
|  | 			resp.Body.Close() | ||||||
|  | 		} | ||||||
|  | 		return user, err | ||||||
|  | 	} | ||||||
|  | 	defer resp.Body.Close() | ||||||
|  | 
 | ||||||
|  | 	if resp.StatusCode != http.StatusOK { | ||||||
|  | 		return user, fmt.Errorf("%s responded with a %d trying to fetch user information", p.providerName, resp.StatusCode) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	bits, err := ioutil.ReadAll(resp.Body) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return user, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	err = json.NewDecoder(bytes.NewReader(bits)).Decode(&user.RawData) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return user, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	err = userFromReader(bytes.NewReader(bits), &user) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return user, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return user, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func userFromReader(r io.Reader, user *goth.User) error { | ||||||
|  | 	u := struct { | ||||||
|  | 		Name          string `json:"username"` | ||||||
|  | 		Email         string `json:"email"` | ||||||
|  | 		AvatarID      string `json:"avatar"` | ||||||
|  | 		MFAEnabled    bool   `json:"mfa_enabled"` | ||||||
|  | 		Discriminator string `json:"discriminator"` | ||||||
|  | 		Verified      bool   `json:"verified"` | ||||||
|  | 		ID            string `json:"id"` | ||||||
|  | 	}{} | ||||||
|  | 
 | ||||||
|  | 	err := json.NewDecoder(r).Decode(&u) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	user.Name = u.Name | ||||||
|  | 	user.Email = u.Email | ||||||
|  | 	user.AvatarURL = "https://media.discordapp.net/avatars/" + u.ID + "/" + u.AvatarID + ".jpg" | ||||||
|  | 	user.UserID = u.ID | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func newConfig(p *Provider, scopes []string) *oauth2.Config { | ||||||
|  | 	c := &oauth2.Config{ | ||||||
|  | 		ClientID:     p.ClientKey, | ||||||
|  | 		ClientSecret: p.Secret, | ||||||
|  | 		RedirectURL:  p.CallbackURL, | ||||||
|  | 		Endpoint: oauth2.Endpoint{ | ||||||
|  | 			AuthURL:  authURL, | ||||||
|  | 			TokenURL: tokenURL, | ||||||
|  | 		}, | ||||||
|  | 		Scopes: []string{}, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if len(scopes) > 0 { | ||||||
|  | 		for _, scope := range scopes { | ||||||
|  | 			c.Scopes = append(c.Scopes, scope) | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		c.Scopes = []string{ScopeIdentify} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return c | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //RefreshTokenAvailable refresh token is provided by auth provider or not
 | ||||||
|  | func (p *Provider) RefreshTokenAvailable() bool { | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //RefreshToken get new access token based on the refresh token
 | ||||||
|  | func (p *Provider) RefreshToken(refreshToken string) (*oauth2.Token, error) { | ||||||
|  | 	token := &oauth2.Token{RefreshToken: refreshToken} | ||||||
|  | 	ts := p.config.TokenSource(oauth2.NoContext, token) | ||||||
|  | 	newToken, err := ts.Token() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return newToken, err | ||||||
|  | } | ||||||
							
								
								
									
										65
									
								
								vendor/github.com/markbates/goth/providers/discord/session.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								vendor/github.com/markbates/goth/providers/discord/session.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,65 @@ | ||||||
|  | package discord | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"encoding/json" | ||||||
|  | 	"errors" | ||||||
|  | 	"github.com/markbates/goth" | ||||||
|  | 	"golang.org/x/oauth2" | ||||||
|  | 	"strings" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Session stores data during the auth process with Discord
 | ||||||
|  | type Session struct { | ||||||
|  | 	AuthURL      string | ||||||
|  | 	AccessToken  string | ||||||
|  | 	RefreshToken string | ||||||
|  | 	ExpiresAt    time.Time | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetAuthURL will return the URL set by calling the `BeginAuth` function on
 | ||||||
|  | // the Discord provider.
 | ||||||
|  | func (s Session) GetAuthURL() (string, error) { | ||||||
|  | 	if s.AuthURL == "" { | ||||||
|  | 		return "", errors.New(goth.NoAuthUrlErrorMessage) | ||||||
|  | 	} | ||||||
|  | 	return s.AuthURL, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Authorize completes the authorization with Discord and returns the access
 | ||||||
|  | // token to be stored for future use.
 | ||||||
|  | func (s *Session) Authorize(provider goth.Provider, params goth.Params) (string, error) { | ||||||
|  | 	p := provider.(*Provider) | ||||||
|  | 	token, err := p.config.Exchange(oauth2.NoContext, params.Get("code")) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if !token.Valid() { | ||||||
|  | 		return "", errors.New("Invalid token received from provider") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	s.AccessToken = token.AccessToken | ||||||
|  | 	s.RefreshToken = token.RefreshToken | ||||||
|  | 	s.ExpiresAt = token.Expiry | ||||||
|  | 	return token.AccessToken, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Marshal marshals a session into a JSON string.
 | ||||||
|  | func (s Session) Marshal() string { | ||||||
|  | 	j, _ := json.Marshal(s) | ||||||
|  | 	return string(j) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // String is equivalent to Marshal. It returns a JSON representation of the
 | ||||||
|  | // of the session.
 | ||||||
|  | func (s Session) String() string { | ||||||
|  | 	return s.Marshal() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // UnmarshalSession will unmarshal a JSON string into a session.
 | ||||||
|  | func (p *Provider) UnmarshalSession(data string) (goth.Session, error) { | ||||||
|  | 	s := &Session{} | ||||||
|  | 	err := json.NewDecoder(strings.NewReader(data)).Decode(s) | ||||||
|  | 	return s, err | ||||||
|  | } | ||||||
							
								
								
									
										42
									
								
								vendor/github.com/markbates/goth/providers/facebook/facebook.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/markbates/goth/providers/facebook/facebook.go
									
									
									
										generated
									
									
										vendored
									
									
								
							|  | @ -37,6 +37,7 @@ func New(clientKey, secret, callbackURL string, scopes ...string) *Provider { | ||||||
| 		providerName: "facebook", | 		providerName: "facebook", | ||||||
| 	} | 	} | ||||||
| 	p.config = newConfig(p, scopes) | 	p.config = newConfig(p, scopes) | ||||||
|  | 	p.Fields = "email,first_name,last_name,link,about,id,name,picture,location" | ||||||
| 	return p | 	return p | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -46,6 +47,7 @@ type Provider struct { | ||||||
| 	Secret       string | 	Secret       string | ||||||
| 	CallbackURL  string | 	CallbackURL  string | ||||||
| 	HTTPClient   *http.Client | 	HTTPClient   *http.Client | ||||||
|  | 	Fields       string | ||||||
| 	config       *oauth2.Config | 	config       *oauth2.Config | ||||||
| 	providerName string | 	providerName string | ||||||
| } | } | ||||||
|  | @ -60,6 +62,16 @@ func (p *Provider) SetName(name string) { | ||||||
| 	p.providerName = name | 	p.providerName = name | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // SetCustomFields sets the fields used to return information
 | ||||||
|  | // for a user.
 | ||||||
|  | //
 | ||||||
|  | // A list of available field values can be found at
 | ||||||
|  | // https://developers.facebook.com/docs/graph-api/reference/user
 | ||||||
|  | func (p *Provider) SetCustomFields(fields []string) *Provider { | ||||||
|  | 	p.Fields = strings.Join(fields, ",") | ||||||
|  | 	return p | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (p *Provider) Client() *http.Client { | func (p *Provider) Client() *http.Client { | ||||||
| 	return goth.HTTPClientWithFallBack(p.HTTPClient) | 	return goth.HTTPClientWithFallBack(p.HTTPClient) | ||||||
| } | } | ||||||
|  | @ -99,7 +111,7 @@ func (p *Provider) FetchUser(session goth.Session) (goth.User, error) { | ||||||
| 
 | 
 | ||||||
| 	reqUrl := fmt.Sprint( | 	reqUrl := fmt.Sprint( | ||||||
| 		endpointProfile, | 		endpointProfile, | ||||||
| 		strings.Join(p.config.Scopes, ","), | 		p.Fields, | ||||||
| 		"&access_token=", | 		"&access_token=", | ||||||
| 		url.QueryEscape(sess.AccessToken), | 		url.QueryEscape(sess.AccessToken), | ||||||
| 		"&appsecret_proof=", | 		"&appsecret_proof=", | ||||||
|  | @ -177,31 +189,17 @@ func newConfig(provider *Provider, scopes []string) *oauth2.Config { | ||||||
| 		}, | 		}, | ||||||
| 		Scopes: []string{ | 		Scopes: []string{ | ||||||
| 			"email", | 			"email", | ||||||
| 			"first_name", |  | ||||||
| 			"last_name", |  | ||||||
| 			"link", |  | ||||||
| 			"about", |  | ||||||
| 			"id", |  | ||||||
| 			"name", |  | ||||||
| 			"picture", |  | ||||||
| 			"location", |  | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// creates possibility to invoke field method like 'picture.type(large)'
 | 	defaultScopes := map[string]struct{}{ | ||||||
| 	var found bool | 		"email": {}, | ||||||
| 	for _, sc := range scopes { | 	} | ||||||
| 		sc := sc | 
 | ||||||
| 		for i, defScope := range c.Scopes { | 	for _, scope := range scopes { | ||||||
| 			if defScope == strings.Split(sc, ".")[0] { | 		if _, exists := defaultScopes[scope]; !exists { | ||||||
| 				c.Scopes[i] = sc | 			c.Scopes = append(c.Scopes, scope) | ||||||
| 				found = true |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 		if !found { |  | ||||||
| 			c.Scopes = append(c.Scopes, sc) |  | ||||||
| 		} |  | ||||||
| 		found = false |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return c | 	return c | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue