From dcef2aebda043564167d32ef8d6ea86516048976 Mon Sep 17 00:00:00 2001 From: Jonathan Edey <145066863+jonathanedey@users.noreply.github.com> Date: Thu, 7 Nov 2024 16:04:42 -0500 Subject: [PATCH] chore: Add `X-Goog-Api-Client` metric header to outgoing authorized http requests (#2763) * chore: Add `X-Goog-Api-Client` metric header to outgoing requests * fix lint * remove quota project id headers from HTTP/2 --- src/auth/auth-api-request.ts | 1 - .../messaging-api-request-internal.ts | 1 - src/utils/api-request.ts | 6 ++ src/utils/index.ts | 4 ++ .../app-check-api-client-internal.spec.ts | 3 +- test/unit/auth/auth-api-request.spec.ts | 6 +- .../data-connect-api-client-internal.spec.ts | 3 +- test/unit/database/database.spec.ts | 3 + test/unit/eventarc/eventarc.spec.ts | 70 ++++++------------- .../extensions-api-client-internal.spec.ts | 31 +++++--- .../functions-api-client-internal.spec.ts | 3 +- .../installations-request-handler.spec.ts | 2 + .../machine-learning-api-client.spec.ts | 3 +- test/unit/messaging/messaging.spec.ts | 4 +- .../project-management-api-request.spec.ts | 3 +- .../remote-config-api-client.spec.ts | 3 +- .../security-rules-api-client.spec.ts | 3 +- test/unit/utils/crypto-signer.spec.ts | 11 ++- 18 files changed, 86 insertions(+), 74 deletions(-) diff --git a/src/auth/auth-api-request.ts b/src/auth/auth-api-request.ts index 3d782fb775..cd9c145b1e 100644 --- a/src/auth/auth-api-request.ts +++ b/src/auth/auth-api-request.ts @@ -47,7 +47,6 @@ import { ProjectConfig, ProjectConfigServerResponse, UpdateProjectConfigRequest /** Firebase Auth request header. */ const FIREBASE_AUTH_HEADERS = { 'X-Client-Version': `Node/Admin/${utils.getSdkVersion()}`, - 'X-Goog-Api-Client': `gl-node/${process.versions.node} fire-admin/${utils.getSdkVersion()}` }; /** Firebase Auth request timeout duration in milliseconds. */ const FIREBASE_AUTH_TIMEOUT = 25000; diff --git a/src/messaging/messaging-api-request-internal.ts b/src/messaging/messaging-api-request-internal.ts index 07621978f3..830fbed568 100644 --- a/src/messaging/messaging-api-request-internal.ts +++ b/src/messaging/messaging-api-request-internal.ts @@ -31,7 +31,6 @@ const FIREBASE_MESSAGING_TIMEOUT = 15000; const FIREBASE_MESSAGING_HTTP_METHOD: HttpMethod = 'POST'; const FIREBASE_MESSAGING_HEADERS = { 'X-Firebase-Client': `fire-admin-node/${getSdkVersion()}`, - 'X-Goog-Api-Client': `gl-node/${process.versions.node} fire-admin/${getSdkVersion()}`, 'access_token_auth': 'true', }; diff --git a/src/utils/api-request.ts b/src/utils/api-request.ts index 69406c27ea..d64e0a2762 100644 --- a/src/utils/api-request.ts +++ b/src/utils/api-request.ts @@ -26,6 +26,7 @@ import url = require('url'); import { EventEmitter } from 'events'; import { Readable } from 'stream'; import * as zlibmod from 'zlib'; +import { getMetricsHeader } from '../utils/index'; /** Http method type definition. */ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD'; @@ -1085,6 +1086,9 @@ export class AuthorizedHttpClient extends HttpClient { if (!requestCopy.httpAgent && this.app.options.httpAgent) { requestCopy.httpAgent = this.app.options.httpAgent; } + + requestCopy.headers['X-Goog-Api-Client'] = getMetricsHeader() + return super.send(requestCopy); }); } @@ -1108,6 +1112,8 @@ export class AuthorizedHttp2Client extends Http2Client { const authHeader = 'Authorization'; requestCopy.headers[authHeader] = `Bearer ${token}`; + requestCopy.headers['X-Goog-Api-Client'] = getMetricsHeader() + return super.send(requestCopy); }); } diff --git a/src/utils/index.ts b/src/utils/index.ts index ebc405ad8e..c7c331206d 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -32,6 +32,10 @@ export function getSdkVersion(): string { return sdkVersion; } +export function getMetricsHeader(): string { + return `gl-node/${process.versions.node} fire-admin/${getSdkVersion()}` +} + /** * Renames properties on an object given a mapping from old to new property names. * diff --git a/test/unit/app-check/app-check-api-client-internal.spec.ts b/test/unit/app-check/app-check-api-client-internal.spec.ts index e5a483d91c..3f2746cf59 100644 --- a/test/unit/app-check/app-check-api-client-internal.spec.ts +++ b/test/unit/app-check/app-check-api-client-internal.spec.ts @@ -23,7 +23,7 @@ import * as sinon from 'sinon'; import { HttpClient } from '../../../src/utils/api-request'; import * as utils from '../utils'; import * as mocks from '../../resources/mocks'; -import { getSdkVersion } from '../../../src/utils'; +import { getMetricsHeader, getSdkVersion } from '../../../src/utils'; import { FirebaseApp } from '../../../src/app/firebase-app'; import { AppCheckApiClient, FirebaseAppCheckError } from '../../../src/app-check/app-check-api-client-internal'; @@ -46,6 +46,7 @@ describe('AppCheckApiClient', () => { 'Authorization': 'Bearer mock-token', 'X-Firebase-Client': `fire-admin-node/${getSdkVersion()}`, 'x-goog-user-project': 'test-project', + 'X-Goog-Api-Client': getMetricsHeader(), }; const noProjectId = 'Failed to determine project ID. Initialize the SDK with service ' diff --git a/test/unit/auth/auth-api-request.spec.ts b/test/unit/auth/auth-api-request.spec.ts index 8abbc80247..bd789421b8 100644 --- a/test/unit/auth/auth-api-request.spec.ts +++ b/test/unit/auth/auth-api-request.spec.ts @@ -42,7 +42,7 @@ import { AuthClientErrorCode, FirebaseAuthError } from '../../../src/utils/error import { ActionCodeSettingsBuilder } from '../../../src/auth/action-code-settings-builder'; import { SAMLConfigServerResponse } from '../../../src/auth/auth-config'; import { expectUserImportResult } from './user-import-builder.spec'; -import { getSdkVersion } from '../../../src/utils/index'; +import { getMetricsHeader, getSdkVersion } from '../../../src/utils/index'; import { UserImportRecord, OIDCAuthProviderConfig, SAMLAuthProviderConfig, OIDCUpdateAuthProviderRequest, SAMLUpdateAuthProviderRequest, UserIdentifier, UpdateRequest, UpdateMultiFactorInfoRequest, @@ -863,12 +863,12 @@ AUTH_REQUEST_HANDLER_TESTS.forEach((handler) => { const mockAccessToken: string = utils.generateRandomAccessToken(); const expectedHeaders: {[key: string]: string} = { 'X-Client-Version': `Node/Admin/${getSdkVersion()}`, - 'X-Goog-Api-Client': `gl-node/${process.versions.node} fire-admin/${getSdkVersion()}`, + 'X-Goog-Api-Client': getMetricsHeader(), 'Authorization': 'Bearer ' + mockAccessToken, }; const expectedHeadersEmulator: {[key: string]: string} = { 'X-Client-Version': `Node/Admin/${getSdkVersion()}`, - 'X-Goog-Api-Client': `gl-node/${process.versions.node} fire-admin/${getSdkVersion()}`, + 'X-Goog-Api-Client': getMetricsHeader(), 'Authorization': 'Bearer owner', }; const callParams = (path: string, method: any, data: any): HttpRequestConfig => { diff --git a/test/unit/data-connect/data-connect-api-client-internal.spec.ts b/test/unit/data-connect/data-connect-api-client-internal.spec.ts index aa45f53b9c..0815515204 100644 --- a/test/unit/data-connect/data-connect-api-client-internal.spec.ts +++ b/test/unit/data-connect/data-connect-api-client-internal.spec.ts @@ -28,7 +28,7 @@ import { DataConnectApiClient, FirebaseDataConnectError } from '../../../src/data-connect/data-connect-api-client-internal'; import { FirebaseApp } from '../../../src/app/firebase-app'; import { ConnectorConfig } from '../../../src/data-connect'; -import { getSdkVersion } from '../../../src/utils'; +import { getMetricsHeader, getSdkVersion } from '../../../src/utils'; describe('DataConnectApiClient', () => { @@ -44,6 +44,7 @@ describe('DataConnectApiClient', () => { 'Authorization': 'Bearer mock-token', 'X-Firebase-Client': `fire-admin-node/${getSdkVersion()}`, 'x-goog-user-project': 'test-project', + 'X-Goog-Api-Client': getMetricsHeader(), }; const noProjectId = 'Failed to determine project ID. Initialize the SDK with service ' diff --git a/test/unit/database/database.spec.ts b/test/unit/database/database.spec.ts index ce86082842..5032deb3c3 100644 --- a/test/unit/database/database.spec.ts +++ b/test/unit/database/database.spec.ts @@ -27,6 +27,7 @@ import { Database, DatabaseService } from '../../../src/database/database'; import { ServiceAccountCredential } from '../../../src/app/credential-internal'; import * as utils from '../utils'; import { HttpClient, HttpRequestConfig } from '../../../src/utils/api-request'; +import { getMetricsHeader } from '../../../src/utils'; describe('Database', () => { let mockApp: FirebaseApp; @@ -332,6 +333,7 @@ describe('Database', () => { url, headers: { Authorization: 'Bearer ' + mockAccessToken, + 'X-Goog-Api-Client': getMetricsHeader(), }, }; @@ -485,6 +487,7 @@ describe('Database', () => { headers: { 'Authorization': 'Bearer ' + mockAccessToken, 'content-type': 'application/json; charset=utf-8', + 'X-Goog-Api-Client': getMetricsHeader(), }, data, }; diff --git a/test/unit/eventarc/eventarc.spec.ts b/test/unit/eventarc/eventarc.spec.ts index 1bbddd5a4d..94587cde16 100644 --- a/test/unit/eventarc/eventarc.spec.ts +++ b/test/unit/eventarc/eventarc.spec.ts @@ -27,7 +27,7 @@ import * as mocks from '../../resources/mocks'; import * as utils from '../utils'; import * as chai from 'chai'; import chaiExclude from 'chai-exclude'; -import { getSdkVersion } from '../../../src/utils/index'; +import { getMetricsHeader, getSdkVersion } from '../../../src/utils/index'; const expect = chai.expect; chai.use(chaiExclude); @@ -56,6 +56,14 @@ describe('eventarc', () => { let mockApp: FirebaseApp; let eventarc: Eventarc; + const getExpectedHeaders = (mockAccessToken: string): object => { + return { + 'X-Firebase-Client': 'fire-admin-node/' + getSdkVersion(), + Authorization: 'Bearer ' + mockAccessToken, + 'X-Goog-Api-Client': getMetricsHeader(), + } + } + before(() => { mockApp = mocks.app(); eventarc = new Eventarc(mockApp); @@ -133,10 +141,7 @@ describe('eventarc', () => { method: 'POST', url: 'https://eventarcpublishing.googleapis.com/v1/projects/project_id/locations/us-central1/channels/firebase:publishEvents', data: `{"events":[${TEST_EVENT1_SERIALIZED}]}`, - headers: { - 'X-Firebase-Client': 'fire-admin-node/' + getSdkVersion(), - Authorization: 'Bearer ' + mockAccessToken - } + headers: getExpectedHeaders(mockAccessToken) }); }); @@ -151,10 +156,7 @@ describe('eventarc', () => { method: 'POST', url: 'https://eventarcpublishing.googleapis.com/v1/projects/project_id/locations/us-central1/channels/firebase:publishEvents', data: `{"events":[${TEST_EVENT1_SERIALIZED},${TEST_EVENT2_SERIALIZED}]}`, - headers: { - 'X-Firebase-Client': 'fire-admin-node/' + getSdkVersion(), - Authorization: 'Bearer ' + mockAccessToken - } + headers: getExpectedHeaders(mockAccessToken) }); }); }); @@ -196,10 +198,7 @@ describe('eventarc', () => { method: 'POST', url: 'https://eventarcpublishing.googleapis.com/v1/projects/other-project-id/locations/us-west1/channels/my-channel2:publishEvents', data: `{"events":[${TEST_EVENT1_SERIALIZED}]}`, - headers: { - 'X-Firebase-Client': 'fire-admin-node/' + getSdkVersion(), - Authorization: 'Bearer ' + mockAccessToken - } + headers: getExpectedHeaders(mockAccessToken) }); }); @@ -214,10 +213,7 @@ describe('eventarc', () => { method: 'POST', url: 'https://eventarcpublishing.googleapis.com/v1/projects/other-project-id/locations/us-west1/channels/my-channel2:publishEvents', data: `{"events":[${TEST_EVENT1_SERIALIZED},${TEST_EVENT2_SERIALIZED}]}`, - headers: { - 'X-Firebase-Client': 'fire-admin-node/' + getSdkVersion(), - Authorization: 'Bearer ' + mockAccessToken - } + headers: getExpectedHeaders(mockAccessToken) }); }); }); @@ -259,10 +255,7 @@ describe('eventarc', () => { method: 'POST', url: 'https://eventarcpublishing.googleapis.com/v1/projects/project_id/locations/us-west1/channels/my-channel:publishEvents', data: `{"events":[${TEST_EVENT1_SERIALIZED}]}`, - headers: { - 'X-Firebase-Client': 'fire-admin-node/' + getSdkVersion(), - Authorization: 'Bearer ' + mockAccessToken - } + headers: getExpectedHeaders(mockAccessToken) }); }); @@ -277,10 +270,7 @@ describe('eventarc', () => { method: 'POST', url: 'https://eventarcpublishing.googleapis.com/v1/projects/project_id/locations/us-west1/channels/my-channel:publishEvents', data: `{"events":[${TEST_EVENT1_SERIALIZED},${TEST_EVENT2_SERIALIZED}]}`, - headers: { - 'X-Firebase-Client': 'fire-admin-node/' + getSdkVersion(), - Authorization: 'Bearer ' + mockAccessToken - } + headers: getExpectedHeaders(mockAccessToken) }); }); }); @@ -322,10 +312,7 @@ describe('eventarc', () => { method: 'POST', url: 'https://eventarcpublishing.googleapis.com/v1/projects/project_id/locations/us-central1/channels/my-channel:publishEvents', data: `{"events":[${TEST_EVENT1_SERIALIZED}]}`, - headers: { - 'X-Firebase-Client': 'fire-admin-node/' + getSdkVersion(), - Authorization: 'Bearer ' + mockAccessToken - } + headers: getExpectedHeaders(mockAccessToken) }); }); @@ -340,10 +327,7 @@ describe('eventarc', () => { method: 'POST', url: 'https://eventarcpublishing.googleapis.com/v1/projects/project_id/locations/us-central1/channels/my-channel:publishEvents', data: `{"events":[${TEST_EVENT1_SERIALIZED},${TEST_EVENT2_SERIALIZED}]}`, - headers: { - 'X-Firebase-Client': 'fire-admin-node/' + getSdkVersion(), - Authorization: 'Bearer ' + mockAccessToken - } + headers: getExpectedHeaders(mockAccessToken) }); }); }); @@ -478,10 +462,7 @@ describe('eventarc', () => { method: 'POST', url: 'https://eventarcpublishing.googleapis.com/v1/projects/project_id/locations/us-central1/channels/firebase:publishEvents', data: `{"events":[${TEST_EVENT1_SERIALIZED}]}`, - headers: { - 'X-Firebase-Client': 'fire-admin-node/' + getSdkVersion(), - Authorization: 'Bearer ' + mockAccessToken - } + headers: getExpectedHeaders(mockAccessToken) }); }); @@ -498,10 +479,7 @@ describe('eventarc', () => { method: 'POST', url: 'https://eventarcpublishing.googleapis.com/v1/projects/project_id/locations/us-central1/channels/firebase:publishEvents', data: `{"events":[${TEST_EVENT1_SERIALIZED}]}`, - headers: { - 'X-Firebase-Client': 'fire-admin-node/' + getSdkVersion(), - Authorization: 'Bearer ' + mockAccessToken - } + headers: getExpectedHeaders(mockAccessToken) }); }); }); @@ -542,10 +520,7 @@ describe('eventarc', () => { method: 'POST', url: 'https://eventarcpublishing.googleapis.com/v1/projects/project_id/locations/us-central1/channels/firebase:publishEvents', data: `{"events":[${TEST_EVENT1_SERIALIZED}]}`, - headers: { - 'X-Firebase-Client': 'fire-admin-node/' + getSdkVersion(), - Authorization: 'Bearer ' + mockAccessToken - } + headers: getExpectedHeaders(mockAccessToken) }); }); @@ -562,10 +537,7 @@ describe('eventarc', () => { method: 'POST', url: 'https://eventarcpublishing.googleapis.com/v1/projects/project_id/locations/us-central1/channels/firebase:publishEvents', data: `{"events":[${TEST_EVENT1_SERIALIZED}]}`, - headers: { - 'X-Firebase-Client': 'fire-admin-node/' + getSdkVersion(), - Authorization: 'Bearer ' + mockAccessToken - } + headers: getExpectedHeaders(mockAccessToken) }); }); }); diff --git a/test/unit/extensions/extensions-api-client-internal.spec.ts b/test/unit/extensions/extensions-api-client-internal.spec.ts index a95baff154..32213b8068 100644 --- a/test/unit/extensions/extensions-api-client-internal.spec.ts +++ b/test/unit/extensions/extensions-api-client-internal.spec.ts @@ -22,8 +22,9 @@ import * as utils from '../utils'; import * as mocks from '../../resources/mocks'; import { FirebaseApp } from '../../../src/app/firebase-app'; import { ExtensionsApiClient, FirebaseExtensionsError } from '../../../src/extensions/extensions-api-client-internal'; -import { HttpClient, HttpRequestConfig } from '../../../src/utils/api-request'; +import { HttpClient } from '../../../src/utils/api-request'; import { SettableProcessingState } from '../../../src/extensions/extensions-api'; +import { getMetricsHeader, getSdkVersion } from '../../../src/utils'; const testProjectId = 'test-project'; const testInstanceId = 'test-instance'; @@ -38,6 +39,13 @@ describe('Extension API client', () => { projectId: 'test-project', serviceAccountId: 'service-acct@email.com' }; + + const EXPECTED_HEADERS = { + 'Authorization': 'Bearer mock-token', + 'X-Firebase-Client': `fire-admin-node/${getSdkVersion()}`, + 'x-goog-user-project': 'test-project', + 'X-Goog-Api-Client': getMetricsHeader(), + } before(() => { app = mocks.appWithOptions(mockOptions); @@ -71,14 +79,19 @@ describe('Extension API client', () => { detailMessage: 'done processing', }, } - const expected = sinon.match((req: HttpRequestConfig) => { - const url = 'https://firebaseextensions.googleapis.com/' + - 'v1beta/projects/test-project/instances/test-instance/runtimeData'; - return req.method == 'PATCH' && req.url == url && req.data == testRuntimeData; - }, 'Incorrect URL or Method'); - httpClientStub.withArgs(expected).resolves(utils.responseFrom(testRuntimeData, 200)); - await expect(apiClient.updateRuntimeData(testProjectId, testInstanceId, testRuntimeData)) - .to.eventually.deep.equal(testRuntimeData); + const url = 'https://firebaseextensions.googleapis.com/' + + 'v1beta/projects/test-project/instances/test-instance/runtimeData'; + httpClientStub = httpClientStub.resolves(utils.responseFrom(testRuntimeData, 200)); + return apiClient.updateRuntimeData(testProjectId, testInstanceId, testRuntimeData) + .then((runtimeData) => { + expect(runtimeData).to.deep.equal(testRuntimeData) + expect(httpClientStub).to.have.been.calledOnce.and.calledWith({ + method: 'PATCH', + url: url, + headers: EXPECTED_HEADERS, + data: testRuntimeData + }) + }) }); it('should convert errors in FirebaseErrors', async () => { diff --git a/test/unit/functions/functions-api-client-internal.spec.ts b/test/unit/functions/functions-api-client-internal.spec.ts index bb1ae0bfbd..40e24b1fea 100644 --- a/test/unit/functions/functions-api-client-internal.spec.ts +++ b/test/unit/functions/functions-api-client-internal.spec.ts @@ -22,7 +22,7 @@ import * as chai from 'chai'; import * as sinon from 'sinon'; import * as utils from '../utils'; import * as mocks from '../../resources/mocks'; -import { getSdkVersion } from '../../../src/utils'; +import { getSdkVersion, getMetricsHeader } from '../../../src/utils'; import { FirebaseApp } from '../../../src/app/firebase-app'; import { FirebaseFunctionsError, FunctionsApiClient, Task } from '../../../src/functions/functions-api-client-internal'; @@ -47,6 +47,7 @@ describe('FunctionsApiClient', () => { 'X-Firebase-Client': `fire-admin-node/${getSdkVersion()}`, 'Authorization': 'Bearer mock-token', 'x-goog-user-project': 'test-project', + 'X-Goog-Api-Client': getMetricsHeader(), }; const noProjectId = 'Failed to determine project ID. Initialize the SDK with service ' diff --git a/test/unit/installations/installations-request-handler.spec.ts b/test/unit/installations/installations-request-handler.spec.ts index 36e696dd2d..8baeaa3de8 100644 --- a/test/unit/installations/installations-request-handler.spec.ts +++ b/test/unit/installations/installations-request-handler.spec.ts @@ -29,6 +29,7 @@ import * as mocks from '../../resources/mocks'; import { FirebaseApp } from '../../../src/app/firebase-app'; import { HttpClient } from '../../../src/utils/api-request'; import { FirebaseInstallationsRequestHandler } from '../../../src/installations/installations-request-handler'; +import { getMetricsHeader } from '../../../src/utils'; chai.should(); chai.use(sinonChai); @@ -57,6 +58,7 @@ describe('FirebaseInstallationsRequestHandler', () => { mockApp = mocks.app(); expectedHeaders = { Authorization: 'Bearer ' + mockAccessToken, + 'X-Goog-Api-Client': getMetricsHeader(), }; return mockApp.INTERNAL.getToken(); }); diff --git a/test/unit/machine-learning/machine-learning-api-client.spec.ts b/test/unit/machine-learning/machine-learning-api-client.spec.ts index 4d6873d200..c77380f2f3 100644 --- a/test/unit/machine-learning/machine-learning-api-client.spec.ts +++ b/test/unit/machine-learning/machine-learning-api-client.spec.ts @@ -25,7 +25,7 @@ import * as utils from '../utils'; import * as mocks from '../../resources/mocks'; import { FirebaseAppError } from '../../../src/utils/error'; import { FirebaseApp } from '../../../src/app/firebase-app'; -import { getSdkVersion } from '../../../src/utils/index'; +import { getMetricsHeader, getSdkVersion } from '../../../src/utils/index'; import { MachineLearningApiClient } from '../../../src/machine-learning/machine-learning-api-client'; import { ListModelsOptions, ModelOptions } from '../../../src/machine-learning/index'; @@ -118,6 +118,7 @@ describe('MachineLearningApiClient', () => { 'Authorization': 'Bearer mock-token', 'X-Firebase-Client': `fire-admin-node/${getSdkVersion()}`, 'x-goog-user-project': 'test-project', + 'X-Goog-Api-Client': getMetricsHeader(), }; const noProjectId = 'Failed to determine project ID. Initialize the SDK with service ' + 'account credentials, or set project ID as an app option. Alternatively, set the ' diff --git a/test/unit/messaging/messaging.spec.ts b/test/unit/messaging/messaging.spec.ts index 6a14f17171..488056488e 100644 --- a/test/unit/messaging/messaging.spec.ts +++ b/test/unit/messaging/messaging.spec.ts @@ -32,7 +32,7 @@ import { SendResponse, MulticastMessage, Messaging, TokenMessage, TopicMessage, ConditionMessage, } from '../../../src/messaging/index'; import { HttpClient } from '../../../src/utils/api-request'; -import { getSdkVersion } from '../../../src/utils/index'; +import { getMetricsHeader, getSdkVersion } from '../../../src/utils/index'; import * as utils from '../utils'; chai.should(); @@ -218,7 +218,7 @@ describe('Messaging', () => { const expectedHeaders = { 'Authorization': 'Bearer ' + mockAccessToken, 'X-Firebase-Client': `fire-admin-node/${getSdkVersion()}`, - 'X-Goog-Api-Client': `gl-node/${process.versions.node} fire-admin/${getSdkVersion()}`, + 'X-Goog-Api-Client': getMetricsHeader(), 'access_token_auth': 'true', }; const emptyResponse = utils.responseFrom({}); diff --git a/test/unit/project-management/project-management-api-request.spec.ts b/test/unit/project-management/project-management-api-request.spec.ts index 772a33ad4c..58f15653b7 100644 --- a/test/unit/project-management/project-management-api-request.spec.ts +++ b/test/unit/project-management/project-management-api-request.spec.ts @@ -28,7 +28,7 @@ import { import { HttpClient } from '../../../src/utils/api-request'; import * as mocks from '../../resources/mocks'; import * as utils from '../utils'; -import { getSdkVersion } from '../../../src/utils/index'; +import { getMetricsHeader, getSdkVersion } from '../../../src/utils/index'; import { AppPlatform, ShaCertificate } from '../../../src/project-management/index'; chai.should(); @@ -76,6 +76,7 @@ describe('ProjectManagementRequestHandler', () => { expectedHeaders = { 'X-Client-Version': `Node/Admin/${getSdkVersion()}`, 'Authorization': 'Bearer ' + mockAccessToken, + 'X-Goog-Api-Client': getMetricsHeader(), }; requestHandler = new ProjectManagementRequestHandler(mockApp); return mockApp.INTERNAL.getToken(); diff --git a/test/unit/remote-config/remote-config-api-client.spec.ts b/test/unit/remote-config/remote-config-api-client.spec.ts index fa464c089a..9b6b8709bf 100644 --- a/test/unit/remote-config/remote-config-api-client.spec.ts +++ b/test/unit/remote-config/remote-config-api-client.spec.ts @@ -29,7 +29,7 @@ import * as mocks from '../../resources/mocks'; import { FirebaseAppError } from '../../../src/utils/error'; import { FirebaseApp } from '../../../src/app/firebase-app'; import { deepCopy } from '../../../src/utils/deep-copy'; -import { getSdkVersion } from '../../../src/utils/index'; +import { getMetricsHeader, getSdkVersion } from '../../../src/utils/index'; import { RemoteConfigTemplate, Version, ListVersionsResult, } from '../../../src/remote-config/index'; @@ -58,6 +58,7 @@ describe('RemoteConfigApiClient', () => { 'X-Firebase-Client': `fire-admin-node/${getSdkVersion()}`, 'Accept-Encoding': 'gzip', 'x-goog-user-project': 'test-project', + 'X-Goog-Api-Client': getMetricsHeader(), }; const VERSION_INFO: Version = { diff --git a/test/unit/security-rules/security-rules-api-client.spec.ts b/test/unit/security-rules/security-rules-api-client.spec.ts index d4139fdb34..2c1c8d9ec0 100644 --- a/test/unit/security-rules/security-rules-api-client.spec.ts +++ b/test/unit/security-rules/security-rules-api-client.spec.ts @@ -26,7 +26,7 @@ import * as utils from '../utils'; import * as mocks from '../../resources/mocks'; import { FirebaseAppError } from '../../../src/utils/error'; import { FirebaseApp } from '../../../src/app/firebase-app'; -import { getSdkVersion } from '../../../src/utils/index'; +import { getSdkVersion, getMetricsHeader } from '../../../src/utils/index'; const expect = chai.expect; @@ -45,6 +45,7 @@ describe('SecurityRulesApiClient', () => { 'Authorization': 'Bearer mock-token', 'X-Firebase-Client': `fire-admin-node/${getSdkVersion()}`, 'x-goog-user-project': 'test-project', + 'X-Goog-Api-Client': getMetricsHeader(), }; const noProjectId = 'Failed to determine project ID. Initialize the SDK with service ' + 'account credentials, or set project ID as an app option. Alternatively, set the ' diff --git a/test/unit/utils/crypto-signer.spec.ts b/test/unit/utils/crypto-signer.spec.ts index efda058c02..024be3ecbe 100644 --- a/test/unit/utils/crypto-signer.spec.ts +++ b/test/unit/utils/crypto-signer.spec.ts @@ -29,6 +29,7 @@ import { ServiceAccountCredential } from '../../../src/app/credential-internal'; import { AuthorizedHttpClient, HttpClient } from '../../../src/utils/api-request'; import { FirebaseApp } from '../../../src/app/firebase-app'; import * as utils from '../utils'; +import { getMetricsHeader } from '../../../src/utils'; chai.should(); chai.use(sinonChai); @@ -103,7 +104,10 @@ describe('CryptoSigner', () => { const signRequest = { method: 'POST', url: 'https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/test-service-account:signBlob', - headers: { Authorization: `Bearer ${mockAccessToken}` }, + headers: { + Authorization: `Bearer ${mockAccessToken}`, + 'X-Goog-Api-Client': getMetricsHeader() + }, data: { payload: input.toString('base64') }, }; let stub: sinon.SinonStub; @@ -158,7 +162,10 @@ describe('CryptoSigner', () => { const signRequest = { method: 'POST', url: 'https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/discovered-service-account:signBlob', - headers: { Authorization: `Bearer ${mockAccessToken}` }, + headers: { + Authorization: `Bearer ${mockAccessToken}`, + 'X-Goog-Api-Client': getMetricsHeader() + }, data: { payload: input.toString('base64') }, }; let stub: sinon.SinonStub;