mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-04 03:42:25 -06:00 
			
		
		
		
	
		
			
	
	
		
			382 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			382 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								// Copyright 2014 The Go Authors. All rights reserved.
							 | 
						||
| 
								 | 
							
								// Use of this source code is governed by a BSD-style
							 | 
						||
| 
								 | 
							
								// license that can be found in the LICENSE file.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Package oauth2 provides support for making
							 | 
						||
| 
								 | 
							
								// OAuth2 authorized and authenticated HTTP requests,
							 | 
						||
| 
								 | 
							
								// as specified in RFC 6749.
							 | 
						||
| 
								 | 
							
								// It can additionally grant authorization with Bearer JWT.
							 | 
						||
| 
								 | 
							
								package oauth2 // import "golang.org/x/oauth2"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import (
							 | 
						||
| 
								 | 
							
									"bytes"
							 | 
						||
| 
								 | 
							
									"context"
							 | 
						||
| 
								 | 
							
									"errors"
							 | 
						||
| 
								 | 
							
									"net/http"
							 | 
						||
| 
								 | 
							
									"net/url"
							 | 
						||
| 
								 | 
							
									"strings"
							 | 
						||
| 
								 | 
							
									"sync"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									"golang.org/x/oauth2/internal"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// NoContext is the default context you should supply if not using
							 | 
						||
| 
								 | 
							
								// your own context.Context (see https://golang.org/x/net/context).
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Deprecated: Use context.Background() or context.TODO() instead.
							 | 
						||
| 
								 | 
							
								var NoContext = context.TODO()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// RegisterBrokenAuthHeaderProvider previously did something. It is now a no-op.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Deprecated: this function no longer does anything. Caller code that
							 | 
						||
| 
								 | 
							
								// wants to avoid potential extra HTTP requests made during
							 | 
						||
| 
								 | 
							
								// auto-probing of the provider's auth style should set
							 | 
						||
| 
								 | 
							
								// Endpoint.AuthStyle.
							 | 
						||
| 
								 | 
							
								func RegisterBrokenAuthHeaderProvider(tokenURL string) {}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Config describes a typical 3-legged OAuth2 flow, with both the
							 | 
						||
| 
								 | 
							
								// client application information and the server's endpoint URLs.
							 | 
						||
| 
								 | 
							
								// For the client credentials 2-legged OAuth2 flow, see the clientcredentials
							 | 
						||
| 
								 | 
							
								// package (https://golang.org/x/oauth2/clientcredentials).
							 | 
						||
| 
								 | 
							
								type Config struct {
							 | 
						||
| 
								 | 
							
									// ClientID is the application's ID.
							 | 
						||
| 
								 | 
							
									ClientID string
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// ClientSecret is the application's secret.
							 | 
						||
| 
								 | 
							
									ClientSecret string
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Endpoint contains the resource server's token endpoint
							 | 
						||
| 
								 | 
							
									// URLs. These are constants specific to each server and are
							 | 
						||
| 
								 | 
							
									// often available via site-specific packages, such as
							 | 
						||
| 
								 | 
							
									// google.Endpoint or github.Endpoint.
							 | 
						||
| 
								 | 
							
									Endpoint Endpoint
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// RedirectURL is the URL to redirect users going through
							 | 
						||
| 
								 | 
							
									// the OAuth flow, after the resource owner's URLs.
							 | 
						||
| 
								 | 
							
									RedirectURL string
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Scope specifies optional requested permissions.
							 | 
						||
| 
								 | 
							
									Scopes []string
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// A TokenSource is anything that can return a token.
							 | 
						||
| 
								 | 
							
								type TokenSource interface {
							 | 
						||
| 
								 | 
							
									// Token returns a token or an error.
							 | 
						||
| 
								 | 
							
									// Token must be safe for concurrent use by multiple goroutines.
							 | 
						||
| 
								 | 
							
									// The returned Token must not be modified.
							 | 
						||
| 
								 | 
							
									Token() (*Token, error)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Endpoint represents an OAuth 2.0 provider's authorization and token
							 | 
						||
| 
								 | 
							
								// endpoint URLs.
							 | 
						||
| 
								 | 
							
								type Endpoint struct {
							 | 
						||
| 
								 | 
							
									AuthURL  string
							 | 
						||
| 
								 | 
							
									TokenURL string
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// AuthStyle optionally specifies how the endpoint wants the
							 | 
						||
| 
								 | 
							
									// client ID & client secret sent. The zero value means to
							 | 
						||
| 
								 | 
							
									// auto-detect.
							 | 
						||
| 
								 | 
							
									AuthStyle AuthStyle
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// AuthStyle represents how requests for tokens are authenticated
							 | 
						||
| 
								 | 
							
								// to the server.
							 | 
						||
| 
								 | 
							
								type AuthStyle int
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const (
							 | 
						||
| 
								 | 
							
									// AuthStyleAutoDetect means to auto-detect which authentication
							 | 
						||
| 
								 | 
							
									// style the provider wants by trying both ways and caching
							 | 
						||
| 
								 | 
							
									// the successful way for the future.
							 | 
						||
| 
								 | 
							
									AuthStyleAutoDetect AuthStyle = 0
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// AuthStyleInParams sends the "client_id" and "client_secret"
							 | 
						||
| 
								 | 
							
									// in the POST body as application/x-www-form-urlencoded parameters.
							 | 
						||
| 
								 | 
							
									AuthStyleInParams AuthStyle = 1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// AuthStyleInHeader sends the client_id and client_password
							 | 
						||
| 
								 | 
							
									// using HTTP Basic Authorization. This is an optional style
							 | 
						||
| 
								 | 
							
									// described in the OAuth2 RFC 6749 section 2.3.1.
							 | 
						||
| 
								 | 
							
									AuthStyleInHeader AuthStyle = 2
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var (
							 | 
						||
| 
								 | 
							
									// AccessTypeOnline and AccessTypeOffline are options passed
							 | 
						||
| 
								 | 
							
									// to the Options.AuthCodeURL method. They modify the
							 | 
						||
| 
								 | 
							
									// "access_type" field that gets sent in the URL returned by
							 | 
						||
| 
								 | 
							
									// AuthCodeURL.
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
									// Online is the default if neither is specified. If your
							 | 
						||
| 
								 | 
							
									// application needs to refresh access tokens when the user
							 | 
						||
| 
								 | 
							
									// is not present at the browser, then use offline. This will
							 | 
						||
| 
								 | 
							
									// result in your application obtaining a refresh token the
							 | 
						||
| 
								 | 
							
									// first time your application exchanges an authorization
							 | 
						||
| 
								 | 
							
									// code for a user.
							 | 
						||
| 
								 | 
							
									AccessTypeOnline  AuthCodeOption = SetAuthURLParam("access_type", "online")
							 | 
						||
| 
								 | 
							
									AccessTypeOffline AuthCodeOption = SetAuthURLParam("access_type", "offline")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// ApprovalForce forces the users to view the consent dialog
							 | 
						||
| 
								 | 
							
									// and confirm the permissions request at the URL returned
							 | 
						||
| 
								 | 
							
									// from AuthCodeURL, even if they've already done so.
							 | 
						||
| 
								 | 
							
									ApprovalForce AuthCodeOption = SetAuthURLParam("prompt", "consent")
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// An AuthCodeOption is passed to Config.AuthCodeURL.
							 | 
						||
| 
								 | 
							
								type AuthCodeOption interface {
							 | 
						||
| 
								 | 
							
									setValue(url.Values)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type setParam struct{ k, v string }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (p setParam) setValue(m url.Values) { m.Set(p.k, p.v) }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// SetAuthURLParam builds an AuthCodeOption which passes key/value parameters
							 | 
						||
| 
								 | 
							
								// to a provider's authorization endpoint.
							 | 
						||
| 
								 | 
							
								func SetAuthURLParam(key, value string) AuthCodeOption {
							 | 
						||
| 
								 | 
							
									return setParam{key, value}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// AuthCodeURL returns a URL to OAuth 2.0 provider's consent page
							 | 
						||
| 
								 | 
							
								// that asks for permissions for the required scopes explicitly.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// State is a token to protect the user from CSRF attacks. You must
							 | 
						||
| 
								 | 
							
								// always provide a non-empty string and validate that it matches the
							 | 
						||
| 
								 | 
							
								// the state query parameter on your redirect callback.
							 | 
						||
| 
								 | 
							
								// See http://tools.ietf.org/html/rfc6749#section-10.12 for more info.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Opts may include AccessTypeOnline or AccessTypeOffline, as well
							 | 
						||
| 
								 | 
							
								// as ApprovalForce.
							 | 
						||
| 
								 | 
							
								// It can also be used to pass the PKCE challenge.
							 | 
						||
| 
								 | 
							
								// See https://www.oauth.com/oauth2-servers/pkce/ for more info.
							 | 
						||
| 
								 | 
							
								func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string {
							 | 
						||
| 
								 | 
							
									var buf bytes.Buffer
							 | 
						||
| 
								 | 
							
									buf.WriteString(c.Endpoint.AuthURL)
							 | 
						||
| 
								 | 
							
									v := url.Values{
							 | 
						||
| 
								 | 
							
										"response_type": {"code"},
							 | 
						||
| 
								 | 
							
										"client_id":     {c.ClientID},
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if c.RedirectURL != "" {
							 | 
						||
| 
								 | 
							
										v.Set("redirect_uri", c.RedirectURL)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if len(c.Scopes) > 0 {
							 | 
						||
| 
								 | 
							
										v.Set("scope", strings.Join(c.Scopes, " "))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if state != "" {
							 | 
						||
| 
								 | 
							
										// TODO(light): Docs say never to omit state; don't allow empty.
							 | 
						||
| 
								 | 
							
										v.Set("state", state)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									for _, opt := range opts {
							 | 
						||
| 
								 | 
							
										opt.setValue(v)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if strings.Contains(c.Endpoint.AuthURL, "?") {
							 | 
						||
| 
								 | 
							
										buf.WriteByte('&')
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
										buf.WriteByte('?')
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									buf.WriteString(v.Encode())
							 | 
						||
| 
								 | 
							
									return buf.String()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// PasswordCredentialsToken converts a resource owner username and password
							 | 
						||
| 
								 | 
							
								// pair into a token.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Per the RFC, this grant type should only be used "when there is a high
							 | 
						||
| 
								 | 
							
								// degree of trust between the resource owner and the client (e.g., the client
							 | 
						||
| 
								 | 
							
								// is part of the device operating system or a highly privileged application),
							 | 
						||
| 
								 | 
							
								// and when other authorization grant types are not available."
							 | 
						||
| 
								 | 
							
								// See https://tools.ietf.org/html/rfc6749#section-4.3 for more info.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// The provided context optionally controls which HTTP client is used. See the HTTPClient variable.
							 | 
						||
| 
								 | 
							
								func (c *Config) PasswordCredentialsToken(ctx context.Context, username, password string) (*Token, error) {
							 | 
						||
| 
								 | 
							
									v := url.Values{
							 | 
						||
| 
								 | 
							
										"grant_type": {"password"},
							 | 
						||
| 
								 | 
							
										"username":   {username},
							 | 
						||
| 
								 | 
							
										"password":   {password},
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if len(c.Scopes) > 0 {
							 | 
						||
| 
								 | 
							
										v.Set("scope", strings.Join(c.Scopes, " "))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return retrieveToken(ctx, c, v)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Exchange converts an authorization code into a token.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// It is used after a resource provider redirects the user back
							 | 
						||
| 
								 | 
							
								// to the Redirect URI (the URL obtained from AuthCodeURL).
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// The provided context optionally controls which HTTP client is used. See the HTTPClient variable.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// The code will be in the *http.Request.FormValue("code"). Before
							 | 
						||
| 
								 | 
							
								// calling Exchange, be sure to validate FormValue("state").
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Opts may include the PKCE verifier code if previously used in AuthCodeURL.
							 | 
						||
| 
								 | 
							
								// See https://www.oauth.com/oauth2-servers/pkce/ for more info.
							 | 
						||
| 
								 | 
							
								func (c *Config) Exchange(ctx context.Context, code string, opts ...AuthCodeOption) (*Token, error) {
							 | 
						||
| 
								 | 
							
									v := url.Values{
							 | 
						||
| 
								 | 
							
										"grant_type": {"authorization_code"},
							 | 
						||
| 
								 | 
							
										"code":       {code},
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if c.RedirectURL != "" {
							 | 
						||
| 
								 | 
							
										v.Set("redirect_uri", c.RedirectURL)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									for _, opt := range opts {
							 | 
						||
| 
								 | 
							
										opt.setValue(v)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return retrieveToken(ctx, c, v)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Client returns an HTTP client using the provided token.
							 | 
						||
| 
								 | 
							
								// The token will auto-refresh as necessary. The underlying
							 | 
						||
| 
								 | 
							
								// HTTP transport will be obtained using the provided context.
							 | 
						||
| 
								 | 
							
								// The returned client and its Transport should not be modified.
							 | 
						||
| 
								 | 
							
								func (c *Config) Client(ctx context.Context, t *Token) *http.Client {
							 | 
						||
| 
								 | 
							
									return NewClient(ctx, c.TokenSource(ctx, t))
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// TokenSource returns a TokenSource that returns t until t expires,
							 | 
						||
| 
								 | 
							
								// automatically refreshing it as necessary using the provided context.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Most users will use Config.Client instead.
							 | 
						||
| 
								 | 
							
								func (c *Config) TokenSource(ctx context.Context, t *Token) TokenSource {
							 | 
						||
| 
								 | 
							
									tkr := &tokenRefresher{
							 | 
						||
| 
								 | 
							
										ctx:  ctx,
							 | 
						||
| 
								 | 
							
										conf: c,
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if t != nil {
							 | 
						||
| 
								 | 
							
										tkr.refreshToken = t.RefreshToken
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return &reuseTokenSource{
							 | 
						||
| 
								 | 
							
										t:   t,
							 | 
						||
| 
								 | 
							
										new: tkr,
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// tokenRefresher is a TokenSource that makes "grant_type"=="refresh_token"
							 | 
						||
| 
								 | 
							
								// HTTP requests to renew a token using a RefreshToken.
							 | 
						||
| 
								 | 
							
								type tokenRefresher struct {
							 | 
						||
| 
								 | 
							
									ctx          context.Context // used to get HTTP requests
							 | 
						||
| 
								 | 
							
									conf         *Config
							 | 
						||
| 
								 | 
							
									refreshToken string
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// WARNING: Token is not safe for concurrent access, as it
							 | 
						||
| 
								 | 
							
								// updates the tokenRefresher's refreshToken field.
							 | 
						||
| 
								 | 
							
								// Within this package, it is used by reuseTokenSource which
							 | 
						||
| 
								 | 
							
								// synchronizes calls to this method with its own mutex.
							 | 
						||
| 
								 | 
							
								func (tf *tokenRefresher) Token() (*Token, error) {
							 | 
						||
| 
								 | 
							
									if tf.refreshToken == "" {
							 | 
						||
| 
								 | 
							
										return nil, errors.New("oauth2: token expired and refresh token is not set")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									tk, err := retrieveToken(tf.ctx, tf.conf, url.Values{
							 | 
						||
| 
								 | 
							
										"grant_type":    {"refresh_token"},
							 | 
						||
| 
								 | 
							
										"refresh_token": {tf.refreshToken},
							 | 
						||
| 
								 | 
							
									})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if tf.refreshToken != tk.RefreshToken {
							 | 
						||
| 
								 | 
							
										tf.refreshToken = tk.RefreshToken
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return tk, err
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// reuseTokenSource is a TokenSource that holds a single token in memory
							 | 
						||
| 
								 | 
							
								// and validates its expiry before each call to retrieve it with
							 | 
						||
| 
								 | 
							
								// Token. If it's expired, it will be auto-refreshed using the
							 | 
						||
| 
								 | 
							
								// new TokenSource.
							 | 
						||
| 
								 | 
							
								type reuseTokenSource struct {
							 | 
						||
| 
								 | 
							
									new TokenSource // called when t is expired.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									mu sync.Mutex // guards t
							 | 
						||
| 
								 | 
							
									t  *Token
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Token returns the current token if it's still valid, else will
							 | 
						||
| 
								 | 
							
								// refresh the current token (using r.Context for HTTP client
							 | 
						||
| 
								 | 
							
								// information) and return the new one.
							 | 
						||
| 
								 | 
							
								func (s *reuseTokenSource) Token() (*Token, error) {
							 | 
						||
| 
								 | 
							
									s.mu.Lock()
							 | 
						||
| 
								 | 
							
									defer s.mu.Unlock()
							 | 
						||
| 
								 | 
							
									if s.t.Valid() {
							 | 
						||
| 
								 | 
							
										return s.t, nil
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									t, err := s.new.Token()
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									s.t = t
							 | 
						||
| 
								 | 
							
									return t, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// StaticTokenSource returns a TokenSource that always returns the same token.
							 | 
						||
| 
								 | 
							
								// Because the provided token t is never refreshed, StaticTokenSource is only
							 | 
						||
| 
								 | 
							
								// useful for tokens that never expire.
							 | 
						||
| 
								 | 
							
								func StaticTokenSource(t *Token) TokenSource {
							 | 
						||
| 
								 | 
							
									return staticTokenSource{t}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// staticTokenSource is a TokenSource that always returns the same Token.
							 | 
						||
| 
								 | 
							
								type staticTokenSource struct {
							 | 
						||
| 
								 | 
							
									t *Token
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (s staticTokenSource) Token() (*Token, error) {
							 | 
						||
| 
								 | 
							
									return s.t, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// HTTPClient is the context key to use with golang.org/x/net/context's
							 | 
						||
| 
								 | 
							
								// WithValue function to associate an *http.Client value with a context.
							 | 
						||
| 
								 | 
							
								var HTTPClient internal.ContextKey
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// NewClient creates an *http.Client from a Context and TokenSource.
							 | 
						||
| 
								 | 
							
								// The returned client is not valid beyond the lifetime of the context.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Note that if a custom *http.Client is provided via the Context it
							 | 
						||
| 
								 | 
							
								// is used only for token acquisition and is not used to configure the
							 | 
						||
| 
								 | 
							
								// *http.Client returned from NewClient.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// As a special case, if src is nil, a non-OAuth2 client is returned
							 | 
						||
| 
								 | 
							
								// using the provided context. This exists to support related OAuth2
							 | 
						||
| 
								 | 
							
								// packages.
							 | 
						||
| 
								 | 
							
								func NewClient(ctx context.Context, src TokenSource) *http.Client {
							 | 
						||
| 
								 | 
							
									if src == nil {
							 | 
						||
| 
								 | 
							
										return internal.ContextClient(ctx)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return &http.Client{
							 | 
						||
| 
								 | 
							
										Transport: &Transport{
							 | 
						||
| 
								 | 
							
											Base:   internal.ContextClient(ctx).Transport,
							 | 
						||
| 
								 | 
							
											Source: ReuseTokenSource(nil, src),
							 | 
						||
| 
								 | 
							
										},
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// ReuseTokenSource returns a TokenSource which repeatedly returns the
							 | 
						||
| 
								 | 
							
								// same token as long as it's valid, starting with t.
							 | 
						||
| 
								 | 
							
								// When its cached token is invalid, a new token is obtained from src.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// ReuseTokenSource is typically used to reuse tokens from a cache
							 | 
						||
| 
								 | 
							
								// (such as a file on disk) between runs of a program, rather than
							 | 
						||
| 
								 | 
							
								// obtaining new tokens unnecessarily.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// The initial token t may be nil, in which case the TokenSource is
							 | 
						||
| 
								 | 
							
								// wrapped in a caching version if it isn't one already. This also
							 | 
						||
| 
								 | 
							
								// means it's always safe to wrap ReuseTokenSource around any other
							 | 
						||
| 
								 | 
							
								// TokenSource without adverse effects.
							 | 
						||
| 
								 | 
							
								func ReuseTokenSource(t *Token, src TokenSource) TokenSource {
							 | 
						||
| 
								 | 
							
									// Don't wrap a reuseTokenSource in itself. That would work,
							 | 
						||
| 
								 | 
							
									// but cause an unnecessary number of mutex operations.
							 | 
						||
| 
								 | 
							
									// Just build the equivalent one.
							 | 
						||
| 
								 | 
							
									if rt, ok := src.(*reuseTokenSource); ok {
							 | 
						||
| 
								 | 
							
										if t == nil {
							 | 
						||
| 
								 | 
							
											// Just use it directly.
							 | 
						||
| 
								 | 
							
											return rt
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										src = rt.new
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return &reuseTokenSource{
							 | 
						||
| 
								 | 
							
										t:   t,
							 | 
						||
| 
								 | 
							
										new: src,
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 |