mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 10:03:42 +08:00 
			
		
		
		
	new driver: kubernetes
Tested with `kind` and GKE. Note: "nodes" shown in `docker buildx ls` are unrelated to Kubernetes "nodes". Probably buildx should come up with an alternative term. Usage: $ kind create cluster $ export KUBECONFIG="$(kind get kubeconfig-path --name="kind")" $ docker buildx create --driver kubernetes --driver-opt replicas=3 --use $ docker buildx build -t foo --load . `--load` loads the image into the local Docker. Driver opts: - `image=IMAGE` - Sets the container image to be used for running buildkit. - `namespace=NS` - Sets the Kubernetes namespace. Defaults to the current namespace. - `replicas=N` - Sets the number of `Pod` replicas. Defaults to 1. - `rootless=(true|false)` - Run the container as a non-root user without `securityContext.privileged`. Defaults to false. - `loadbalance=(sticky|random)` - Load-balancing strategy. If set to "sticky", the pod is chosen using the hash of the context path. Defaults to "sticky" Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
This commit is contained in:
		
							
								
								
									
										13
									
								
								vendor/golang.org/x/oauth2/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								vendor/golang.org/x/oauth2/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
language: go
 | 
			
		||||
 | 
			
		||||
go:
 | 
			
		||||
  - tip
 | 
			
		||||
 | 
			
		||||
install:
 | 
			
		||||
  - export GOPATH="$HOME/gopath"
 | 
			
		||||
  - mkdir -p "$GOPATH/src/golang.org/x"
 | 
			
		||||
  - mv "$TRAVIS_BUILD_DIR" "$GOPATH/src/golang.org/x/oauth2"
 | 
			
		||||
  - go get -v -t -d golang.org/x/oauth2/...
 | 
			
		||||
 | 
			
		||||
script:
 | 
			
		||||
  - go test -v golang.org/x/oauth2/...
 | 
			
		||||
							
								
								
									
										3
									
								
								vendor/golang.org/x/oauth2/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/golang.org/x/oauth2/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
# This source code refers to The Go Authors for copyright purposes.
 | 
			
		||||
# The master list of authors is in the main Go distribution,
 | 
			
		||||
# visible at http://tip.golang.org/AUTHORS.
 | 
			
		||||
							
								
								
									
										26
									
								
								vendor/golang.org/x/oauth2/CONTRIBUTING.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								vendor/golang.org/x/oauth2/CONTRIBUTING.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
# Contributing to Go
 | 
			
		||||
 | 
			
		||||
Go is an open source project.
 | 
			
		||||
 | 
			
		||||
It is the work of hundreds of contributors. We appreciate your help!
 | 
			
		||||
 | 
			
		||||
## Filing issues
 | 
			
		||||
 | 
			
		||||
When [filing an issue](https://github.com/golang/oauth2/issues), make sure to answer these five questions:
 | 
			
		||||
 | 
			
		||||
1.  What version of Go are you using (`go version`)?
 | 
			
		||||
2.  What operating system and processor architecture are you using?
 | 
			
		||||
3.  What did you do?
 | 
			
		||||
4.  What did you expect to see?
 | 
			
		||||
5.  What did you see instead?
 | 
			
		||||
 | 
			
		||||
General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker.
 | 
			
		||||
The gophers there will answer or ask you to file an issue if you've tripped over a bug.
 | 
			
		||||
 | 
			
		||||
## Contributing code
 | 
			
		||||
 | 
			
		||||
Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html)
 | 
			
		||||
before sending patches.
 | 
			
		||||
 | 
			
		||||
Unless otherwise noted, the Go source files are distributed under
 | 
			
		||||
the BSD-style license found in the LICENSE file.
 | 
			
		||||
							
								
								
									
										3
									
								
								vendor/golang.org/x/oauth2/CONTRIBUTORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/golang.org/x/oauth2/CONTRIBUTORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
# This source code was written by the Go contributors.
 | 
			
		||||
# The master list of contributors is in the main Go distribution,
 | 
			
		||||
# visible at http://tip.golang.org/CONTRIBUTORS.
 | 
			
		||||
							
								
								
									
										27
									
								
								vendor/golang.org/x/oauth2/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/golang.org/x/oauth2/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
Copyright (c) 2009 The Go Authors. All rights reserved.
 | 
			
		||||
 | 
			
		||||
Redistribution and use in source and binary forms, with or without
 | 
			
		||||
modification, are permitted provided that the following conditions are
 | 
			
		||||
met:
 | 
			
		||||
 | 
			
		||||
   * Redistributions of source code must retain the above copyright
 | 
			
		||||
notice, this list of conditions and the following disclaimer.
 | 
			
		||||
   * Redistributions in binary form must reproduce the above
 | 
			
		||||
copyright notice, this list of conditions and the following disclaimer
 | 
			
		||||
in the documentation and/or other materials provided with the
 | 
			
		||||
distribution.
 | 
			
		||||
   * Neither the name of Google Inc. nor the names of its
 | 
			
		||||
contributors may be used to endorse or promote products derived from
 | 
			
		||||
this software without specific prior written permission.
 | 
			
		||||
 | 
			
		||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
			
		||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
			
		||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
			
		||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
			
		||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
			
		||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
			
		||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
			
		||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
			
		||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
							
								
								
									
										77
									
								
								vendor/golang.org/x/oauth2/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								vendor/golang.org/x/oauth2/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
			
		||||
# OAuth2 for Go
 | 
			
		||||
 | 
			
		||||
[](https://travis-ci.org/golang/oauth2)
 | 
			
		||||
[](https://godoc.org/golang.org/x/oauth2)
 | 
			
		||||
 | 
			
		||||
oauth2 package contains a client implementation for OAuth 2.0 spec.
 | 
			
		||||
 | 
			
		||||
## Installation
 | 
			
		||||
 | 
			
		||||
~~~~
 | 
			
		||||
go get golang.org/x/oauth2
 | 
			
		||||
~~~~
 | 
			
		||||
 | 
			
		||||
Or you can manually git clone the repository to
 | 
			
		||||
`$(go env GOPATH)/src/golang.org/x/oauth2`.
 | 
			
		||||
 | 
			
		||||
See godoc for further documentation and examples.
 | 
			
		||||
 | 
			
		||||
* [godoc.org/golang.org/x/oauth2](http://godoc.org/golang.org/x/oauth2)
 | 
			
		||||
* [godoc.org/golang.org/x/oauth2/google](http://godoc.org/golang.org/x/oauth2/google)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## App Engine
 | 
			
		||||
 | 
			
		||||
In change 96e89be (March 2015), we removed the `oauth2.Context2` type in favor
 | 
			
		||||
of the [`context.Context`](https://golang.org/x/net/context#Context) type from
 | 
			
		||||
the `golang.org/x/net/context` package
 | 
			
		||||
 | 
			
		||||
This means it's no longer possible to use the "Classic App Engine"
 | 
			
		||||
`appengine.Context` type with the `oauth2` package. (You're using
 | 
			
		||||
Classic App Engine if you import the package `"appengine"`.)
 | 
			
		||||
 | 
			
		||||
To work around this, you may use the new `"google.golang.org/appengine"`
 | 
			
		||||
package. This package has almost the same API as the `"appengine"` package,
 | 
			
		||||
but it can be fetched with `go get` and used on "Managed VMs" and well as
 | 
			
		||||
Classic App Engine.
 | 
			
		||||
 | 
			
		||||
See the [new `appengine` package's readme](https://github.com/golang/appengine#updating-a-go-app-engine-app)
 | 
			
		||||
for information on updating your app.
 | 
			
		||||
 | 
			
		||||
If you don't want to update your entire app to use the new App Engine packages,
 | 
			
		||||
you may use both sets of packages in parallel, using only the new packages
 | 
			
		||||
with the `oauth2` package.
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
import (
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
	"golang.org/x/oauth2"
 | 
			
		||||
	"golang.org/x/oauth2/google"
 | 
			
		||||
	newappengine "google.golang.org/appengine"
 | 
			
		||||
	newurlfetch "google.golang.org/appengine/urlfetch"
 | 
			
		||||
 | 
			
		||||
	"appengine"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func handler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	var c appengine.Context = appengine.NewContext(r)
 | 
			
		||||
	c.Infof("Logging a message with the old package")
 | 
			
		||||
 | 
			
		||||
	var ctx context.Context = newappengine.NewContext(r)
 | 
			
		||||
	client := &http.Client{
 | 
			
		||||
		Transport: &oauth2.Transport{
 | 
			
		||||
			Source: google.AppEngineTokenSource(ctx, "scope"),
 | 
			
		||||
			Base:   &newurlfetch.Transport{Context: ctx},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	client.Get("...")
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Report Issues / Send Patches
 | 
			
		||||
 | 
			
		||||
This repository uses Gerrit for code changes. To learn how to submit changes to
 | 
			
		||||
this repository, see https://golang.org/doc/contribute.html.
 | 
			
		||||
 | 
			
		||||
The main issue tracker for the oauth2 repository is located at
 | 
			
		||||
https://github.com/golang/oauth2/issues.
 | 
			
		||||
							
								
								
									
										89
									
								
								vendor/golang.org/x/oauth2/google/appengine.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								vendor/golang.org/x/oauth2/google/appengine.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
// 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 google
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
	"golang.org/x/oauth2"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// appengineFlex is set at init time by appengineflex_hook.go. If true, we are on App Engine Flex.
 | 
			
		||||
var appengineFlex bool
 | 
			
		||||
 | 
			
		||||
// Set at init time by appengine_hook.go. If nil, we're not on App Engine.
 | 
			
		||||
var appengineTokenFunc func(c context.Context, scopes ...string) (token string, expiry time.Time, err error)
 | 
			
		||||
 | 
			
		||||
// Set at init time by appengine_hook.go. If nil, we're not on App Engine.
 | 
			
		||||
var appengineAppIDFunc func(c context.Context) string
 | 
			
		||||
 | 
			
		||||
// AppEngineTokenSource returns a token source that fetches tokens
 | 
			
		||||
// issued to the current App Engine application's service account.
 | 
			
		||||
// If you are implementing a 3-legged OAuth 2.0 flow on App Engine
 | 
			
		||||
// that involves user accounts, see oauth2.Config instead.
 | 
			
		||||
//
 | 
			
		||||
// The provided context must have come from appengine.NewContext.
 | 
			
		||||
func AppEngineTokenSource(ctx context.Context, scope ...string) oauth2.TokenSource {
 | 
			
		||||
	if appengineTokenFunc == nil {
 | 
			
		||||
		panic("google: AppEngineTokenSource can only be used on App Engine.")
 | 
			
		||||
	}
 | 
			
		||||
	scopes := append([]string{}, scope...)
 | 
			
		||||
	sort.Strings(scopes)
 | 
			
		||||
	return &appEngineTokenSource{
 | 
			
		||||
		ctx:    ctx,
 | 
			
		||||
		scopes: scopes,
 | 
			
		||||
		key:    strings.Join(scopes, " "),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// aeTokens helps the fetched tokens to be reused until their expiration.
 | 
			
		||||
var (
 | 
			
		||||
	aeTokensMu sync.Mutex
 | 
			
		||||
	aeTokens   = make(map[string]*tokenLock) // key is space-separated scopes
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type tokenLock struct {
 | 
			
		||||
	mu sync.Mutex // guards t; held while fetching or updating t
 | 
			
		||||
	t  *oauth2.Token
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type appEngineTokenSource struct {
 | 
			
		||||
	ctx    context.Context
 | 
			
		||||
	scopes []string
 | 
			
		||||
	key    string // to aeTokens map; space-separated scopes
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ts *appEngineTokenSource) Token() (*oauth2.Token, error) {
 | 
			
		||||
	if appengineTokenFunc == nil {
 | 
			
		||||
		panic("google: AppEngineTokenSource can only be used on App Engine.")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	aeTokensMu.Lock()
 | 
			
		||||
	tok, ok := aeTokens[ts.key]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		tok = &tokenLock{}
 | 
			
		||||
		aeTokens[ts.key] = tok
 | 
			
		||||
	}
 | 
			
		||||
	aeTokensMu.Unlock()
 | 
			
		||||
 | 
			
		||||
	tok.mu.Lock()
 | 
			
		||||
	defer tok.mu.Unlock()
 | 
			
		||||
	if tok.t.Valid() {
 | 
			
		||||
		return tok.t, nil
 | 
			
		||||
	}
 | 
			
		||||
	access, exp, err := appengineTokenFunc(ts.ctx, ts.scopes...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	tok.t = &oauth2.Token{
 | 
			
		||||
		AccessToken: access,
 | 
			
		||||
		Expiry:      exp,
 | 
			
		||||
	}
 | 
			
		||||
	return tok.t, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								vendor/golang.org/x/oauth2/google/appengine_hook.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								vendor/golang.org/x/oauth2/google/appengine_hook.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
// Copyright 2015 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.
 | 
			
		||||
 | 
			
		||||
// +build appengine appenginevm
 | 
			
		||||
 | 
			
		||||
package google
 | 
			
		||||
 | 
			
		||||
import "google.golang.org/appengine"
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	appengineTokenFunc = appengine.AccessToken
 | 
			
		||||
	appengineAppIDFunc = appengine.AppID
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								vendor/golang.org/x/oauth2/google/appengineflex_hook.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								vendor/golang.org/x/oauth2/google/appengineflex_hook.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
// Copyright 2015 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.
 | 
			
		||||
 | 
			
		||||
// +build appenginevm
 | 
			
		||||
 | 
			
		||||
package google
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	appengineFlex = true // Flex doesn't support appengine.AccessToken; depend on metadata server.
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										115
									
								
								vendor/golang.org/x/oauth2/google/default.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								vendor/golang.org/x/oauth2/google/default.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,115 @@
 | 
			
		||||
// Copyright 2015 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 google
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"runtime"
 | 
			
		||||
 | 
			
		||||
	"cloud.google.com/go/compute/metadata"
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
	"golang.org/x/oauth2"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// DefaultClient returns an HTTP Client that uses the
 | 
			
		||||
// DefaultTokenSource to obtain authentication credentials.
 | 
			
		||||
func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) {
 | 
			
		||||
	ts, err := DefaultTokenSource(ctx, scope...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return oauth2.NewClient(ctx, ts), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DefaultTokenSource returns the token source for
 | 
			
		||||
// "Application Default Credentials".
 | 
			
		||||
// It is a shortcut for FindDefaultCredentials(ctx, scope).TokenSource.
 | 
			
		||||
func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSource, error) {
 | 
			
		||||
	creds, err := FindDefaultCredentials(ctx, scope...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return creds.TokenSource, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Common implementation for FindDefaultCredentials.
 | 
			
		||||
func findDefaultCredentials(ctx context.Context, scopes []string) (*DefaultCredentials, error) {
 | 
			
		||||
	// First, try the environment variable.
 | 
			
		||||
	const envVar = "GOOGLE_APPLICATION_CREDENTIALS"
 | 
			
		||||
	if filename := os.Getenv(envVar); filename != "" {
 | 
			
		||||
		creds, err := readCredentialsFile(ctx, filename, scopes)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("google: error getting credentials using %v environment variable: %v", envVar, err)
 | 
			
		||||
		}
 | 
			
		||||
		return creds, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Second, try a well-known file.
 | 
			
		||||
	filename := wellKnownFile()
 | 
			
		||||
	if creds, err := readCredentialsFile(ctx, filename, scopes); err == nil {
 | 
			
		||||
		return creds, nil
 | 
			
		||||
	} else if !os.IsNotExist(err) {
 | 
			
		||||
		return nil, fmt.Errorf("google: error getting credentials using well-known file (%v): %v", filename, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Third, if we're on Google App Engine use those credentials.
 | 
			
		||||
	if appengineTokenFunc != nil && !appengineFlex {
 | 
			
		||||
		return &DefaultCredentials{
 | 
			
		||||
			ProjectID:   appengineAppIDFunc(ctx),
 | 
			
		||||
			TokenSource: AppEngineTokenSource(ctx, scopes...),
 | 
			
		||||
		}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Fourth, if we're on Google Compute Engine use the metadata server.
 | 
			
		||||
	if metadata.OnGCE() {
 | 
			
		||||
		id, _ := metadata.ProjectID()
 | 
			
		||||
		return &DefaultCredentials{
 | 
			
		||||
			ProjectID:   id,
 | 
			
		||||
			TokenSource: ComputeTokenSource(""),
 | 
			
		||||
		}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// None are found; return helpful error.
 | 
			
		||||
	const url = "https://developers.google.com/accounts/docs/application-default-credentials"
 | 
			
		||||
	return nil, fmt.Errorf("google: could not find default credentials. See %v for more information.", url)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Common implementation for CredentialsFromJSON.
 | 
			
		||||
func credentialsFromJSON(ctx context.Context, jsonData []byte, scopes []string) (*DefaultCredentials, error) {
 | 
			
		||||
	var f credentialsFile
 | 
			
		||||
	if err := json.Unmarshal(jsonData, &f); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	ts, err := f.tokenSource(ctx, append([]string(nil), scopes...))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return &DefaultCredentials{
 | 
			
		||||
		ProjectID:   f.ProjectID,
 | 
			
		||||
		TokenSource: ts,
 | 
			
		||||
		JSON:        jsonData,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func wellKnownFile() string {
 | 
			
		||||
	const f = "application_default_credentials.json"
 | 
			
		||||
	if runtime.GOOS == "windows" {
 | 
			
		||||
		return filepath.Join(os.Getenv("APPDATA"), "gcloud", f)
 | 
			
		||||
	}
 | 
			
		||||
	return filepath.Join(guessUnixHomeDir(), ".config", "gcloud", f)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func readCredentialsFile(ctx context.Context, filename string, scopes []string) (*DefaultCredentials, error) {
 | 
			
		||||
	b, err := ioutil.ReadFile(filename)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return CredentialsFromJSON(ctx, b, scopes...)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								vendor/golang.org/x/oauth2/google/doc_go19.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/golang.org/x/oauth2/google/doc_go19.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
// Copyright 2018 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.
 | 
			
		||||
 | 
			
		||||
// +build go1.9
 | 
			
		||||
 | 
			
		||||
// Package google provides support for making OAuth2 authorized and authenticated
 | 
			
		||||
// HTTP requests to Google APIs. It supports the Web server flow, client-side
 | 
			
		||||
// credentials, service accounts, Google Compute Engine service accounts, and Google
 | 
			
		||||
// App Engine service accounts.
 | 
			
		||||
//
 | 
			
		||||
// A brief overview of the package follows. For more information, please read
 | 
			
		||||
// https://developers.google.com/accounts/docs/OAuth2
 | 
			
		||||
// and
 | 
			
		||||
// https://developers.google.com/accounts/docs/application-default-credentials.
 | 
			
		||||
//
 | 
			
		||||
// OAuth2 Configs
 | 
			
		||||
//
 | 
			
		||||
// Two functions in this package return golang.org/x/oauth2.Config values from Google credential
 | 
			
		||||
// data. Google supports two JSON formats for OAuth2 credentials: one is handled by ConfigFromJSON,
 | 
			
		||||
// the other by JWTConfigFromJSON. The returned Config can be used to obtain a TokenSource or
 | 
			
		||||
// create an http.Client.
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
// Credentials
 | 
			
		||||
//
 | 
			
		||||
// The Credentials type represents Google credentials, including Application Default
 | 
			
		||||
// Credentials.
 | 
			
		||||
//
 | 
			
		||||
// Use FindDefaultCredentials to obtain Application Default Credentials.
 | 
			
		||||
// FindDefaultCredentials looks in some well-known places for a credentials file, and
 | 
			
		||||
// will call AppEngineTokenSource or ComputeTokenSource as needed.
 | 
			
		||||
//
 | 
			
		||||
// DefaultClient and DefaultTokenSource are convenience methods. They first call FindDefaultCredentials,
 | 
			
		||||
// then use the credentials to construct an http.Client or an oauth2.TokenSource.
 | 
			
		||||
//
 | 
			
		||||
// Use CredentialsFromJSON to obtain credentials from either of the two JSON formats
 | 
			
		||||
// described in OAuth2 Configs, above. The TokenSource in the returned value is the
 | 
			
		||||
// same as the one obtained from the oauth2.Config returned from ConfigFromJSON or
 | 
			
		||||
// JWTConfigFromJSON, but the Credentials may contain additional information
 | 
			
		||||
// that is useful is some circumstances.
 | 
			
		||||
package google // import "golang.org/x/oauth2/google"
 | 
			
		||||
							
								
								
									
										43
									
								
								vendor/golang.org/x/oauth2/google/doc_not_go19.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								vendor/golang.org/x/oauth2/google/doc_not_go19.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
// Copyright 2018 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.
 | 
			
		||||
 | 
			
		||||
// +build !go1.9
 | 
			
		||||
 | 
			
		||||
// Package google provides support for making OAuth2 authorized and authenticated
 | 
			
		||||
// HTTP requests to Google APIs. It supports the Web server flow, client-side
 | 
			
		||||
// credentials, service accounts, Google Compute Engine service accounts, and Google
 | 
			
		||||
// App Engine service accounts.
 | 
			
		||||
//
 | 
			
		||||
// A brief overview of the package follows. For more information, please read
 | 
			
		||||
// https://developers.google.com/accounts/docs/OAuth2
 | 
			
		||||
// and
 | 
			
		||||
// https://developers.google.com/accounts/docs/application-default-credentials.
 | 
			
		||||
//
 | 
			
		||||
// OAuth2 Configs
 | 
			
		||||
//
 | 
			
		||||
// Two functions in this package return golang.org/x/oauth2.Config values from Google credential
 | 
			
		||||
// data. Google supports two JSON formats for OAuth2 credentials: one is handled by ConfigFromJSON,
 | 
			
		||||
// the other by JWTConfigFromJSON. The returned Config can be used to obtain a TokenSource or
 | 
			
		||||
// create an http.Client.
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
// Credentials
 | 
			
		||||
//
 | 
			
		||||
// The DefaultCredentials type represents Google Application Default Credentials, as
 | 
			
		||||
// well as other forms of credential.
 | 
			
		||||
//
 | 
			
		||||
// Use FindDefaultCredentials to obtain Application Default Credentials.
 | 
			
		||||
// FindDefaultCredentials looks in some well-known places for a credentials file, and
 | 
			
		||||
// will call AppEngineTokenSource or ComputeTokenSource as needed.
 | 
			
		||||
//
 | 
			
		||||
// DefaultClient and DefaultTokenSource are convenience methods. They first call FindDefaultCredentials,
 | 
			
		||||
// then use the credentials to construct an http.Client or an oauth2.TokenSource.
 | 
			
		||||
//
 | 
			
		||||
// Use CredentialsFromJSON to obtain credentials from either of the two JSON
 | 
			
		||||
// formats described in OAuth2 Configs, above. (The DefaultCredentials returned may
 | 
			
		||||
// not be "Application Default Credentials".) The TokenSource in the returned value
 | 
			
		||||
// is the same as the one obtained from the oauth2.Config returned from
 | 
			
		||||
// ConfigFromJSON or JWTConfigFromJSON, but the DefaultCredentials may contain
 | 
			
		||||
// additional information that is useful is some circumstances.
 | 
			
		||||
package google // import "golang.org/x/oauth2/google"
 | 
			
		||||
							
								
								
									
										57
									
								
								vendor/golang.org/x/oauth2/google/go19.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								vendor/golang.org/x/oauth2/google/go19.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
// Copyright 2018 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.
 | 
			
		||||
 | 
			
		||||
// +build go1.9
 | 
			
		||||
 | 
			
		||||
package google
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
	"golang.org/x/oauth2"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Credentials holds Google credentials, including "Application Default Credentials".
 | 
			
		||||
// For more details, see:
 | 
			
		||||
// https://developers.google.com/accounts/docs/application-default-credentials
 | 
			
		||||
type Credentials struct {
 | 
			
		||||
	ProjectID   string // may be empty
 | 
			
		||||
	TokenSource oauth2.TokenSource
 | 
			
		||||
 | 
			
		||||
	// JSON contains the raw bytes from a JSON credentials file.
 | 
			
		||||
	// This field may be nil if authentication is provided by the
 | 
			
		||||
	// environment and not with a credentials file, e.g. when code is
 | 
			
		||||
	// running on Google Cloud Platform.
 | 
			
		||||
	JSON []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DefaultCredentials is the old name of Credentials.
 | 
			
		||||
//
 | 
			
		||||
// Deprecated: use Credentials instead.
 | 
			
		||||
type DefaultCredentials = Credentials
 | 
			
		||||
 | 
			
		||||
// FindDefaultCredentials searches for "Application Default Credentials".
 | 
			
		||||
//
 | 
			
		||||
// It looks for credentials in the following places,
 | 
			
		||||
// preferring the first location found:
 | 
			
		||||
//
 | 
			
		||||
//   1. A JSON file whose path is specified by the
 | 
			
		||||
//      GOOGLE_APPLICATION_CREDENTIALS environment variable.
 | 
			
		||||
//   2. A JSON file in a location known to the gcloud command-line tool.
 | 
			
		||||
//      On Windows, this is %APPDATA%/gcloud/application_default_credentials.json.
 | 
			
		||||
//      On other systems, $HOME/.config/gcloud/application_default_credentials.json.
 | 
			
		||||
//   3. On Google App Engine it uses the appengine.AccessToken function.
 | 
			
		||||
//   4. On Google Compute Engine and Google App Engine Managed VMs, it fetches
 | 
			
		||||
//      credentials from the metadata server.
 | 
			
		||||
//      (In this final case any provided scopes are ignored.)
 | 
			
		||||
func FindDefaultCredentials(ctx context.Context, scopes ...string) (*Credentials, error) {
 | 
			
		||||
	return findDefaultCredentials(ctx, scopes)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CredentialsFromJSON obtains Google credentials from a JSON value. The JSON can
 | 
			
		||||
// represent either a Google Developers Console client_credentials.json file (as in
 | 
			
		||||
// ConfigFromJSON) or a Google Developers service account key file (as in
 | 
			
		||||
// JWTConfigFromJSON).
 | 
			
		||||
func CredentialsFromJSON(ctx context.Context, jsonData []byte, scopes ...string) (*Credentials, error) {
 | 
			
		||||
	return credentialsFromJSON(ctx, jsonData, scopes)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										192
									
								
								vendor/golang.org/x/oauth2/google/google.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								vendor/golang.org/x/oauth2/google/google.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,192 @@
 | 
			
		||||
// 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 google
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"cloud.google.com/go/compute/metadata"
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
	"golang.org/x/oauth2"
 | 
			
		||||
	"golang.org/x/oauth2/jwt"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Endpoint is Google's OAuth 2.0 endpoint.
 | 
			
		||||
var Endpoint = oauth2.Endpoint{
 | 
			
		||||
	AuthURL:  "https://accounts.google.com/o/oauth2/auth",
 | 
			
		||||
	TokenURL: "https://accounts.google.com/o/oauth2/token",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// JWTTokenURL is Google's OAuth 2.0 token URL to use with the JWT flow.
 | 
			
		||||
const JWTTokenURL = "https://accounts.google.com/o/oauth2/token"
 | 
			
		||||
 | 
			
		||||
// ConfigFromJSON uses a Google Developers Console client_credentials.json
 | 
			
		||||
// file to construct a config.
 | 
			
		||||
// client_credentials.json can be downloaded from
 | 
			
		||||
// https://console.developers.google.com, under "Credentials". Download the Web
 | 
			
		||||
// application credentials in the JSON format and provide the contents of the
 | 
			
		||||
// file as jsonKey.
 | 
			
		||||
func ConfigFromJSON(jsonKey []byte, scope ...string) (*oauth2.Config, error) {
 | 
			
		||||
	type cred struct {
 | 
			
		||||
		ClientID     string   `json:"client_id"`
 | 
			
		||||
		ClientSecret string   `json:"client_secret"`
 | 
			
		||||
		RedirectURIs []string `json:"redirect_uris"`
 | 
			
		||||
		AuthURI      string   `json:"auth_uri"`
 | 
			
		||||
		TokenURI     string   `json:"token_uri"`
 | 
			
		||||
	}
 | 
			
		||||
	var j struct {
 | 
			
		||||
		Web       *cred `json:"web"`
 | 
			
		||||
		Installed *cred `json:"installed"`
 | 
			
		||||
	}
 | 
			
		||||
	if err := json.Unmarshal(jsonKey, &j); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	var c *cred
 | 
			
		||||
	switch {
 | 
			
		||||
	case j.Web != nil:
 | 
			
		||||
		c = j.Web
 | 
			
		||||
	case j.Installed != nil:
 | 
			
		||||
		c = j.Installed
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, fmt.Errorf("oauth2/google: no credentials found")
 | 
			
		||||
	}
 | 
			
		||||
	if len(c.RedirectURIs) < 1 {
 | 
			
		||||
		return nil, errors.New("oauth2/google: missing redirect URL in the client_credentials.json")
 | 
			
		||||
	}
 | 
			
		||||
	return &oauth2.Config{
 | 
			
		||||
		ClientID:     c.ClientID,
 | 
			
		||||
		ClientSecret: c.ClientSecret,
 | 
			
		||||
		RedirectURL:  c.RedirectURIs[0],
 | 
			
		||||
		Scopes:       scope,
 | 
			
		||||
		Endpoint: oauth2.Endpoint{
 | 
			
		||||
			AuthURL:  c.AuthURI,
 | 
			
		||||
			TokenURL: c.TokenURI,
 | 
			
		||||
		},
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// JWTConfigFromJSON uses a Google Developers service account JSON key file to read
 | 
			
		||||
// the credentials that authorize and authenticate the requests.
 | 
			
		||||
// Create a service account on "Credentials" for your project at
 | 
			
		||||
// https://console.developers.google.com to download a JSON key file.
 | 
			
		||||
func JWTConfigFromJSON(jsonKey []byte, scope ...string) (*jwt.Config, error) {
 | 
			
		||||
	var f credentialsFile
 | 
			
		||||
	if err := json.Unmarshal(jsonKey, &f); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if f.Type != serviceAccountKey {
 | 
			
		||||
		return nil, fmt.Errorf("google: read JWT from JSON credentials: 'type' field is %q (expected %q)", f.Type, serviceAccountKey)
 | 
			
		||||
	}
 | 
			
		||||
	scope = append([]string(nil), scope...) // copy
 | 
			
		||||
	return f.jwtConfig(scope), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// JSON key file types.
 | 
			
		||||
const (
 | 
			
		||||
	serviceAccountKey  = "service_account"
 | 
			
		||||
	userCredentialsKey = "authorized_user"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// credentialsFile is the unmarshalled representation of a credentials file.
 | 
			
		||||
type credentialsFile struct {
 | 
			
		||||
	Type string `json:"type"` // serviceAccountKey or userCredentialsKey
 | 
			
		||||
 | 
			
		||||
	// Service Account fields
 | 
			
		||||
	ClientEmail  string `json:"client_email"`
 | 
			
		||||
	PrivateKeyID string `json:"private_key_id"`
 | 
			
		||||
	PrivateKey   string `json:"private_key"`
 | 
			
		||||
	TokenURL     string `json:"token_uri"`
 | 
			
		||||
	ProjectID    string `json:"project_id"`
 | 
			
		||||
 | 
			
		||||
	// User Credential fields
 | 
			
		||||
	// (These typically come from gcloud auth.)
 | 
			
		||||
	ClientSecret string `json:"client_secret"`
 | 
			
		||||
	ClientID     string `json:"client_id"`
 | 
			
		||||
	RefreshToken string `json:"refresh_token"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *credentialsFile) jwtConfig(scopes []string) *jwt.Config {
 | 
			
		||||
	cfg := &jwt.Config{
 | 
			
		||||
		Email:        f.ClientEmail,
 | 
			
		||||
		PrivateKey:   []byte(f.PrivateKey),
 | 
			
		||||
		PrivateKeyID: f.PrivateKeyID,
 | 
			
		||||
		Scopes:       scopes,
 | 
			
		||||
		TokenURL:     f.TokenURL,
 | 
			
		||||
	}
 | 
			
		||||
	if cfg.TokenURL == "" {
 | 
			
		||||
		cfg.TokenURL = JWTTokenURL
 | 
			
		||||
	}
 | 
			
		||||
	return cfg
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *credentialsFile) tokenSource(ctx context.Context, scopes []string) (oauth2.TokenSource, error) {
 | 
			
		||||
	switch f.Type {
 | 
			
		||||
	case serviceAccountKey:
 | 
			
		||||
		cfg := f.jwtConfig(scopes)
 | 
			
		||||
		return cfg.TokenSource(ctx), nil
 | 
			
		||||
	case userCredentialsKey:
 | 
			
		||||
		cfg := &oauth2.Config{
 | 
			
		||||
			ClientID:     f.ClientID,
 | 
			
		||||
			ClientSecret: f.ClientSecret,
 | 
			
		||||
			Scopes:       scopes,
 | 
			
		||||
			Endpoint:     Endpoint,
 | 
			
		||||
		}
 | 
			
		||||
		tok := &oauth2.Token{RefreshToken: f.RefreshToken}
 | 
			
		||||
		return cfg.TokenSource(ctx, tok), nil
 | 
			
		||||
	case "":
 | 
			
		||||
		return nil, errors.New("missing 'type' field in credentials")
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, fmt.Errorf("unknown credential type: %q", f.Type)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ComputeTokenSource returns a token source that fetches access tokens
 | 
			
		||||
// from Google Compute Engine (GCE)'s metadata server. It's only valid to use
 | 
			
		||||
// this token source if your program is running on a GCE instance.
 | 
			
		||||
// If no account is specified, "default" is used.
 | 
			
		||||
// Further information about retrieving access tokens from the GCE metadata
 | 
			
		||||
// server can be found at https://cloud.google.com/compute/docs/authentication.
 | 
			
		||||
func ComputeTokenSource(account string) oauth2.TokenSource {
 | 
			
		||||
	return oauth2.ReuseTokenSource(nil, computeSource{account: account})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type computeSource struct {
 | 
			
		||||
	account string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (cs computeSource) Token() (*oauth2.Token, error) {
 | 
			
		||||
	if !metadata.OnGCE() {
 | 
			
		||||
		return nil, errors.New("oauth2/google: can't get a token from the metadata service; not running on GCE")
 | 
			
		||||
	}
 | 
			
		||||
	acct := cs.account
 | 
			
		||||
	if acct == "" {
 | 
			
		||||
		acct = "default"
 | 
			
		||||
	}
 | 
			
		||||
	tokenJSON, err := metadata.Get("instance/service-accounts/" + acct + "/token")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	var res struct {
 | 
			
		||||
		AccessToken  string `json:"access_token"`
 | 
			
		||||
		ExpiresInSec int    `json:"expires_in"`
 | 
			
		||||
		TokenType    string `json:"token_type"`
 | 
			
		||||
	}
 | 
			
		||||
	err = json.NewDecoder(strings.NewReader(tokenJSON)).Decode(&res)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("oauth2/google: invalid token JSON from metadata: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if res.ExpiresInSec == 0 || res.AccessToken == "" {
 | 
			
		||||
		return nil, fmt.Errorf("oauth2/google: incomplete token received from metadata")
 | 
			
		||||
	}
 | 
			
		||||
	return &oauth2.Token{
 | 
			
		||||
		AccessToken: res.AccessToken,
 | 
			
		||||
		TokenType:   res.TokenType,
 | 
			
		||||
		Expiry:      time.Now().Add(time.Duration(res.ExpiresInSec) * time.Second),
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								vendor/golang.org/x/oauth2/google/jwt.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								vendor/golang.org/x/oauth2/google/jwt.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
			
		||||
// Copyright 2015 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 google
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/rsa"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/oauth2"
 | 
			
		||||
	"golang.org/x/oauth2/internal"
 | 
			
		||||
	"golang.org/x/oauth2/jws"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// JWTAccessTokenSourceFromJSON uses a Google Developers service account JSON
 | 
			
		||||
// key file to read the credentials that authorize and authenticate the
 | 
			
		||||
// requests, and returns a TokenSource that does not use any OAuth2 flow but
 | 
			
		||||
// instead creates a JWT and sends that as the access token.
 | 
			
		||||
// The audience is typically a URL that specifies the scope of the credentials.
 | 
			
		||||
//
 | 
			
		||||
// Note that this is not a standard OAuth flow, but rather an
 | 
			
		||||
// optimization supported by a few Google services.
 | 
			
		||||
// Unless you know otherwise, you should use JWTConfigFromJSON instead.
 | 
			
		||||
func JWTAccessTokenSourceFromJSON(jsonKey []byte, audience string) (oauth2.TokenSource, error) {
 | 
			
		||||
	cfg, err := JWTConfigFromJSON(jsonKey)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("google: could not parse JSON key: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	pk, err := internal.ParseKey(cfg.PrivateKey)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("google: could not parse key: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	ts := &jwtAccessTokenSource{
 | 
			
		||||
		email:    cfg.Email,
 | 
			
		||||
		audience: audience,
 | 
			
		||||
		pk:       pk,
 | 
			
		||||
		pkID:     cfg.PrivateKeyID,
 | 
			
		||||
	}
 | 
			
		||||
	tok, err := ts.Token()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return oauth2.ReuseTokenSource(tok, ts), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type jwtAccessTokenSource struct {
 | 
			
		||||
	email, audience string
 | 
			
		||||
	pk              *rsa.PrivateKey
 | 
			
		||||
	pkID            string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ts *jwtAccessTokenSource) Token() (*oauth2.Token, error) {
 | 
			
		||||
	iat := time.Now()
 | 
			
		||||
	exp := iat.Add(time.Hour)
 | 
			
		||||
	cs := &jws.ClaimSet{
 | 
			
		||||
		Iss: ts.email,
 | 
			
		||||
		Sub: ts.email,
 | 
			
		||||
		Aud: ts.audience,
 | 
			
		||||
		Iat: iat.Unix(),
 | 
			
		||||
		Exp: exp.Unix(),
 | 
			
		||||
	}
 | 
			
		||||
	hdr := &jws.Header{
 | 
			
		||||
		Algorithm: "RS256",
 | 
			
		||||
		Typ:       "JWT",
 | 
			
		||||
		KeyID:     string(ts.pkID),
 | 
			
		||||
	}
 | 
			
		||||
	msg, err := jws.Encode(hdr, cs, ts.pk)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("google: could not encode JWT: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	return &oauth2.Token{AccessToken: msg, TokenType: "Bearer", Expiry: exp}, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										54
									
								
								vendor/golang.org/x/oauth2/google/not_go19.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								vendor/golang.org/x/oauth2/google/not_go19.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
// Copyright 2018 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.
 | 
			
		||||
 | 
			
		||||
// +build !go1.9
 | 
			
		||||
 | 
			
		||||
package google
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
	"golang.org/x/oauth2"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// DefaultCredentials holds Google credentials, including "Application Default Credentials".
 | 
			
		||||
// For more details, see:
 | 
			
		||||
// https://developers.google.com/accounts/docs/application-default-credentials
 | 
			
		||||
type DefaultCredentials struct {
 | 
			
		||||
	ProjectID   string // may be empty
 | 
			
		||||
	TokenSource oauth2.TokenSource
 | 
			
		||||
 | 
			
		||||
	// JSON contains the raw bytes from a JSON credentials file.
 | 
			
		||||
	// This field may be nil if authentication is provided by the
 | 
			
		||||
	// environment and not with a credentials file, e.g. when code is
 | 
			
		||||
	// running on Google Cloud Platform.
 | 
			
		||||
	JSON []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FindDefaultCredentials searches for "Application Default Credentials".
 | 
			
		||||
//
 | 
			
		||||
// It looks for credentials in the following places,
 | 
			
		||||
// preferring the first location found:
 | 
			
		||||
//
 | 
			
		||||
//   1. A JSON file whose path is specified by the
 | 
			
		||||
//      GOOGLE_APPLICATION_CREDENTIALS environment variable.
 | 
			
		||||
//   2. A JSON file in a location known to the gcloud command-line tool.
 | 
			
		||||
//      On Windows, this is %APPDATA%/gcloud/application_default_credentials.json.
 | 
			
		||||
//      On other systems, $HOME/.config/gcloud/application_default_credentials.json.
 | 
			
		||||
//   3. On Google App Engine it uses the appengine.AccessToken function.
 | 
			
		||||
//   4. On Google Compute Engine and Google App Engine Managed VMs, it fetches
 | 
			
		||||
//      credentials from the metadata server.
 | 
			
		||||
//      (In this final case any provided scopes are ignored.)
 | 
			
		||||
func FindDefaultCredentials(ctx context.Context, scopes ...string) (*DefaultCredentials, error) {
 | 
			
		||||
	return findDefaultCredentials(ctx, scopes)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CredentialsFromJSON obtains Google credentials from a JSON value. The JSON can
 | 
			
		||||
// represent either a Google Developers Console client_credentials.json file (as in
 | 
			
		||||
// ConfigFromJSON) or a Google Developers service account key file (as in
 | 
			
		||||
// JWTConfigFromJSON).
 | 
			
		||||
//
 | 
			
		||||
// Note: despite the name, the returned credentials may not be Application Default Credentials.
 | 
			
		||||
func CredentialsFromJSON(ctx context.Context, jsonData []byte, scopes ...string) (*DefaultCredentials, error) {
 | 
			
		||||
	return credentialsFromJSON(ctx, jsonData, scopes)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										201
									
								
								vendor/golang.org/x/oauth2/google/sdk.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								vendor/golang.org/x/oauth2/google/sdk.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,201 @@
 | 
			
		||||
// Copyright 2015 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 google
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/user"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
	"golang.org/x/oauth2"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type sdkCredentials struct {
 | 
			
		||||
	Data []struct {
 | 
			
		||||
		Credential struct {
 | 
			
		||||
			ClientID     string     `json:"client_id"`
 | 
			
		||||
			ClientSecret string     `json:"client_secret"`
 | 
			
		||||
			AccessToken  string     `json:"access_token"`
 | 
			
		||||
			RefreshToken string     `json:"refresh_token"`
 | 
			
		||||
			TokenExpiry  *time.Time `json:"token_expiry"`
 | 
			
		||||
		} `json:"credential"`
 | 
			
		||||
		Key struct {
 | 
			
		||||
			Account string `json:"account"`
 | 
			
		||||
			Scope   string `json:"scope"`
 | 
			
		||||
		} `json:"key"`
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// An SDKConfig provides access to tokens from an account already
 | 
			
		||||
// authorized via the Google Cloud SDK.
 | 
			
		||||
type SDKConfig struct {
 | 
			
		||||
	conf         oauth2.Config
 | 
			
		||||
	initialToken *oauth2.Token
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewSDKConfig creates an SDKConfig for the given Google Cloud SDK
 | 
			
		||||
// account. If account is empty, the account currently active in
 | 
			
		||||
// Google Cloud SDK properties is used.
 | 
			
		||||
// Google Cloud SDK credentials must be created by running `gcloud auth`
 | 
			
		||||
// before using this function.
 | 
			
		||||
// The Google Cloud SDK is available at https://cloud.google.com/sdk/.
 | 
			
		||||
func NewSDKConfig(account string) (*SDKConfig, error) {
 | 
			
		||||
	configPath, err := sdkConfigPath()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("oauth2/google: error getting SDK config path: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	credentialsPath := filepath.Join(configPath, "credentials")
 | 
			
		||||
	f, err := os.Open(credentialsPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("oauth2/google: failed to load SDK credentials: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	defer f.Close()
 | 
			
		||||
 | 
			
		||||
	var c sdkCredentials
 | 
			
		||||
	if err := json.NewDecoder(f).Decode(&c); err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("oauth2/google: failed to decode SDK credentials from %q: %v", credentialsPath, err)
 | 
			
		||||
	}
 | 
			
		||||
	if len(c.Data) == 0 {
 | 
			
		||||
		return nil, fmt.Errorf("oauth2/google: no credentials found in %q, run `gcloud auth login` to create one", credentialsPath)
 | 
			
		||||
	}
 | 
			
		||||
	if account == "" {
 | 
			
		||||
		propertiesPath := filepath.Join(configPath, "properties")
 | 
			
		||||
		f, err := os.Open(propertiesPath)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("oauth2/google: failed to load SDK properties: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
		defer f.Close()
 | 
			
		||||
		ini, err := parseINI(f)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("oauth2/google: failed to parse SDK properties %q: %v", propertiesPath, err)
 | 
			
		||||
		}
 | 
			
		||||
		core, ok := ini["core"]
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return nil, fmt.Errorf("oauth2/google: failed to find [core] section in %v", ini)
 | 
			
		||||
		}
 | 
			
		||||
		active, ok := core["account"]
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return nil, fmt.Errorf("oauth2/google: failed to find %q attribute in %v", "account", core)
 | 
			
		||||
		}
 | 
			
		||||
		account = active
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, d := range c.Data {
 | 
			
		||||
		if account == "" || d.Key.Account == account {
 | 
			
		||||
			if d.Credential.AccessToken == "" && d.Credential.RefreshToken == "" {
 | 
			
		||||
				return nil, fmt.Errorf("oauth2/google: no token available for account %q", account)
 | 
			
		||||
			}
 | 
			
		||||
			var expiry time.Time
 | 
			
		||||
			if d.Credential.TokenExpiry != nil {
 | 
			
		||||
				expiry = *d.Credential.TokenExpiry
 | 
			
		||||
			}
 | 
			
		||||
			return &SDKConfig{
 | 
			
		||||
				conf: oauth2.Config{
 | 
			
		||||
					ClientID:     d.Credential.ClientID,
 | 
			
		||||
					ClientSecret: d.Credential.ClientSecret,
 | 
			
		||||
					Scopes:       strings.Split(d.Key.Scope, " "),
 | 
			
		||||
					Endpoint:     Endpoint,
 | 
			
		||||
					RedirectURL:  "oob",
 | 
			
		||||
				},
 | 
			
		||||
				initialToken: &oauth2.Token{
 | 
			
		||||
					AccessToken:  d.Credential.AccessToken,
 | 
			
		||||
					RefreshToken: d.Credential.RefreshToken,
 | 
			
		||||
					Expiry:       expiry,
 | 
			
		||||
				},
 | 
			
		||||
			}, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil, fmt.Errorf("oauth2/google: no such credentials for account %q", account)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Client returns an HTTP client using Google Cloud SDK credentials to
 | 
			
		||||
// authorize requests. The token will auto-refresh as necessary. The
 | 
			
		||||
// underlying http.RoundTripper will be obtained using the provided
 | 
			
		||||
// context. The returned client and its Transport should not be
 | 
			
		||||
// modified.
 | 
			
		||||
func (c *SDKConfig) Client(ctx context.Context) *http.Client {
 | 
			
		||||
	return &http.Client{
 | 
			
		||||
		Transport: &oauth2.Transport{
 | 
			
		||||
			Source: c.TokenSource(ctx),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TokenSource returns an oauth2.TokenSource that retrieve tokens from
 | 
			
		||||
// Google Cloud SDK credentials using the provided context.
 | 
			
		||||
// It will returns the current access token stored in the credentials,
 | 
			
		||||
// and refresh it when it expires, but it won't update the credentials
 | 
			
		||||
// with the new access token.
 | 
			
		||||
func (c *SDKConfig) TokenSource(ctx context.Context) oauth2.TokenSource {
 | 
			
		||||
	return c.conf.TokenSource(ctx, c.initialToken)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Scopes are the OAuth 2.0 scopes the current account is authorized for.
 | 
			
		||||
func (c *SDKConfig) Scopes() []string {
 | 
			
		||||
	return c.conf.Scopes
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseINI(ini io.Reader) (map[string]map[string]string, error) {
 | 
			
		||||
	result := map[string]map[string]string{
 | 
			
		||||
		"": {}, // root section
 | 
			
		||||
	}
 | 
			
		||||
	scanner := bufio.NewScanner(ini)
 | 
			
		||||
	currentSection := ""
 | 
			
		||||
	for scanner.Scan() {
 | 
			
		||||
		line := strings.TrimSpace(scanner.Text())
 | 
			
		||||
		if strings.HasPrefix(line, ";") {
 | 
			
		||||
			// comment.
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
 | 
			
		||||
			currentSection = strings.TrimSpace(line[1 : len(line)-1])
 | 
			
		||||
			result[currentSection] = map[string]string{}
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		parts := strings.SplitN(line, "=", 2)
 | 
			
		||||
		if len(parts) == 2 && parts[0] != "" {
 | 
			
		||||
			result[currentSection][strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if err := scanner.Err(); err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("error scanning ini: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	return result, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// sdkConfigPath tries to guess where the gcloud config is located.
 | 
			
		||||
// It can be overridden during tests.
 | 
			
		||||
var sdkConfigPath = func() (string, error) {
 | 
			
		||||
	if runtime.GOOS == "windows" {
 | 
			
		||||
		return filepath.Join(os.Getenv("APPDATA"), "gcloud"), nil
 | 
			
		||||
	}
 | 
			
		||||
	homeDir := guessUnixHomeDir()
 | 
			
		||||
	if homeDir == "" {
 | 
			
		||||
		return "", errors.New("unable to get current user home directory: os/user lookup failed; $HOME is empty")
 | 
			
		||||
	}
 | 
			
		||||
	return filepath.Join(homeDir, ".config", "gcloud"), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func guessUnixHomeDir() string {
 | 
			
		||||
	// Prefer $HOME over user.Current due to glibc bug: golang.org/issue/13470
 | 
			
		||||
	if v := os.Getenv("HOME"); v != "" {
 | 
			
		||||
		return v
 | 
			
		||||
	}
 | 
			
		||||
	// Else, fall back to user.Current:
 | 
			
		||||
	if u, err := user.Current(); err == nil {
 | 
			
		||||
		return u.HomeDir
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								vendor/golang.org/x/oauth2/internal/client_appengine.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								vendor/golang.org/x/oauth2/internal/client_appengine.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
// Copyright 2018 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.
 | 
			
		||||
 | 
			
		||||
// +build appengine
 | 
			
		||||
 | 
			
		||||
package internal
 | 
			
		||||
 | 
			
		||||
import "google.golang.org/appengine/urlfetch"
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	appengineClientHook = urlfetch.Client
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								vendor/golang.org/x/oauth2/internal/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								vendor/golang.org/x/oauth2/internal/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
// Copyright 2017 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 internal contains support packages for oauth2 package.
 | 
			
		||||
package internal
 | 
			
		||||
							
								
								
									
										37
									
								
								vendor/golang.org/x/oauth2/internal/oauth2.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								vendor/golang.org/x/oauth2/internal/oauth2.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
// 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 internal
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/rsa"
 | 
			
		||||
	"crypto/x509"
 | 
			
		||||
	"encoding/pem"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ParseKey converts the binary contents of a private key file
 | 
			
		||||
// to an *rsa.PrivateKey. It detects whether the private key is in a
 | 
			
		||||
// PEM container or not. If so, it extracts the the private key
 | 
			
		||||
// from PEM container before conversion. It only supports PEM
 | 
			
		||||
// containers with no passphrase.
 | 
			
		||||
func ParseKey(key []byte) (*rsa.PrivateKey, error) {
 | 
			
		||||
	block, _ := pem.Decode(key)
 | 
			
		||||
	if block != nil {
 | 
			
		||||
		key = block.Bytes
 | 
			
		||||
	}
 | 
			
		||||
	parsedKey, err := x509.ParsePKCS8PrivateKey(key)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		parsedKey, err = x509.ParsePKCS1PrivateKey(key)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("private key should be a PEM or plain PKSC1 or PKCS8; parse error: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	parsed, ok := parsedKey.(*rsa.PrivateKey)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil, errors.New("private key is invalid")
 | 
			
		||||
	}
 | 
			
		||||
	return parsed, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										272
									
								
								vendor/golang.org/x/oauth2/internal/token.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										272
									
								
								vendor/golang.org/x/oauth2/internal/token.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,272 @@
 | 
			
		||||
// 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 internal
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"mime"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
	"golang.org/x/net/context/ctxhttp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Token represents the credentials used to authorize
 | 
			
		||||
// the requests to access protected resources on the OAuth 2.0
 | 
			
		||||
// provider's backend.
 | 
			
		||||
//
 | 
			
		||||
// This type is a mirror of oauth2.Token and exists to break
 | 
			
		||||
// an otherwise-circular dependency. Other internal packages
 | 
			
		||||
// should convert this Token into an oauth2.Token before use.
 | 
			
		||||
type Token struct {
 | 
			
		||||
	// AccessToken is the token that authorizes and authenticates
 | 
			
		||||
	// the requests.
 | 
			
		||||
	AccessToken string
 | 
			
		||||
 | 
			
		||||
	// TokenType is the type of token.
 | 
			
		||||
	// The Type method returns either this or "Bearer", the default.
 | 
			
		||||
	TokenType string
 | 
			
		||||
 | 
			
		||||
	// RefreshToken is a token that's used by the application
 | 
			
		||||
	// (as opposed to the user) to refresh the access token
 | 
			
		||||
	// if it expires.
 | 
			
		||||
	RefreshToken string
 | 
			
		||||
 | 
			
		||||
	// Expiry is the optional expiration time of the access token.
 | 
			
		||||
	//
 | 
			
		||||
	// If zero, TokenSource implementations will reuse the same
 | 
			
		||||
	// token forever and RefreshToken or equivalent
 | 
			
		||||
	// mechanisms for that TokenSource will not be used.
 | 
			
		||||
	Expiry time.Time
 | 
			
		||||
 | 
			
		||||
	// Raw optionally contains extra metadata from the server
 | 
			
		||||
	// when updating a token.
 | 
			
		||||
	Raw interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tokenJSON is the struct representing the HTTP response from OAuth2
 | 
			
		||||
// providers returning a token in JSON form.
 | 
			
		||||
type tokenJSON struct {
 | 
			
		||||
	AccessToken  string         `json:"access_token"`
 | 
			
		||||
	TokenType    string         `json:"token_type"`
 | 
			
		||||
	RefreshToken string         `json:"refresh_token"`
 | 
			
		||||
	ExpiresIn    expirationTime `json:"expires_in"` // at least PayPal returns string, while most return number
 | 
			
		||||
	Expires      expirationTime `json:"expires"`    // broken Facebook spelling of expires_in
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *tokenJSON) expiry() (t time.Time) {
 | 
			
		||||
	if v := e.ExpiresIn; v != 0 {
 | 
			
		||||
		return time.Now().Add(time.Duration(v) * time.Second)
 | 
			
		||||
	}
 | 
			
		||||
	if v := e.Expires; v != 0 {
 | 
			
		||||
		return time.Now().Add(time.Duration(v) * time.Second)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type expirationTime int32
 | 
			
		||||
 | 
			
		||||
func (e *expirationTime) UnmarshalJSON(b []byte) error {
 | 
			
		||||
	var n json.Number
 | 
			
		||||
	err := json.Unmarshal(b, &n)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	i, err := n.Int64()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	*e = expirationTime(i)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var brokenAuthHeaderProviders = []string{
 | 
			
		||||
	"https://accounts.google.com/",
 | 
			
		||||
	"https://api.codeswholesale.com/oauth/token",
 | 
			
		||||
	"https://api.dropbox.com/",
 | 
			
		||||
	"https://api.dropboxapi.com/",
 | 
			
		||||
	"https://api.instagram.com/",
 | 
			
		||||
	"https://api.netatmo.net/",
 | 
			
		||||
	"https://api.odnoklassniki.ru/",
 | 
			
		||||
	"https://api.pushbullet.com/",
 | 
			
		||||
	"https://api.soundcloud.com/",
 | 
			
		||||
	"https://api.twitch.tv/",
 | 
			
		||||
	"https://id.twitch.tv/",
 | 
			
		||||
	"https://app.box.com/",
 | 
			
		||||
	"https://api.box.com/",
 | 
			
		||||
	"https://connect.stripe.com/",
 | 
			
		||||
	"https://login.mailchimp.com/",
 | 
			
		||||
	"https://login.microsoftonline.com/",
 | 
			
		||||
	"https://login.salesforce.com/",
 | 
			
		||||
	"https://login.windows.net",
 | 
			
		||||
	"https://login.live.com/",
 | 
			
		||||
	"https://oauth.sandbox.trainingpeaks.com/",
 | 
			
		||||
	"https://oauth.trainingpeaks.com/",
 | 
			
		||||
	"https://oauth.vk.com/",
 | 
			
		||||
	"https://openapi.baidu.com/",
 | 
			
		||||
	"https://slack.com/",
 | 
			
		||||
	"https://test-sandbox.auth.corp.google.com",
 | 
			
		||||
	"https://test.salesforce.com/",
 | 
			
		||||
	"https://user.gini.net/",
 | 
			
		||||
	"https://www.douban.com/",
 | 
			
		||||
	"https://www.googleapis.com/",
 | 
			
		||||
	"https://www.linkedin.com/",
 | 
			
		||||
	"https://www.strava.com/oauth/",
 | 
			
		||||
	"https://www.wunderlist.com/oauth/",
 | 
			
		||||
	"https://api.patreon.com/",
 | 
			
		||||
	"https://sandbox.codeswholesale.com/oauth/token",
 | 
			
		||||
	"https://api.sipgate.com/v1/authorization/oauth",
 | 
			
		||||
	"https://api.medium.com/v1/tokens",
 | 
			
		||||
	"https://log.finalsurge.com/oauth/token",
 | 
			
		||||
	"https://multisport.todaysplan.com.au/rest/oauth/access_token",
 | 
			
		||||
	"https://whats.todaysplan.com.au/rest/oauth/access_token",
 | 
			
		||||
	"https://stackoverflow.com/oauth/access_token",
 | 
			
		||||
	"https://account.health.nokia.com",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// brokenAuthHeaderDomains lists broken providers that issue dynamic endpoints.
 | 
			
		||||
var brokenAuthHeaderDomains = []string{
 | 
			
		||||
	".auth0.com",
 | 
			
		||||
	".force.com",
 | 
			
		||||
	".myshopify.com",
 | 
			
		||||
	".okta.com",
 | 
			
		||||
	".oktapreview.com",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RegisterBrokenAuthHeaderProvider(tokenURL string) {
 | 
			
		||||
	brokenAuthHeaderProviders = append(brokenAuthHeaderProviders, tokenURL)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// providerAuthHeaderWorks reports whether the OAuth2 server identified by the tokenURL
 | 
			
		||||
// implements the OAuth2 spec correctly
 | 
			
		||||
// See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
 | 
			
		||||
// In summary:
 | 
			
		||||
// - Reddit only accepts client secret in the Authorization header
 | 
			
		||||
// - Dropbox accepts either it in URL param or Auth header, but not both.
 | 
			
		||||
// - Google only accepts URL param (not spec compliant?), not Auth header
 | 
			
		||||
// - Stripe only accepts client secret in Auth header with Bearer method, not Basic
 | 
			
		||||
func providerAuthHeaderWorks(tokenURL string) bool {
 | 
			
		||||
	for _, s := range brokenAuthHeaderProviders {
 | 
			
		||||
		if strings.HasPrefix(tokenURL, s) {
 | 
			
		||||
			// Some sites fail to implement the OAuth2 spec fully.
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if u, err := url.Parse(tokenURL); err == nil {
 | 
			
		||||
		for _, s := range brokenAuthHeaderDomains {
 | 
			
		||||
			if strings.HasSuffix(u.Host, s) {
 | 
			
		||||
				return false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Assume the provider implements the spec properly
 | 
			
		||||
	// otherwise. We can add more exceptions as they're
 | 
			
		||||
	// discovered. We will _not_ be adding configurable hooks
 | 
			
		||||
	// to this package to let users select server bugs.
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values) (*Token, error) {
 | 
			
		||||
	bustedAuth := !providerAuthHeaderWorks(tokenURL)
 | 
			
		||||
	if bustedAuth {
 | 
			
		||||
		if clientID != "" {
 | 
			
		||||
			v.Set("client_id", clientID)
 | 
			
		||||
		}
 | 
			
		||||
		if clientSecret != "" {
 | 
			
		||||
			v.Set("client_secret", clientSecret)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	req, err := http.NewRequest("POST", tokenURL, strings.NewReader(v.Encode()))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 | 
			
		||||
	if !bustedAuth {
 | 
			
		||||
		req.SetBasicAuth(url.QueryEscape(clientID), url.QueryEscape(clientSecret))
 | 
			
		||||
	}
 | 
			
		||||
	r, err := ctxhttp.Do(ctx, ContextClient(ctx), req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer r.Body.Close()
 | 
			
		||||
	body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1<<20))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if code := r.StatusCode; code < 200 || code > 299 {
 | 
			
		||||
		return nil, &RetrieveError{
 | 
			
		||||
			Response: r,
 | 
			
		||||
			Body:     body,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var token *Token
 | 
			
		||||
	content, _, _ := mime.ParseMediaType(r.Header.Get("Content-Type"))
 | 
			
		||||
	switch content {
 | 
			
		||||
	case "application/x-www-form-urlencoded", "text/plain":
 | 
			
		||||
		vals, err := url.ParseQuery(string(body))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		token = &Token{
 | 
			
		||||
			AccessToken:  vals.Get("access_token"),
 | 
			
		||||
			TokenType:    vals.Get("token_type"),
 | 
			
		||||
			RefreshToken: vals.Get("refresh_token"),
 | 
			
		||||
			Raw:          vals,
 | 
			
		||||
		}
 | 
			
		||||
		e := vals.Get("expires_in")
 | 
			
		||||
		if e == "" {
 | 
			
		||||
			// TODO(jbd): Facebook's OAuth2 implementation is broken and
 | 
			
		||||
			// returns expires_in field in expires. Remove the fallback to expires,
 | 
			
		||||
			// when Facebook fixes their implementation.
 | 
			
		||||
			e = vals.Get("expires")
 | 
			
		||||
		}
 | 
			
		||||
		expires, _ := strconv.Atoi(e)
 | 
			
		||||
		if expires != 0 {
 | 
			
		||||
			token.Expiry = time.Now().Add(time.Duration(expires) * time.Second)
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		var tj tokenJSON
 | 
			
		||||
		if err = json.Unmarshal(body, &tj); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		token = &Token{
 | 
			
		||||
			AccessToken:  tj.AccessToken,
 | 
			
		||||
			TokenType:    tj.TokenType,
 | 
			
		||||
			RefreshToken: tj.RefreshToken,
 | 
			
		||||
			Expiry:       tj.expiry(),
 | 
			
		||||
			Raw:          make(map[string]interface{}),
 | 
			
		||||
		}
 | 
			
		||||
		json.Unmarshal(body, &token.Raw) // no error checks for optional fields
 | 
			
		||||
	}
 | 
			
		||||
	// Don't overwrite `RefreshToken` with an empty value
 | 
			
		||||
	// if this was a token refreshing request.
 | 
			
		||||
	if token.RefreshToken == "" {
 | 
			
		||||
		token.RefreshToken = v.Get("refresh_token")
 | 
			
		||||
	}
 | 
			
		||||
	if token.AccessToken == "" {
 | 
			
		||||
		return token, errors.New("oauth2: server response missing access_token")
 | 
			
		||||
	}
 | 
			
		||||
	return token, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RetrieveError struct {
 | 
			
		||||
	Response *http.Response
 | 
			
		||||
	Body     []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *RetrieveError) Error() string {
 | 
			
		||||
	return fmt.Sprintf("oauth2: cannot fetch token: %v\nResponse: %s", r.Response.Status, r.Body)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								vendor/golang.org/x/oauth2/internal/transport.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								vendor/golang.org/x/oauth2/internal/transport.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
// 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 internal
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 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 ContextKey
 | 
			
		||||
 | 
			
		||||
// ContextKey is just an empty struct. It exists so HTTPClient can be
 | 
			
		||||
// an immutable public variable with a unique type. It's immutable
 | 
			
		||||
// because nobody else can create a ContextKey, being unexported.
 | 
			
		||||
type ContextKey struct{}
 | 
			
		||||
 | 
			
		||||
var appengineClientHook func(context.Context) *http.Client
 | 
			
		||||
 | 
			
		||||
func ContextClient(ctx context.Context) *http.Client {
 | 
			
		||||
	if ctx != nil {
 | 
			
		||||
		if hc, ok := ctx.Value(HTTPClient).(*http.Client); ok {
 | 
			
		||||
			return hc
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if appengineClientHook != nil {
 | 
			
		||||
		return appengineClientHook(ctx)
 | 
			
		||||
	}
 | 
			
		||||
	return http.DefaultClient
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										182
									
								
								vendor/golang.org/x/oauth2/jws/jws.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								vendor/golang.org/x/oauth2/jws/jws.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,182 @@
 | 
			
		||||
// 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 jws provides a partial implementation
 | 
			
		||||
// of JSON Web Signature encoding and decoding.
 | 
			
		||||
// It exists to support the golang.org/x/oauth2 package.
 | 
			
		||||
//
 | 
			
		||||
// See RFC 7515.
 | 
			
		||||
//
 | 
			
		||||
// Deprecated: this package is not intended for public use and might be
 | 
			
		||||
// removed in the future. It exists for internal use only.
 | 
			
		||||
// Please switch to another JWS package or copy this package into your own
 | 
			
		||||
// source tree.
 | 
			
		||||
package jws // import "golang.org/x/oauth2/jws"
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"crypto"
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"crypto/rsa"
 | 
			
		||||
	"crypto/sha256"
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ClaimSet contains information about the JWT signature including the
 | 
			
		||||
// permissions being requested (scopes), the target of the token, the issuer,
 | 
			
		||||
// the time the token was issued, and the lifetime of the token.
 | 
			
		||||
type ClaimSet struct {
 | 
			
		||||
	Iss   string `json:"iss"`             // email address of the client_id of the application making the access token request
 | 
			
		||||
	Scope string `json:"scope,omitempty"` // space-delimited list of the permissions the application requests
 | 
			
		||||
	Aud   string `json:"aud"`             // descriptor of the intended target of the assertion (Optional).
 | 
			
		||||
	Exp   int64  `json:"exp"`             // the expiration time of the assertion (seconds since Unix epoch)
 | 
			
		||||
	Iat   int64  `json:"iat"`             // the time the assertion was issued (seconds since Unix epoch)
 | 
			
		||||
	Typ   string `json:"typ,omitempty"`   // token type (Optional).
 | 
			
		||||
 | 
			
		||||
	// Email for which the application is requesting delegated access (Optional).
 | 
			
		||||
	Sub string `json:"sub,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// The old name of Sub. Client keeps setting Prn to be
 | 
			
		||||
	// complaint with legacy OAuth 2.0 providers. (Optional)
 | 
			
		||||
	Prn string `json:"prn,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// See http://tools.ietf.org/html/draft-jones-json-web-token-10#section-4.3
 | 
			
		||||
	// This array is marshalled using custom code (see (c *ClaimSet) encode()).
 | 
			
		||||
	PrivateClaims map[string]interface{} `json:"-"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *ClaimSet) encode() (string, error) {
 | 
			
		||||
	// Reverting time back for machines whose time is not perfectly in sync.
 | 
			
		||||
	// If client machine's time is in the future according
 | 
			
		||||
	// to Google servers, an access token will not be issued.
 | 
			
		||||
	now := time.Now().Add(-10 * time.Second)
 | 
			
		||||
	if c.Iat == 0 {
 | 
			
		||||
		c.Iat = now.Unix()
 | 
			
		||||
	}
 | 
			
		||||
	if c.Exp == 0 {
 | 
			
		||||
		c.Exp = now.Add(time.Hour).Unix()
 | 
			
		||||
	}
 | 
			
		||||
	if c.Exp < c.Iat {
 | 
			
		||||
		return "", fmt.Errorf("jws: invalid Exp = %v; must be later than Iat = %v", c.Exp, c.Iat)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b, err := json.Marshal(c)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(c.PrivateClaims) == 0 {
 | 
			
		||||
		return base64.RawURLEncoding.EncodeToString(b), nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Marshal private claim set and then append it to b.
 | 
			
		||||
	prv, err := json.Marshal(c.PrivateClaims)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", fmt.Errorf("jws: invalid map of private claims %v", c.PrivateClaims)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Concatenate public and private claim JSON objects.
 | 
			
		||||
	if !bytes.HasSuffix(b, []byte{'}'}) {
 | 
			
		||||
		return "", fmt.Errorf("jws: invalid JSON %s", b)
 | 
			
		||||
	}
 | 
			
		||||
	if !bytes.HasPrefix(prv, []byte{'{'}) {
 | 
			
		||||
		return "", fmt.Errorf("jws: invalid JSON %s", prv)
 | 
			
		||||
	}
 | 
			
		||||
	b[len(b)-1] = ','         // Replace closing curly brace with a comma.
 | 
			
		||||
	b = append(b, prv[1:]...) // Append private claims.
 | 
			
		||||
	return base64.RawURLEncoding.EncodeToString(b), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Header represents the header for the signed JWS payloads.
 | 
			
		||||
type Header struct {
 | 
			
		||||
	// The algorithm used for signature.
 | 
			
		||||
	Algorithm string `json:"alg"`
 | 
			
		||||
 | 
			
		||||
	// Represents the token type.
 | 
			
		||||
	Typ string `json:"typ"`
 | 
			
		||||
 | 
			
		||||
	// The optional hint of which key is being used.
 | 
			
		||||
	KeyID string `json:"kid,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *Header) encode() (string, error) {
 | 
			
		||||
	b, err := json.Marshal(h)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	return base64.RawURLEncoding.EncodeToString(b), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Decode decodes a claim set from a JWS payload.
 | 
			
		||||
func Decode(payload string) (*ClaimSet, error) {
 | 
			
		||||
	// decode returned id token to get expiry
 | 
			
		||||
	s := strings.Split(payload, ".")
 | 
			
		||||
	if len(s) < 2 {
 | 
			
		||||
		// TODO(jbd): Provide more context about the error.
 | 
			
		||||
		return nil, errors.New("jws: invalid token received")
 | 
			
		||||
	}
 | 
			
		||||
	decoded, err := base64.RawURLEncoding.DecodeString(s[1])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	c := &ClaimSet{}
 | 
			
		||||
	err = json.NewDecoder(bytes.NewBuffer(decoded)).Decode(c)
 | 
			
		||||
	return c, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Signer returns a signature for the given data.
 | 
			
		||||
type Signer func(data []byte) (sig []byte, err error)
 | 
			
		||||
 | 
			
		||||
// EncodeWithSigner encodes a header and claim set with the provided signer.
 | 
			
		||||
func EncodeWithSigner(header *Header, c *ClaimSet, sg Signer) (string, error) {
 | 
			
		||||
	head, err := header.encode()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	cs, err := c.encode()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	ss := fmt.Sprintf("%s.%s", head, cs)
 | 
			
		||||
	sig, err := sg([]byte(ss))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	return fmt.Sprintf("%s.%s", ss, base64.RawURLEncoding.EncodeToString(sig)), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Encode encodes a signed JWS with provided header and claim set.
 | 
			
		||||
// This invokes EncodeWithSigner using crypto/rsa.SignPKCS1v15 with the given RSA private key.
 | 
			
		||||
func Encode(header *Header, c *ClaimSet, key *rsa.PrivateKey) (string, error) {
 | 
			
		||||
	sg := func(data []byte) (sig []byte, err error) {
 | 
			
		||||
		h := sha256.New()
 | 
			
		||||
		h.Write(data)
 | 
			
		||||
		return rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, h.Sum(nil))
 | 
			
		||||
	}
 | 
			
		||||
	return EncodeWithSigner(header, c, sg)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Verify tests whether the provided JWT token's signature was produced by the private key
 | 
			
		||||
// associated with the supplied public key.
 | 
			
		||||
func Verify(token string, key *rsa.PublicKey) error {
 | 
			
		||||
	parts := strings.Split(token, ".")
 | 
			
		||||
	if len(parts) != 3 {
 | 
			
		||||
		return errors.New("jws: invalid token received, token must have 3 parts")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	signedContent := parts[0] + "." + parts[1]
 | 
			
		||||
	signatureString, err := base64.RawURLEncoding.DecodeString(parts[2])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	h := sha256.New()
 | 
			
		||||
	h.Write([]byte(signedContent))
 | 
			
		||||
	return rsa.VerifyPKCS1v15(key, crypto.SHA256, h.Sum(nil), []byte(signatureString))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										162
									
								
								vendor/golang.org/x/oauth2/jwt/jwt.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								vendor/golang.org/x/oauth2/jwt/jwt.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,162 @@
 | 
			
		||||
// 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 jwt implements the OAuth 2.0 JSON Web Token flow, commonly
 | 
			
		||||
// known as "two-legged OAuth 2.0".
 | 
			
		||||
//
 | 
			
		||||
// See: https://tools.ietf.org/html/draft-ietf-oauth-jwt-bearer-12
 | 
			
		||||
package jwt
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
	"golang.org/x/oauth2"
 | 
			
		||||
	"golang.org/x/oauth2/internal"
 | 
			
		||||
	"golang.org/x/oauth2/jws"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	defaultGrantType = "urn:ietf:params:oauth:grant-type:jwt-bearer"
 | 
			
		||||
	defaultHeader    = &jws.Header{Algorithm: "RS256", Typ: "JWT"}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Config is the configuration for using JWT to fetch tokens,
 | 
			
		||||
// commonly known as "two-legged OAuth 2.0".
 | 
			
		||||
type Config struct {
 | 
			
		||||
	// Email is the OAuth client identifier used when communicating with
 | 
			
		||||
	// the configured OAuth provider.
 | 
			
		||||
	Email string
 | 
			
		||||
 | 
			
		||||
	// PrivateKey contains the contents of an RSA private key or the
 | 
			
		||||
	// contents of a PEM file that contains a private key. The provided
 | 
			
		||||
	// private key is used to sign JWT payloads.
 | 
			
		||||
	// PEM containers with a passphrase are not supported.
 | 
			
		||||
	// Use the following command to convert a PKCS 12 file into a PEM.
 | 
			
		||||
	//
 | 
			
		||||
	//    $ openssl pkcs12 -in key.p12 -out key.pem -nodes
 | 
			
		||||
	//
 | 
			
		||||
	PrivateKey []byte
 | 
			
		||||
 | 
			
		||||
	// PrivateKeyID contains an optional hint indicating which key is being
 | 
			
		||||
	// used.
 | 
			
		||||
	PrivateKeyID string
 | 
			
		||||
 | 
			
		||||
	// Subject is the optional user to impersonate.
 | 
			
		||||
	Subject string
 | 
			
		||||
 | 
			
		||||
	// Scopes optionally specifies a list of requested permission scopes.
 | 
			
		||||
	Scopes []string
 | 
			
		||||
 | 
			
		||||
	// TokenURL is the endpoint required to complete the 2-legged JWT flow.
 | 
			
		||||
	TokenURL string
 | 
			
		||||
 | 
			
		||||
	// Expires optionally specifies how long the token is valid for.
 | 
			
		||||
	Expires time.Duration
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TokenSource returns a JWT TokenSource using the configuration
 | 
			
		||||
// in c and the HTTP client from the provided context.
 | 
			
		||||
func (c *Config) TokenSource(ctx context.Context) oauth2.TokenSource {
 | 
			
		||||
	return oauth2.ReuseTokenSource(nil, jwtSource{ctx, c})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Client returns an HTTP client wrapping the context's
 | 
			
		||||
// HTTP transport and adding Authorization headers with tokens
 | 
			
		||||
// obtained from c.
 | 
			
		||||
//
 | 
			
		||||
// The returned client and its Transport should not be modified.
 | 
			
		||||
func (c *Config) Client(ctx context.Context) *http.Client {
 | 
			
		||||
	return oauth2.NewClient(ctx, c.TokenSource(ctx))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// jwtSource is a source that always does a signed JWT request for a token.
 | 
			
		||||
// It should typically be wrapped with a reuseTokenSource.
 | 
			
		||||
type jwtSource struct {
 | 
			
		||||
	ctx  context.Context
 | 
			
		||||
	conf *Config
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (js jwtSource) Token() (*oauth2.Token, error) {
 | 
			
		||||
	pk, err := internal.ParseKey(js.conf.PrivateKey)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	hc := oauth2.NewClient(js.ctx, nil)
 | 
			
		||||
	claimSet := &jws.ClaimSet{
 | 
			
		||||
		Iss:   js.conf.Email,
 | 
			
		||||
		Scope: strings.Join(js.conf.Scopes, " "),
 | 
			
		||||
		Aud:   js.conf.TokenURL,
 | 
			
		||||
	}
 | 
			
		||||
	if subject := js.conf.Subject; subject != "" {
 | 
			
		||||
		claimSet.Sub = subject
 | 
			
		||||
		// prn is the old name of sub. Keep setting it
 | 
			
		||||
		// to be compatible with legacy OAuth 2.0 providers.
 | 
			
		||||
		claimSet.Prn = subject
 | 
			
		||||
	}
 | 
			
		||||
	if t := js.conf.Expires; t > 0 {
 | 
			
		||||
		claimSet.Exp = time.Now().Add(t).Unix()
 | 
			
		||||
	}
 | 
			
		||||
	h := *defaultHeader
 | 
			
		||||
	h.KeyID = js.conf.PrivateKeyID
 | 
			
		||||
	payload, err := jws.Encode(&h, claimSet, pk)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	v := url.Values{}
 | 
			
		||||
	v.Set("grant_type", defaultGrantType)
 | 
			
		||||
	v.Set("assertion", payload)
 | 
			
		||||
	resp, err := hc.PostForm(js.conf.TokenURL, v)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	defer resp.Body.Close()
 | 
			
		||||
	body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if c := resp.StatusCode; c < 200 || c > 299 {
 | 
			
		||||
		return nil, &oauth2.RetrieveError{
 | 
			
		||||
			Response: resp,
 | 
			
		||||
			Body:     body,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// tokenRes is the JSON response body.
 | 
			
		||||
	var tokenRes struct {
 | 
			
		||||
		AccessToken string `json:"access_token"`
 | 
			
		||||
		TokenType   string `json:"token_type"`
 | 
			
		||||
		IDToken     string `json:"id_token"`
 | 
			
		||||
		ExpiresIn   int64  `json:"expires_in"` // relative seconds from now
 | 
			
		||||
	}
 | 
			
		||||
	if err := json.Unmarshal(body, &tokenRes); err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	token := &oauth2.Token{
 | 
			
		||||
		AccessToken: tokenRes.AccessToken,
 | 
			
		||||
		TokenType:   tokenRes.TokenType,
 | 
			
		||||
	}
 | 
			
		||||
	raw := make(map[string]interface{})
 | 
			
		||||
	json.Unmarshal(body, &raw) // no error checks for optional fields
 | 
			
		||||
	token = token.WithExtra(raw)
 | 
			
		||||
 | 
			
		||||
	if secs := tokenRes.ExpiresIn; secs > 0 {
 | 
			
		||||
		token.Expiry = time.Now().Add(time.Duration(secs) * time.Second)
 | 
			
		||||
	}
 | 
			
		||||
	if v := tokenRes.IDToken; v != "" {
 | 
			
		||||
		// decode returned id token to get expiry
 | 
			
		||||
		claimSet, err := jws.Decode(v)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("oauth2: error decoding JWT token: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
		token.Expiry = time.Unix(claimSet.Exp, 0)
 | 
			
		||||
	}
 | 
			
		||||
	return token, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										362
									
								
								vendor/golang.org/x/oauth2/oauth2.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										362
									
								
								vendor/golang.org/x/oauth2/oauth2.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,362 @@
 | 
			
		||||
// 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"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
	"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 registers an OAuth2 server
 | 
			
		||||
// identified by the tokenURL prefix as an OAuth2 implementation
 | 
			
		||||
// which doesn't support the HTTP Basic authentication
 | 
			
		||||
// scheme to authenticate with the authorization server.
 | 
			
		||||
// Once a server is registered, credentials (client_id and client_secret)
 | 
			
		||||
// will be passed as query parameters rather than being present
 | 
			
		||||
// in the Authorization header.
 | 
			
		||||
// See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
 | 
			
		||||
func RegisterBrokenAuthHeaderProvider(tokenURL string) {
 | 
			
		||||
	internal.RegisterBrokenAuthHeaderProvider(tokenURL)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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 contains the OAuth 2.0 provider's authorization and token
 | 
			
		||||
// endpoint URLs.
 | 
			
		||||
type Endpoint struct {
 | 
			
		||||
	AuthURL  string
 | 
			
		||||
	TokenURL string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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("approval_prompt", "force")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 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 challange.
 | 
			
		||||
// 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 HTTP client to use is derived from the context.
 | 
			
		||||
// If nil, http.DefaultClient is used.
 | 
			
		||||
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 HTTP client to use is derived from the context.
 | 
			
		||||
// If a client is not provided via the context, http.DefaultClient is used.
 | 
			
		||||
//
 | 
			
		||||
// 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,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										175
									
								
								vendor/golang.org/x/oauth2/token.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								vendor/golang.org/x/oauth2/token.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,175 @@
 | 
			
		||||
// 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
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
	"golang.org/x/oauth2/internal"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// expiryDelta determines how earlier a token should be considered
 | 
			
		||||
// expired than its actual expiration time. It is used to avoid late
 | 
			
		||||
// expirations due to client-server time mismatches.
 | 
			
		||||
const expiryDelta = 10 * time.Second
 | 
			
		||||
 | 
			
		||||
// Token represents the credentials used to authorize
 | 
			
		||||
// the requests to access protected resources on the OAuth 2.0
 | 
			
		||||
// provider's backend.
 | 
			
		||||
//
 | 
			
		||||
// Most users of this package should not access fields of Token
 | 
			
		||||
// directly. They're exported mostly for use by related packages
 | 
			
		||||
// implementing derivative OAuth2 flows.
 | 
			
		||||
type Token struct {
 | 
			
		||||
	// AccessToken is the token that authorizes and authenticates
 | 
			
		||||
	// the requests.
 | 
			
		||||
	AccessToken string `json:"access_token"`
 | 
			
		||||
 | 
			
		||||
	// TokenType is the type of token.
 | 
			
		||||
	// The Type method returns either this or "Bearer", the default.
 | 
			
		||||
	TokenType string `json:"token_type,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// RefreshToken is a token that's used by the application
 | 
			
		||||
	// (as opposed to the user) to refresh the access token
 | 
			
		||||
	// if it expires.
 | 
			
		||||
	RefreshToken string `json:"refresh_token,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// Expiry is the optional expiration time of the access token.
 | 
			
		||||
	//
 | 
			
		||||
	// If zero, TokenSource implementations will reuse the same
 | 
			
		||||
	// token forever and RefreshToken or equivalent
 | 
			
		||||
	// mechanisms for that TokenSource will not be used.
 | 
			
		||||
	Expiry time.Time `json:"expiry,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// raw optionally contains extra metadata from the server
 | 
			
		||||
	// when updating a token.
 | 
			
		||||
	raw interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Type returns t.TokenType if non-empty, else "Bearer".
 | 
			
		||||
func (t *Token) Type() string {
 | 
			
		||||
	if strings.EqualFold(t.TokenType, "bearer") {
 | 
			
		||||
		return "Bearer"
 | 
			
		||||
	}
 | 
			
		||||
	if strings.EqualFold(t.TokenType, "mac") {
 | 
			
		||||
		return "MAC"
 | 
			
		||||
	}
 | 
			
		||||
	if strings.EqualFold(t.TokenType, "basic") {
 | 
			
		||||
		return "Basic"
 | 
			
		||||
	}
 | 
			
		||||
	if t.TokenType != "" {
 | 
			
		||||
		return t.TokenType
 | 
			
		||||
	}
 | 
			
		||||
	return "Bearer"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetAuthHeader sets the Authorization header to r using the access
 | 
			
		||||
// token in t.
 | 
			
		||||
//
 | 
			
		||||
// This method is unnecessary when using Transport or an HTTP Client
 | 
			
		||||
// returned by this package.
 | 
			
		||||
func (t *Token) SetAuthHeader(r *http.Request) {
 | 
			
		||||
	r.Header.Set("Authorization", t.Type()+" "+t.AccessToken)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithExtra returns a new Token that's a clone of t, but using the
 | 
			
		||||
// provided raw extra map. This is only intended for use by packages
 | 
			
		||||
// implementing derivative OAuth2 flows.
 | 
			
		||||
func (t *Token) WithExtra(extra interface{}) *Token {
 | 
			
		||||
	t2 := new(Token)
 | 
			
		||||
	*t2 = *t
 | 
			
		||||
	t2.raw = extra
 | 
			
		||||
	return t2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Extra returns an extra field.
 | 
			
		||||
// Extra fields are key-value pairs returned by the server as a
 | 
			
		||||
// part of the token retrieval response.
 | 
			
		||||
func (t *Token) Extra(key string) interface{} {
 | 
			
		||||
	if raw, ok := t.raw.(map[string]interface{}); ok {
 | 
			
		||||
		return raw[key]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vals, ok := t.raw.(url.Values)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	v := vals.Get(key)
 | 
			
		||||
	switch s := strings.TrimSpace(v); strings.Count(s, ".") {
 | 
			
		||||
	case 0: // Contains no "."; try to parse as int
 | 
			
		||||
		if i, err := strconv.ParseInt(s, 10, 64); err == nil {
 | 
			
		||||
			return i
 | 
			
		||||
		}
 | 
			
		||||
	case 1: // Contains a single "."; try to parse as float
 | 
			
		||||
		if f, err := strconv.ParseFloat(s, 64); err == nil {
 | 
			
		||||
			return f
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// expired reports whether the token is expired.
 | 
			
		||||
// t must be non-nil.
 | 
			
		||||
func (t *Token) expired() bool {
 | 
			
		||||
	if t.Expiry.IsZero() {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return t.Expiry.Round(0).Add(-expiryDelta).Before(time.Now())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Valid reports whether t is non-nil, has an AccessToken, and is not expired.
 | 
			
		||||
func (t *Token) Valid() bool {
 | 
			
		||||
	return t != nil && t.AccessToken != "" && !t.expired()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tokenFromInternal maps an *internal.Token struct into
 | 
			
		||||
// a *Token struct.
 | 
			
		||||
func tokenFromInternal(t *internal.Token) *Token {
 | 
			
		||||
	if t == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return &Token{
 | 
			
		||||
		AccessToken:  t.AccessToken,
 | 
			
		||||
		TokenType:    t.TokenType,
 | 
			
		||||
		RefreshToken: t.RefreshToken,
 | 
			
		||||
		Expiry:       t.Expiry,
 | 
			
		||||
		raw:          t.Raw,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// retrieveToken takes a *Config and uses that to retrieve an *internal.Token.
 | 
			
		||||
// This token is then mapped from *internal.Token into an *oauth2.Token which is returned along
 | 
			
		||||
// with an error..
 | 
			
		||||
func retrieveToken(ctx context.Context, c *Config, v url.Values) (*Token, error) {
 | 
			
		||||
	tk, err := internal.RetrieveToken(ctx, c.ClientID, c.ClientSecret, c.Endpoint.TokenURL, v)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if rErr, ok := err.(*internal.RetrieveError); ok {
 | 
			
		||||
			return nil, (*RetrieveError)(rErr)
 | 
			
		||||
		}
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return tokenFromInternal(tk), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RetrieveError is the error returned when the token endpoint returns a
 | 
			
		||||
// non-2XX HTTP status code.
 | 
			
		||||
type RetrieveError struct {
 | 
			
		||||
	Response *http.Response
 | 
			
		||||
	// Body is the body that was consumed by reading Response.Body.
 | 
			
		||||
	// It may be truncated.
 | 
			
		||||
	Body []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *RetrieveError) Error() string {
 | 
			
		||||
	return fmt.Sprintf("oauth2: cannot fetch token: %v\nResponse: %s", r.Response.Status, r.Body)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										144
									
								
								vendor/golang.org/x/oauth2/transport.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								vendor/golang.org/x/oauth2/transport.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,144 @@
 | 
			
		||||
// 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
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Transport is an http.RoundTripper that makes OAuth 2.0 HTTP requests,
 | 
			
		||||
// wrapping a base RoundTripper and adding an Authorization header
 | 
			
		||||
// with a token from the supplied Sources.
 | 
			
		||||
//
 | 
			
		||||
// Transport is a low-level mechanism. Most code will use the
 | 
			
		||||
// higher-level Config.Client method instead.
 | 
			
		||||
type Transport struct {
 | 
			
		||||
	// Source supplies the token to add to outgoing requests'
 | 
			
		||||
	// Authorization headers.
 | 
			
		||||
	Source TokenSource
 | 
			
		||||
 | 
			
		||||
	// Base is the base RoundTripper used to make HTTP requests.
 | 
			
		||||
	// If nil, http.DefaultTransport is used.
 | 
			
		||||
	Base http.RoundTripper
 | 
			
		||||
 | 
			
		||||
	mu     sync.Mutex                      // guards modReq
 | 
			
		||||
	modReq map[*http.Request]*http.Request // original -> modified
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RoundTrip authorizes and authenticates the request with an
 | 
			
		||||
// access token from Transport's Source.
 | 
			
		||||
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
 | 
			
		||||
	reqBodyClosed := false
 | 
			
		||||
	if req.Body != nil {
 | 
			
		||||
		defer func() {
 | 
			
		||||
			if !reqBodyClosed {
 | 
			
		||||
				req.Body.Close()
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if t.Source == nil {
 | 
			
		||||
		return nil, errors.New("oauth2: Transport's Source is nil")
 | 
			
		||||
	}
 | 
			
		||||
	token, err := t.Source.Token()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	req2 := cloneRequest(req) // per RoundTripper contract
 | 
			
		||||
	token.SetAuthHeader(req2)
 | 
			
		||||
	t.setModReq(req, req2)
 | 
			
		||||
	res, err := t.base().RoundTrip(req2)
 | 
			
		||||
 | 
			
		||||
	// req.Body is assumed to have been closed by the base RoundTripper.
 | 
			
		||||
	reqBodyClosed = true
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.setModReq(req, nil)
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	res.Body = &onEOFReader{
 | 
			
		||||
		rc: res.Body,
 | 
			
		||||
		fn: func() { t.setModReq(req, nil) },
 | 
			
		||||
	}
 | 
			
		||||
	return res, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CancelRequest cancels an in-flight request by closing its connection.
 | 
			
		||||
func (t *Transport) CancelRequest(req *http.Request) {
 | 
			
		||||
	type canceler interface {
 | 
			
		||||
		CancelRequest(*http.Request)
 | 
			
		||||
	}
 | 
			
		||||
	if cr, ok := t.base().(canceler); ok {
 | 
			
		||||
		t.mu.Lock()
 | 
			
		||||
		modReq := t.modReq[req]
 | 
			
		||||
		delete(t.modReq, req)
 | 
			
		||||
		t.mu.Unlock()
 | 
			
		||||
		cr.CancelRequest(modReq)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *Transport) base() http.RoundTripper {
 | 
			
		||||
	if t.Base != nil {
 | 
			
		||||
		return t.Base
 | 
			
		||||
	}
 | 
			
		||||
	return http.DefaultTransport
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *Transport) setModReq(orig, mod *http.Request) {
 | 
			
		||||
	t.mu.Lock()
 | 
			
		||||
	defer t.mu.Unlock()
 | 
			
		||||
	if t.modReq == nil {
 | 
			
		||||
		t.modReq = make(map[*http.Request]*http.Request)
 | 
			
		||||
	}
 | 
			
		||||
	if mod == nil {
 | 
			
		||||
		delete(t.modReq, orig)
 | 
			
		||||
	} else {
 | 
			
		||||
		t.modReq[orig] = mod
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// cloneRequest returns a clone of the provided *http.Request.
 | 
			
		||||
// The clone is a shallow copy of the struct and its Header map.
 | 
			
		||||
func cloneRequest(r *http.Request) *http.Request {
 | 
			
		||||
	// shallow copy of the struct
 | 
			
		||||
	r2 := new(http.Request)
 | 
			
		||||
	*r2 = *r
 | 
			
		||||
	// deep copy of the Header
 | 
			
		||||
	r2.Header = make(http.Header, len(r.Header))
 | 
			
		||||
	for k, s := range r.Header {
 | 
			
		||||
		r2.Header[k] = append([]string(nil), s...)
 | 
			
		||||
	}
 | 
			
		||||
	return r2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type onEOFReader struct {
 | 
			
		||||
	rc io.ReadCloser
 | 
			
		||||
	fn func()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *onEOFReader) Read(p []byte) (n int, err error) {
 | 
			
		||||
	n, err = r.rc.Read(p)
 | 
			
		||||
	if err == io.EOF {
 | 
			
		||||
		r.runFunc()
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *onEOFReader) Close() error {
 | 
			
		||||
	err := r.rc.Close()
 | 
			
		||||
	r.runFunc()
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *onEOFReader) runFunc() {
 | 
			
		||||
	if fn := r.fn; fn != nil {
 | 
			
		||||
		fn()
 | 
			
		||||
		r.fn = nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user