From 084440cd0c6739a298f3032adf0627f23aea22d3 Mon Sep 17 00:00:00 2001 From: Jonathan Edey Date: Tue, 19 Nov 2024 10:00:25 -0500 Subject: [PATCH 1/3] chore: Add `X-Goog-Api-Client` metric header to outgoing requests --- appcheck/appcheck.go | 19 ++++++++++++++++++ appcheck/appcheck_test.go | 37 ++++++++++++++++++++---------------- auth/auth.go | 4 +--- auth/auth_test.go | 9 +++------ auth/token_generator.go | 3 +++ auth/token_generator_test.go | 13 +++++++++++-- auth/user_mgt_test.go | 3 +-- firebase.go | 2 ++ iid/iid.go | 3 +++ iid/iid_test.go | 13 +++++++++++++ internal/http_client.go | 7 +++++++ internal/internal.go | 2 ++ messaging/messaging.go | 6 ++---- messaging/messaging_test.go | 5 +---- messaging/topic_mgt.go | 7 +++++-- messaging/topic_mgt_test.go | 5 +++++ 16 files changed, 99 insertions(+), 39 deletions(-) diff --git a/appcheck/appcheck.go b/appcheck/appcheck.go index 89868916..08ce9cdb 100644 --- a/appcheck/appcheck.go +++ b/appcheck/appcheck.go @@ -18,6 +18,7 @@ package appcheck import ( "context" "errors" + "net/http" "strings" "time" @@ -77,6 +78,7 @@ func NewClient(ctx context.Context, conf *internal.AppCheckConfig) (*Client, err jwks, err := keyfunc.Get(JWKSUrl, keyfunc.Options{ Ctx: ctx, RefreshInterval: 6 * time.Hour, + RequestFactory: makeRequestFactory(conf), }) if err != nil { return nil, err @@ -88,6 +90,23 @@ func NewClient(ctx context.Context, conf *internal.AppCheckConfig) (*Client, err }, nil } +func makeRequestFactory(conf *internal.AppCheckConfig) func(ctx context.Context, url string) (*http.Request, error) { + opts := []internal.HTTPOption{ + internal.WithHeader("x-goog-api-client", internal.GetMetricsHeader(conf.Version)), + } + + return func(ctx context.Context, url string) (*http.Request, error) { + hr, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + return nil, err + } + for _, o := range opts { + o(hr) + } + return hr, nil + } +} + // VerifyToken verifies the given App Check token. // // VerifyToken considers an App Check token string to be valid if all the following conditions are met: diff --git a/appcheck/appcheck_test.go b/appcheck/appcheck_test.go index 6cd088c0..7e5e6026 100644 --- a/appcheck/appcheck_test.go +++ b/appcheck/appcheck_test.go @@ -17,8 +17,14 @@ import ( "github.com/google/go-cmp/cmp" ) +var testAppCheckConfig = &internal.AppCheckConfig{ + ProjectID: "project_id", + Version: "test-version", +} + func TestVerifyTokenHasValidClaims(t *testing.T) { - ts, err := setupFakeJWKS() + var tr http.Request + ts, err := setupFakeJWKS(&tr) if err != nil { t.Fatalf("Error setting up fake JWKS server: %v", err) } @@ -30,15 +36,17 @@ func TestVerifyTokenHasValidClaims(t *testing.T) { } JWKSUrl = ts.URL - conf := &internal.AppCheckConfig{ - ProjectID: "project_id", - } - client, err := NewClient(context.Background(), conf) + client, err := NewClient(context.Background(), testAppCheckConfig) if err != nil { t.Errorf("Error creating NewClient: %v", err) } + xGoogAPIClientHeader := internal.GetMetricsHeader(testAppCheckConfig.Version) + if h := tr.Header.Get("x-goog-api-client"); h != xGoogAPIClientHeader { + t.Errorf("x-goog-api-client header = %q; want = %q", h, xGoogAPIClientHeader) + } + type appCheckClaims struct { Aud []string `json:"aud"` jwt.RegisteredClaims @@ -169,18 +177,16 @@ func TestVerifyTokenHasValidClaims(t *testing.T) { } func TestVerifyTokenMustExist(t *testing.T) { - ts, err := setupFakeJWKS() + var tr http.Request + ts, err := setupFakeJWKS(&tr) if err != nil { t.Fatalf("Error setting up fake JWK server: %v", err) } defer ts.Close() JWKSUrl = ts.URL - conf := &internal.AppCheckConfig{ - ProjectID: "project_id", - } - client, err := NewClient(context.Background(), conf) + client, err := NewClient(context.Background(), testAppCheckConfig) if err != nil { t.Errorf("Error creating NewClient: %v", err) } @@ -197,7 +203,8 @@ func TestVerifyTokenMustExist(t *testing.T) { } func TestVerifyTokenNotExpired(t *testing.T) { - ts, err := setupFakeJWKS() + var tr http.Request + ts, err := setupFakeJWKS(&tr) if err != nil { t.Fatalf("Error setting up fake JWKS server: %v", err) } @@ -209,11 +216,8 @@ func TestVerifyTokenNotExpired(t *testing.T) { } JWKSUrl = ts.URL - conf := &internal.AppCheckConfig{ - ProjectID: "project_id", - } - client, err := NewClient(context.Background(), conf) + client, err := NewClient(context.Background(), testAppCheckConfig) if err != nil { t.Errorf("Error creating NewClient: %v", err) } @@ -264,12 +268,13 @@ func TestVerifyTokenNotExpired(t *testing.T) { } } -func setupFakeJWKS() (*httptest.Server, error) { +func setupFakeJWKS(tr *http.Request) (*httptest.Server, error) { jwks, err := os.ReadFile("../testdata/mock.jwks.json") if err != nil { return nil, err } ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + *tr = *r w.Write(jwks) })) return ts, nil diff --git a/auth/auth.go b/auth/auth.go index 0bda04a0..a7028698 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -21,7 +21,6 @@ import ( "errors" "fmt" "os" - "runtime" "strings" "time" @@ -134,12 +133,11 @@ func NewClient(ctx context.Context, conf *internal.AuthConfig) (*Client, error) return nil, err } - goVersion := strings.TrimPrefix(runtime.Version(), "go") hc := internal.WithDefaultRetryConfig(transport) hc.CreateErrFn = handleHTTPError hc.Opts = []internal.HTTPOption{ internal.WithHeader("X-Client-Version", fmt.Sprintf("Go/Admin/%s", conf.Version)), - internal.WithHeader("x-goog-api-client", fmt.Sprintf("gl-go/%s fire-admin/%s", goVersion, conf.Version)), + internal.WithHeader("x-goog-api-client", internal.GetMetricsHeader(conf.Version)), } baseURL := defaultAuthURL diff --git a/auth/auth_test.go b/auth/auth_test.go index 2a00220b..9c8b1523 100644 --- a/auth/auth_test.go +++ b/auth/auth_test.go @@ -23,7 +23,6 @@ import ( "log" "net/http" "os" - "runtime" "strings" "syscall" "testing" @@ -1452,11 +1451,9 @@ func checkBaseClient(client *Client, wantProjectID string) error { return fmt.Errorf("version = %q; want = %q", version, wantVersion) } - goVersion := strings.TrimPrefix(runtime.Version(), "go") - xGoogAPIClientHeader := req.Header.Get("x-goog-api-client") - wantXGoogAPIClientHeader := fmt.Sprintf("gl-go/%s fire-admin/%s", goVersion, testVersion) - if xGoogAPIClientHeader != wantXGoogAPIClientHeader { - return fmt.Errorf("x-goog-api-client header = %q; want = %q", xGoogAPIClientHeader, wantXGoogAPIClientHeader) + xGoogAPIClientHeader := internal.GetMetricsHeader(testVersion) + if h := req.Header.Get("x-goog-api-client"); h != xGoogAPIClientHeader { + return fmt.Errorf("x-goog-api-client header = %q; want = %q", h, xGoogAPIClientHeader) } return nil diff --git a/auth/token_generator.go b/auth/token_generator.go index 0e18b8c8..ddf777be 100644 --- a/auth/token_generator.go +++ b/auth/token_generator.go @@ -172,6 +172,9 @@ type iamSigner struct { func newIAMSigner(ctx context.Context, config *internal.AuthConfig) (*iamSigner, error) { hc, _, err := internal.NewHTTPClient(ctx, config.Opts...) + hc.Opts = []internal.HTTPOption{ + internal.WithHeader("x-goog-api-client", internal.GetMetricsHeader(config.Version)), + } if err != nil { return nil, err } diff --git a/auth/token_generator_test.go b/auth/token_generator_test.go index c80c4dea..c79e3a9a 100644 --- a/auth/token_generator_test.go +++ b/auth/token_generator_test.go @@ -122,6 +122,7 @@ func TestIAMSigner(t *testing.T) { conf := &internal.AuthConfig{ Opts: optsWithTokenSource, ServiceAccountID: "test-service-account", + Version: testVersion, } signer, err := newIAMSigner(ctx, conf) if err != nil { @@ -155,6 +156,7 @@ func TestIAMSignerHTTPError(t *testing.T) { conf := &internal.AuthConfig{ Opts: optsWithTokenSource, ServiceAccountID: "test-service-account", + Version: testVersion, } signer, err := newIAMSigner(context.Background(), conf) if err != nil { @@ -182,6 +184,7 @@ func TestIAMSignerUnknownHTTPError(t *testing.T) { conf := &internal.AuthConfig{ Opts: optsWithTokenSource, ServiceAccountID: "test-service-account", + Version: testVersion, } signer, err := newIAMSigner(context.Background(), conf) if err != nil { @@ -208,7 +211,8 @@ func TestIAMSignerUnknownHTTPError(t *testing.T) { func TestIAMSignerWithMetadataService(t *testing.T) { ctx := context.Background() conf := &internal.AuthConfig{ - Opts: optsWithTokenSource, + Opts: optsWithTokenSource, + Version: testVersion, } signer, err := newIAMSigner(ctx, conf) @@ -253,7 +257,8 @@ func TestIAMSignerWithMetadataService(t *testing.T) { func TestIAMSignerNoMetadataService(t *testing.T) { ctx := context.Background() conf := &internal.AuthConfig{ - Opts: optsWithTokenSource, + Opts: optsWithTokenSource, + Version: testVersion, } signer, err := newIAMSigner(ctx, conf) @@ -340,6 +345,10 @@ func iamServer(t *testing.T, serviceAcct, signature string) *httptest.Server { if r.URL.Path != wantPath { t.Errorf("Path = %q; want = %q", r.URL.Path, wantPath) } + xGoogAPIClientHeader := internal.GetMetricsHeader(testVersion) + if h := r.Header.Get("x-goog-api-client"); h != xGoogAPIClientHeader { + t.Errorf("x-goog-api-client header = %q; want = %q", h, xGoogAPIClientHeader) + } w.Header().Set("Content-Type", "application/json") b, err := json.Marshal(resp) diff --git a/auth/user_mgt_test.go b/auth/user_mgt_test.go index 902ed280..97e64c39 100644 --- a/auth/user_mgt_test.go +++ b/auth/user_mgt_test.go @@ -24,7 +24,6 @@ import ( "net/http" "net/http/httptest" "reflect" - "runtime" "sort" "strconv" "strings" @@ -2317,7 +2316,7 @@ func echoServer(resp interface{}, t *testing.T) *mockAuthServer { } gh = r.Header.Get("x-goog-api-client") - wh = fmt.Sprintf("gl-go/%s fire-admin/%s", strings.TrimPrefix(runtime.Version(), "go"), testVersion) + wh = internal.GetMetricsHeader(testVersion) if gh != wh { t.Errorf("x-goog-api-client header = %q; want: %q", gh, wh) } diff --git a/firebase.go b/firebase.go index 8b1facd4..cd12a502 100644 --- a/firebase.go +++ b/firebase.go @@ -115,6 +115,7 @@ func (a *App) InstanceID(ctx context.Context) (*iid.Client, error) { conf := &internal.InstanceIDConfig{ ProjectID: a.projectID, Opts: a.opts, + Version: Version, } return iid.NewClient(ctx, conf) } @@ -133,6 +134,7 @@ func (a *App) Messaging(ctx context.Context) (*messaging.Client, error) { func (a *App) AppCheck(ctx context.Context) (*appcheck.Client, error) { conf := &internal.AppCheckConfig{ ProjectID: a.projectID, + Version: Version, } return appcheck.NewClient(ctx, conf) } diff --git a/iid/iid.go b/iid/iid.go index 96486a6a..259f3c36 100644 --- a/iid/iid.go +++ b/iid/iid.go @@ -116,6 +116,9 @@ func NewClient(ctx context.Context, c *internal.InstanceIDConfig) (*Client, erro } hc, _, err := internal.NewHTTPClient(ctx, c.Opts...) + hc.Opts = []internal.HTTPOption{ + internal.WithHeader("x-goog-api-client", internal.GetMetricsHeader(c.Version)), + } if err != nil { return nil, err } diff --git a/iid/iid_test.go b/iid/iid_test.go index c9134207..208da357 100644 --- a/iid/iid_test.go +++ b/iid/iid_test.go @@ -31,6 +31,7 @@ var testIIDConfig = &internal.InstanceIDConfig{ Opts: []option.ClientOption{ option.WithTokenSource(&internal.MockTokenSource{AccessToken: "test-token"}), }, + Version: "test-version", } func TestNoProjectID(t *testing.T) { @@ -83,6 +84,10 @@ func TestDeleteInstanceID(t *testing.T) { if h := tr.Header.Get("Authorization"); h != "Bearer test-token" { t.Errorf("Authorization = %q; want = %q", h, "Bearer test-token") } + xGoogAPIClientHeader := internal.GetMetricsHeader(testIIDConfig.Version) + if h := tr.Header.Get("x-goog-api-client"); h != xGoogAPIClientHeader { + t.Errorf("x-goog-api-client header = %q; want = %q", h, xGoogAPIClientHeader) + } } func TestDeleteInstanceIDError(t *testing.T) { @@ -156,6 +161,10 @@ func TestDeleteInstanceIDError(t *testing.T) { if h := tr.Header.Get("Authorization"); h != "Bearer test-token" { t.Errorf("Authorization = %q; want = %q", h, "Bearer test-token") } + xGoogAPIClientHeader := internal.GetMetricsHeader(testIIDConfig.Version) + if h := tr.Header.Get("x-goog-api-client"); h != xGoogAPIClientHeader { + t.Errorf("x-goog-api-client header = %q; want = %q", h, xGoogAPIClientHeader) + } tr = nil } } @@ -201,6 +210,10 @@ func TestDeleteInstanceIDUnexpectedError(t *testing.T) { if h := tr.Header.Get("Authorization"); h != "Bearer test-token" { t.Errorf("Authorization = %q; want = %q", h, "Bearer test-token") } + xGoogAPIClientHeader := internal.GetMetricsHeader(testIIDConfig.Version) + if h := tr.Header.Get("x-goog-api-client"); h != xGoogAPIClientHeader { + t.Errorf("x-goog-api-client header = %q; want = %q", h, xGoogAPIClientHeader) + } } func TestDeleteInstanceIDConnectionError(t *testing.T) { diff --git a/internal/http_client.go b/internal/http_client.go index 280aecc4..9adffefd 100644 --- a/internal/http_client.go +++ b/internal/http_client.go @@ -23,7 +23,9 @@ import ( "io/ioutil" "math" "net/http" + "runtime" "strconv" + "strings" "time" "google.golang.org/api/option" @@ -441,3 +443,8 @@ func retryNetworkAndHTTPErrors(statusCodes ...int) RetryCondition { return false } } + +func GetMetricsHeader(sdkVersion string) string { + goVersion := strings.TrimPrefix(runtime.Version(), "go") + return fmt.Sprintf("gl-go/%s fire-admin/%s", goVersion, sdkVersion) +} diff --git a/internal/internal.go b/internal/internal.go index 287391c5..fce5fcae 100644 --- a/internal/internal.go +++ b/internal/internal.go @@ -50,6 +50,7 @@ type HashConfig map[string]interface{} type InstanceIDConfig struct { Opts []option.ClientOption ProjectID string + Version string } // DatabaseConfig represents the configuration of Firebase Database service. @@ -76,6 +77,7 @@ type MessagingConfig struct { // AppCheckConfig represents the configuration of App Check service. type AppCheckConfig struct { ProjectID string + Version string } // MockTokenSource is a TokenSource implementation that can be used for testing. diff --git a/messaging/messaging.go b/messaging/messaging.go index 525cccb6..dcd412c3 100644 --- a/messaging/messaging.go +++ b/messaging/messaging.go @@ -23,7 +23,6 @@ import ( "fmt" "net/http" "regexp" - "runtime" "strconv" "strings" "time" @@ -878,7 +877,7 @@ func NewClient(ctx context.Context, c *internal.MessagingConfig) (*Client, error return &Client{ fcmClient: newFCMClient(hc, c, messagingEndpoint, batchEndpoint), - iidClient: newIIDClient(hc), + iidClient: newIIDClient(hc, c), }, nil } @@ -894,12 +893,11 @@ func newFCMClient(hc *http.Client, conf *internal.MessagingConfig, messagingEndp client := internal.WithDefaultRetryConfig(hc) client.CreateErrFn = handleFCMError - goVersion := strings.TrimPrefix(runtime.Version(), "go") version := fmt.Sprintf("fire-admin-go/%s", conf.Version) client.Opts = []internal.HTTPOption{ internal.WithHeader(apiFormatVersionHeader, apiFormatVersion), internal.WithHeader(firebaseClientHeader, version), - internal.WithHeader("x-goog-api-client", fmt.Sprintf("gl-go/%s fire-admin/%s", goVersion, conf.Version)), + internal.WithHeader("x-goog-api-client", internal.GetMetricsHeader(conf.Version)), } return &fcmClient{ diff --git a/messaging/messaging_test.go b/messaging/messaging_test.go index 8b31fc46..dceed542 100644 --- a/messaging/messaging_test.go +++ b/messaging/messaging_test.go @@ -21,8 +21,6 @@ import ( "net/http" "net/http/httptest" "reflect" - "runtime" - "strings" "testing" "time" @@ -1396,8 +1394,7 @@ func checkFCMRequest(t *testing.T, b []byte, tr *http.Request, want map[string]i if h := tr.Header.Get("X-FIREBASE-CLIENT"); h != clientVersion { t.Errorf("X-FIREBASE-CLIENT = %q; want = %q", h, clientVersion) } - goVersion := strings.TrimPrefix(runtime.Version(), "go") - xGoogAPIClientHeader := "gl-go/" + goVersion + " fire-admin/" + testMessagingConfig.Version + xGoogAPIClientHeader := internal.GetMetricsHeader(testMessagingConfig.Version) if h := tr.Header.Get("x-goog-api-client"); h != xGoogAPIClientHeader { t.Errorf("x-goog-api-client header = %q; want = %q", h, xGoogAPIClientHeader) } diff --git a/messaging/topic_mgt.go b/messaging/topic_mgt.go index 15a29787..88492585 100644 --- a/messaging/topic_mgt.go +++ b/messaging/topic_mgt.go @@ -63,10 +63,13 @@ type iidClient struct { httpClient *internal.HTTPClient } -func newIIDClient(hc *http.Client) *iidClient { +func newIIDClient(hc *http.Client, conf *internal.MessagingConfig) *iidClient { client := internal.WithDefaultRetryConfig(hc) client.CreateErrFn = handleIIDError - client.Opts = []internal.HTTPOption{internal.WithHeader("access_token_auth", "true")} + client.Opts = []internal.HTTPOption{ + internal.WithHeader("access_token_auth", "true"), + internal.WithHeader("x-goog-api-client", internal.GetMetricsHeader(conf.Version)), + } return &iidClient{ iidEndpoint: iidEndpoint, httpClient: client, diff --git a/messaging/topic_mgt_test.go b/messaging/topic_mgt_test.go index 15ea45d1..6d58114d 100644 --- a/messaging/topic_mgt_test.go +++ b/messaging/topic_mgt_test.go @@ -25,6 +25,7 @@ import ( "testing" "firebase.google.com/go/v4/errorutils" + "firebase.google.com/go/v4/internal" ) func TestSubscribe(t *testing.T) { @@ -198,6 +199,10 @@ func checkIIDRequest(t *testing.T, b []byte, tr *http.Request, op string) { if h := tr.Header.Get("Authorization"); h != "Bearer test-token" { t.Errorf("Authorization = %q; want = %q", h, "Bearer test-token") } + xGoogAPIClientHeader := internal.GetMetricsHeader(testMessagingConfig.Version) + if h := tr.Header.Get("x-goog-api-client"); h != xGoogAPIClientHeader { + t.Errorf("x-goog-api-client header = %q; want = %q", h, xGoogAPIClientHeader) + } } func checkTopicMgtResponse(t *testing.T, resp *TopicManagementResponse) { From c04763b4559d080430a5b1dbb8db745a88fc6655 Mon Sep 17 00:00:00 2001 From: Jonathan Edey Date: Tue, 19 Nov 2024 13:01:03 -0500 Subject: [PATCH 2/3] Fix lint and test --- auth/token_generator.go | 6 +++--- iid/iid.go | 6 +++--- internal/http_client.go | 1 + 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/auth/token_generator.go b/auth/token_generator.go index ddf777be..7aa2d564 100644 --- a/auth/token_generator.go +++ b/auth/token_generator.go @@ -172,12 +172,12 @@ type iamSigner struct { func newIAMSigner(ctx context.Context, config *internal.AuthConfig) (*iamSigner, error) { hc, _, err := internal.NewHTTPClient(ctx, config.Opts...) - hc.Opts = []internal.HTTPOption{ - internal.WithHeader("x-goog-api-client", internal.GetMetricsHeader(config.Version)), - } if err != nil { return nil, err } + hc.Opts = []internal.HTTPOption{ + internal.WithHeader("x-goog-api-client", internal.GetMetricsHeader(config.Version)), + } return &iamSigner{ mutex: &sync.Mutex{}, diff --git a/iid/iid.go b/iid/iid.go index 259f3c36..7a3e9b55 100644 --- a/iid/iid.go +++ b/iid/iid.go @@ -116,12 +116,12 @@ func NewClient(ctx context.Context, c *internal.InstanceIDConfig) (*Client, erro } hc, _, err := internal.NewHTTPClient(ctx, c.Opts...) - hc.Opts = []internal.HTTPOption{ - internal.WithHeader("x-goog-api-client", internal.GetMetricsHeader(c.Version)), - } if err != nil { return nil, err } + hc.Opts = []internal.HTTPOption{ + internal.WithHeader("x-goog-api-client", internal.GetMetricsHeader(c.Version)), + } hc.CreateErrFn = createError return &Client{ diff --git a/internal/http_client.go b/internal/http_client.go index 9adffefd..9463f98e 100644 --- a/internal/http_client.go +++ b/internal/http_client.go @@ -444,6 +444,7 @@ func retryNetworkAndHTTPErrors(statusCodes ...int) RetryCondition { } } +// GetMetricsHeader constructs header value for metrics attribution func GetMetricsHeader(sdkVersion string) string { goVersion := strings.TrimPrefix(runtime.Version(), "go") return fmt.Sprintf("gl-go/%s fire-admin/%s", goVersion, sdkVersion) From 4bd3b45777475b350b714b9dfe1bdc66f0177e4a Mon Sep 17 00:00:00 2001 From: Jonathan Edey Date: Wed, 20 Nov 2024 14:31:14 -0500 Subject: [PATCH 3/3] Remove App Check headers --- appcheck/appcheck.go | 19 ------------------- appcheck/appcheck_test.go | 37 ++++++++++++++++--------------------- firebase.go | 1 - internal/internal.go | 1 - 4 files changed, 16 insertions(+), 42 deletions(-) diff --git a/appcheck/appcheck.go b/appcheck/appcheck.go index 08ce9cdb..89868916 100644 --- a/appcheck/appcheck.go +++ b/appcheck/appcheck.go @@ -18,7 +18,6 @@ package appcheck import ( "context" "errors" - "net/http" "strings" "time" @@ -78,7 +77,6 @@ func NewClient(ctx context.Context, conf *internal.AppCheckConfig) (*Client, err jwks, err := keyfunc.Get(JWKSUrl, keyfunc.Options{ Ctx: ctx, RefreshInterval: 6 * time.Hour, - RequestFactory: makeRequestFactory(conf), }) if err != nil { return nil, err @@ -90,23 +88,6 @@ func NewClient(ctx context.Context, conf *internal.AppCheckConfig) (*Client, err }, nil } -func makeRequestFactory(conf *internal.AppCheckConfig) func(ctx context.Context, url string) (*http.Request, error) { - opts := []internal.HTTPOption{ - internal.WithHeader("x-goog-api-client", internal.GetMetricsHeader(conf.Version)), - } - - return func(ctx context.Context, url string) (*http.Request, error) { - hr, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) - if err != nil { - return nil, err - } - for _, o := range opts { - o(hr) - } - return hr, nil - } -} - // VerifyToken verifies the given App Check token. // // VerifyToken considers an App Check token string to be valid if all the following conditions are met: diff --git a/appcheck/appcheck_test.go b/appcheck/appcheck_test.go index 7e5e6026..6cd088c0 100644 --- a/appcheck/appcheck_test.go +++ b/appcheck/appcheck_test.go @@ -17,14 +17,8 @@ import ( "github.com/google/go-cmp/cmp" ) -var testAppCheckConfig = &internal.AppCheckConfig{ - ProjectID: "project_id", - Version: "test-version", -} - func TestVerifyTokenHasValidClaims(t *testing.T) { - var tr http.Request - ts, err := setupFakeJWKS(&tr) + ts, err := setupFakeJWKS() if err != nil { t.Fatalf("Error setting up fake JWKS server: %v", err) } @@ -36,17 +30,15 @@ func TestVerifyTokenHasValidClaims(t *testing.T) { } JWKSUrl = ts.URL + conf := &internal.AppCheckConfig{ + ProjectID: "project_id", + } - client, err := NewClient(context.Background(), testAppCheckConfig) + client, err := NewClient(context.Background(), conf) if err != nil { t.Errorf("Error creating NewClient: %v", err) } - xGoogAPIClientHeader := internal.GetMetricsHeader(testAppCheckConfig.Version) - if h := tr.Header.Get("x-goog-api-client"); h != xGoogAPIClientHeader { - t.Errorf("x-goog-api-client header = %q; want = %q", h, xGoogAPIClientHeader) - } - type appCheckClaims struct { Aud []string `json:"aud"` jwt.RegisteredClaims @@ -177,16 +169,18 @@ func TestVerifyTokenHasValidClaims(t *testing.T) { } func TestVerifyTokenMustExist(t *testing.T) { - var tr http.Request - ts, err := setupFakeJWKS(&tr) + ts, err := setupFakeJWKS() if err != nil { t.Fatalf("Error setting up fake JWK server: %v", err) } defer ts.Close() JWKSUrl = ts.URL + conf := &internal.AppCheckConfig{ + ProjectID: "project_id", + } - client, err := NewClient(context.Background(), testAppCheckConfig) + client, err := NewClient(context.Background(), conf) if err != nil { t.Errorf("Error creating NewClient: %v", err) } @@ -203,8 +197,7 @@ func TestVerifyTokenMustExist(t *testing.T) { } func TestVerifyTokenNotExpired(t *testing.T) { - var tr http.Request - ts, err := setupFakeJWKS(&tr) + ts, err := setupFakeJWKS() if err != nil { t.Fatalf("Error setting up fake JWKS server: %v", err) } @@ -216,8 +209,11 @@ func TestVerifyTokenNotExpired(t *testing.T) { } JWKSUrl = ts.URL + conf := &internal.AppCheckConfig{ + ProjectID: "project_id", + } - client, err := NewClient(context.Background(), testAppCheckConfig) + client, err := NewClient(context.Background(), conf) if err != nil { t.Errorf("Error creating NewClient: %v", err) } @@ -268,13 +264,12 @@ func TestVerifyTokenNotExpired(t *testing.T) { } } -func setupFakeJWKS(tr *http.Request) (*httptest.Server, error) { +func setupFakeJWKS() (*httptest.Server, error) { jwks, err := os.ReadFile("../testdata/mock.jwks.json") if err != nil { return nil, err } ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - *tr = *r w.Write(jwks) })) return ts, nil diff --git a/firebase.go b/firebase.go index cd12a502..98e04a07 100644 --- a/firebase.go +++ b/firebase.go @@ -134,7 +134,6 @@ func (a *App) Messaging(ctx context.Context) (*messaging.Client, error) { func (a *App) AppCheck(ctx context.Context) (*appcheck.Client, error) { conf := &internal.AppCheckConfig{ ProjectID: a.projectID, - Version: Version, } return appcheck.NewClient(ctx, conf) } diff --git a/internal/internal.go b/internal/internal.go index fce5fcae..9fb9e726 100644 --- a/internal/internal.go +++ b/internal/internal.go @@ -77,7 +77,6 @@ type MessagingConfig struct { // AppCheckConfig represents the configuration of App Check service. type AppCheckConfig struct { ProjectID string - Version string } // MockTokenSource is a TokenSource implementation that can be used for testing.