1// Copyright 2017 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Package internal supports the options and transport packages.
16package internal
17
18import (
19	"errors"
20	"net/http"
21
22	"golang.org/x/oauth2"
23	"golang.org/x/oauth2/google"
24	"google.golang.org/grpc"
25)
26
27// DialSettings holds information needed to establish a connection with a
28// Google API service.
29type DialSettings struct {
30	Endpoint        string
31	Scopes          []string
32	TokenSource     oauth2.TokenSource
33	Credentials     *google.Credentials
34	CredentialsFile string // if set, Token Source is ignored.
35	CredentialsJSON []byte
36	UserAgent       string
37	APIKey          string
38	Audiences       []string
39	HTTPClient      *http.Client
40	GRPCDialOpts    []grpc.DialOption
41	GRPCConn        *grpc.ClientConn
42	NoAuth          bool
43
44	// Google API system parameters. For more information please read:
45	// https://cloud.google.com/apis/docs/system-parameters
46	QuotaProject  string
47	RequestReason string
48}
49
50// Validate reports an error if ds is invalid.
51func (ds *DialSettings) Validate() error {
52	hasCreds := ds.APIKey != "" || ds.TokenSource != nil || ds.CredentialsFile != "" || ds.Credentials != nil
53	if ds.NoAuth && hasCreds {
54		return errors.New("options.WithoutAuthentication is incompatible with any option that provides credentials")
55	}
56	// Credentials should not appear with other options.
57	// We currently allow TokenSource and CredentialsFile to coexist.
58	// TODO(jba): make TokenSource & CredentialsFile an error (breaking change).
59	nCreds := 0
60	if ds.Credentials != nil {
61		nCreds++
62	}
63	if ds.CredentialsJSON != nil {
64		nCreds++
65	}
66	if ds.CredentialsFile != "" {
67		nCreds++
68	}
69	if ds.APIKey != "" {
70		nCreds++
71	}
72	if ds.TokenSource != nil {
73		nCreds++
74	}
75	if len(ds.Scopes) > 0 && len(ds.Audiences) > 0 {
76		return errors.New("WithScopes is incompatible with WithAudience")
77	}
78	// Accept only one form of credentials, except we allow TokenSource and CredentialsFile for backwards compatibility.
79	if nCreds > 1 && !(nCreds == 2 && ds.TokenSource != nil && ds.CredentialsFile != "") {
80		return errors.New("multiple credential options provided")
81	}
82	if ds.HTTPClient != nil && ds.GRPCConn != nil {
83		return errors.New("WithHTTPClient is incompatible with WithGRPCConn")
84	}
85	if ds.HTTPClient != nil && ds.GRPCDialOpts != nil {
86		return errors.New("WithHTTPClient is incompatible with gRPC dial options")
87	}
88	if ds.HTTPClient != nil && ds.QuotaProject != "" {
89		return errors.New("WithHTTPClient is incompatible with QuotaProject")
90	}
91	if ds.HTTPClient != nil && ds.RequestReason != "" {
92		return errors.New("WithHTTPClient is incompatible with RequestReason")
93	}
94
95	return nil
96}
97