Skip to content

Commit e123f24

Browse files
authored
Enable platform logging for AppCheck (#4857)
1 parent efafeec commit e123f24

File tree

10 files changed

+118
-54
lines changed

10 files changed

+118
-54
lines changed

.changeset/loud-bears-rule.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@firebase/app': patch
3+
---
4+
5+
Add AppCheck platform logging string.

packages/app-check/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
"bugs": {
5353
"url": "https://github.com/firebase/firebase-js-sdk/issues"
5454
},
55-
"typings": "dist/index.d.ts",
55+
"typings": "dist/src/index.d.ts",
5656
"nyc": {
5757
"extension": [
5858
".ts"

packages/app-check/src/client.test.ts

+15-6
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import '../test/setup';
1919
import { expect } from 'chai';
2020
import { stub, SinonStub, useFakeTimers } from 'sinon';
2121
import { FirebaseApp } from '@firebase/app-types';
22-
import { getFakeApp } from '../test/util';
22+
import { getFakeApp, getFakePlatformLoggingProvider } from '../test/util';
2323
import { getExchangeRecaptchaTokenRequest, exchangeToken } from './client';
2424
import { FirebaseError } from '@firebase/util';
2525
import { ERROR_FACTORY, AppCheckError } from './errors';
@@ -64,9 +64,14 @@ describe('client', () => {
6464
);
6565

6666
const response = await exchangeToken(
67-
getExchangeRecaptchaTokenRequest(app, 'fake-custom-token')
67+
getExchangeRecaptchaTokenRequest(app, 'fake-custom-token'),
68+
getFakePlatformLoggingProvider('a/1.2.3 fire-app-check/2.3.4')
6869
);
6970

71+
expect(
72+
(fetchStub.args[0][1]?.['headers'] as any)['X-Firebase-Client']
73+
).to.equal('a/1.2.3 fire-app-check/2.3.4');
74+
7075
expect(response).to.deep.equal({
7176
token: 'fake-appcheck-token',
7277
expireTimeMillis: 3600
@@ -85,7 +90,8 @@ describe('client', () => {
8590

8691
try {
8792
await exchangeToken(
88-
getExchangeRecaptchaTokenRequest(app, 'fake-custom-token')
93+
getExchangeRecaptchaTokenRequest(app, 'fake-custom-token'),
94+
getFakePlatformLoggingProvider()
8995
);
9096
} catch (e) {
9197
expect(e).instanceOf(FirebaseError);
@@ -113,7 +119,8 @@ describe('client', () => {
113119

114120
try {
115121
await exchangeToken(
116-
getExchangeRecaptchaTokenRequest(app, 'fake-custom-token')
122+
getExchangeRecaptchaTokenRequest(app, 'fake-custom-token'),
123+
getFakePlatformLoggingProvider()
117124
);
118125
} catch (e) {
119126
expect(e).instanceOf(FirebaseError);
@@ -140,7 +147,8 @@ describe('client', () => {
140147

141148
try {
142149
await exchangeToken(
143-
getExchangeRecaptchaTokenRequest(app, 'fake-custom-token')
150+
getExchangeRecaptchaTokenRequest(app, 'fake-custom-token'),
151+
getFakePlatformLoggingProvider()
144152
);
145153
} catch (e) {
146154
expect(e).instanceOf(FirebaseError);
@@ -173,7 +181,8 @@ describe('client', () => {
173181

174182
try {
175183
await exchangeToken(
176-
getExchangeRecaptchaTokenRequest(app, 'fake-custom-token')
184+
getExchangeRecaptchaTokenRequest(app, 'fake-custom-token'),
185+
getFakePlatformLoggingProvider()
177186
);
178187
} catch (e) {
179188
expect(e).instanceOf(FirebaseError);

packages/app-check/src/client.ts

+17-11
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
import { FirebaseApp } from '@firebase/app-types';
2424
import { ERROR_FACTORY, AppCheckError } from './errors';
2525
import { AppCheckToken } from '@firebase/app-check-types';
26-
import { version } from '../package.json';
26+
import { Provider } from '@firebase/component';
2727

2828
/**
2929
* Response JSON returned from AppCheck server endpoint.
@@ -39,18 +39,24 @@ interface AppCheckRequest {
3939
body: { [key: string]: string };
4040
}
4141

42-
export async function exchangeToken({
43-
url,
44-
body
45-
}: AppCheckRequest): Promise<AppCheckToken> {
46-
const options = {
42+
export async function exchangeToken(
43+
{ url, body }: AppCheckRequest,
44+
platformLoggerProvider: Provider<'platform-logger'>
45+
): Promise<AppCheckToken> {
46+
const headers: HeadersInit = {
47+
'Content-Type': 'application/json'
48+
};
49+
// If platform logger exists, add the platform info string to the header.
50+
const platformLogger = platformLoggerProvider.getImmediate({
51+
optional: true
52+
});
53+
if (platformLogger) {
54+
headers['X-Firebase-Client'] = platformLogger.getPlatformInfoString();
55+
}
56+
const options: RequestInit = {
4757
method: 'POST',
4858
body: JSON.stringify(body),
49-
headers: {
50-
'Content-Type': 'application/json',
51-
// JS platform identifier + appCheck version only
52-
'X-Firebase-Client': `fire-js/ fire-app-check/${version}`
53-
}
59+
headers
5460
};
5561
let response;
5662
try {

packages/app-check/src/factory.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
addTokenListener,
2525
removeTokenListener
2626
} from './internal-api';
27+
import { Provider } from '@firebase/component';
2728

2829
export function factory(app: FirebaseApp): FirebaseAppCheck {
2930
return {
@@ -32,10 +33,15 @@ export function factory(app: FirebaseApp): FirebaseAppCheck {
3233
};
3334
}
3435

35-
export function internalFactory(app: FirebaseApp): FirebaseAppCheckInternal {
36+
export function internalFactory(
37+
app: FirebaseApp,
38+
platformLoggerProvider: Provider<'platform-logger'>
39+
): FirebaseAppCheckInternal {
3640
return {
37-
getToken: forceRefresh => getToken(app, forceRefresh),
38-
addTokenListener: listener => addTokenListener(app, listener),
41+
getToken: forceRefresh =>
42+
getToken(app, platformLoggerProvider, forceRefresh),
43+
addTokenListener: listener =>
44+
addTokenListener(app, platformLoggerProvider, listener),
3945
removeTokenListener: listener => removeTokenListener(app, listener)
4046
};
4147
}

packages/app-check/src/index.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
import { factory, internalFactory } from './factory';
2525
import { initializeDebugMode } from './debug';
2626
import { AppCheckInternalComponentName } from '@firebase/app-check-interop-types';
27+
import { name, version } from '../package.json';
2728

2829
const APP_CHECK_NAME: AppCheckComponentName = 'appCheck';
2930
const APP_CHECK_NAME_INTERNAL: AppCheckInternalComponentName =
@@ -49,13 +50,14 @@ function registerAppCheck(firebase: _FirebaseNamespace): void {
4950
container => {
5051
// getImmediate for FirebaseApp will always succeed
5152
const app = container.getProvider('app').getImmediate();
52-
return internalFactory(app);
53+
const platformLoggerProvider = container.getProvider('platform-logger');
54+
return internalFactory(app, platformLoggerProvider);
5355
},
5456
ComponentType.PUBLIC
5557
)
5658
);
5759

58-
// TODO: register AppCheck version with firebase.registerVersion() before BETA. We don't want to report version in EAP
60+
firebase.registerVersion(name, version);
5961
}
6062

6163
registerAppCheck(firebase as _FirebaseNamespace);

packages/app-check/src/internal-api.test.ts

+30-25
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
FAKE_SITE_KEY,
2424
getFakeApp,
2525
getFakeCustomTokenProvider,
26+
getFakePlatformLoggingProvider,
2627
removegreCAPTCHAScriptsOnPage
2728
} from '../test/util';
2829
import { activate } from './api';
@@ -40,6 +41,8 @@ import { getState, clearState, setState, getDebugState } from './state';
4041
import { AppCheckTokenListener } from '@firebase/app-check-interop-types';
4142
import { Deferred } from '@firebase/util';
4243

44+
const fakePlatformLoggingProvider = getFakePlatformLoggingProvider();
45+
4346
describe('internal api', () => {
4447
let app: FirebaseApp;
4548

@@ -70,7 +73,7 @@ describe('internal api', () => {
7073
const customProviderSpy = spy(customTokenProvider, 'getToken');
7174

7275
activate(app, customTokenProvider);
73-
const token = await getToken(app);
76+
const token = await getToken(app, fakePlatformLoggingProvider);
7477

7578
expect(customProviderSpy).to.be.called;
7679
expect(token).to.deep.equal({
@@ -91,7 +94,7 @@ describe('internal api', () => {
9194
'exchangeToken'
9295
).returns(Promise.resolve(fakeRecaptchaAppCheckToken));
9396

94-
const token = await getToken(app);
97+
const token = await getToken(app, fakePlatformLoggingProvider);
9598

9699
expect(reCAPTCHASpy).to.be.called;
97100

@@ -112,7 +115,7 @@ describe('internal api', () => {
112115
const error = new Error('oops, something went wrong');
113116
stub(client, 'exchangeToken').returns(Promise.reject(error));
114117

115-
const token = await getToken(app);
118+
const token = await getToken(app, fakePlatformLoggingProvider);
116119

117120
expect(reCAPTCHASpy).to.be.called;
118121
expect(token).to.deep.equal({
@@ -135,10 +138,10 @@ describe('internal api', () => {
135138

136139
const listener1 = spy();
137140
const listener2 = spy();
138-
addTokenListener(app, listener1);
139-
addTokenListener(app, listener2);
141+
addTokenListener(app, fakePlatformLoggingProvider, listener1);
142+
addTokenListener(app, fakePlatformLoggingProvider, listener2);
140143

141-
await getToken(app);
144+
await getToken(app, fakePlatformLoggingProvider);
142145

143146
expect(listener1).to.be.calledWith({
144147
token: fakeCachedAppCheckToken.token
@@ -161,10 +164,10 @@ describe('internal api', () => {
161164

162165
const listener1 = spy();
163166
const listener2 = spy();
164-
addTokenListener(app, listener1);
165-
addTokenListener(app, listener2);
167+
addTokenListener(app, fakePlatformLoggingProvider, listener1);
168+
addTokenListener(app, fakePlatformLoggingProvider, listener2);
166169

167-
await getToken(app);
170+
await getToken(app, fakePlatformLoggingProvider);
168171

169172
expect(listener1).to.be.calledWith({
170173
token: fakeRecaptchaAppCheckToken.token
@@ -185,10 +188,10 @@ describe('internal api', () => {
185188
};
186189
const listener2 = spy();
187190

188-
addTokenListener(app, listener1);
189-
addTokenListener(app, listener2);
191+
addTokenListener(app, fakePlatformLoggingProvider, listener1);
192+
addTokenListener(app, fakePlatformLoggingProvider, listener2);
190193

191-
await getToken(app);
194+
await getToken(app, fakePlatformLoggingProvider);
192195

193196
expect(listener2).to.be.calledWith({
194197
token: fakeRecaptchaAppCheckToken.token
@@ -206,7 +209,7 @@ describe('internal api', () => {
206209
const clientStub = stub(client, 'exchangeToken');
207210

208211
expect(getState(app).token).to.equal(undefined);
209-
expect(await getToken(app)).to.deep.equal({
212+
expect(await getToken(app, fakePlatformLoggingProvider)).to.deep.equal({
210213
token: fakeCachedAppCheckToken.token
211214
});
212215
expect(getState(app).token).to.equal(fakeCachedAppCheckToken);
@@ -224,7 +227,7 @@ describe('internal api', () => {
224227
Promise.resolve(fakeRecaptchaAppCheckToken)
225228
);
226229
const storageWriteStub = stub(storage, 'writeTokenToStorage');
227-
const result = await getToken(app);
230+
const result = await getToken(app, fakePlatformLoggingProvider);
228231
expect(result).to.deep.equal({ token: fakeRecaptchaAppCheckToken.token });
229232
expect(storageWriteStub).has.been.calledWith(
230233
app,
@@ -238,7 +241,7 @@ describe('internal api', () => {
238241
setState(app, { ...getState(app), token: fakeRecaptchaAppCheckToken });
239242

240243
const clientStub = stub(client, 'exchangeToken');
241-
expect(await getToken(app)).to.deep.equal({
244+
expect(await getToken(app, fakePlatformLoggingProvider)).to.deep.equal({
242245
token: fakeRecaptchaAppCheckToken.token
243246
});
244247
expect(clientStub).to.not.have.been.called;
@@ -255,7 +258,9 @@ describe('internal api', () => {
255258
Promise.resolve(fakeRecaptchaAppCheckToken)
256259
);
257260

258-
expect(await getToken(app, true)).to.deep.equal({
261+
expect(
262+
await getToken(app, fakePlatformLoggingProvider, true)
263+
).to.deep.equal({
259264
token: fakeRecaptchaAppCheckToken.token
260265
});
261266
});
@@ -271,7 +276,7 @@ describe('internal api', () => {
271276
debugState.token.resolve('my-debug-token');
272277
activate(app, FAKE_SITE_KEY);
273278

274-
const token = await getToken(app);
279+
const token = await getToken(app, fakePlatformLoggingProvider);
275280
expect(exchangeTokenStub.args[0][0].body['debug_token']).to.equal(
276281
'my-debug-token'
277282
);
@@ -283,7 +288,7 @@ describe('internal api', () => {
283288
it('adds token listeners', () => {
284289
const listener = (): void => {};
285290

286-
addTokenListener(app, listener);
291+
addTokenListener(app, fakePlatformLoggingProvider, listener);
287292

288293
expect(getState(app).tokenListeners[0]).to.equal(listener);
289294
});
@@ -293,7 +298,7 @@ describe('internal api', () => {
293298
expect(getState(app).tokenListeners.length).to.equal(0);
294299
expect(getState(app).tokenRefresher).to.equal(undefined);
295300

296-
addTokenListener(app, listener);
301+
addTokenListener(app, fakePlatformLoggingProvider, listener);
297302

298303
expect(getState(app).tokenRefresher?.isRunning()).to.be.true;
299304
});
@@ -316,7 +321,7 @@ describe('internal api', () => {
316321
}
317322
});
318323

319-
addTokenListener(app, fakeListener);
324+
addTokenListener(app, fakePlatformLoggingProvider, fakeListener);
320325
});
321326

322327
it('notifies the listener with the valid token in storage', done => {
@@ -337,7 +342,7 @@ describe('internal api', () => {
337342
done();
338343
};
339344

340-
addTokenListener(app, fakeListener);
345+
addTokenListener(app, fakePlatformLoggingProvider, fakeListener);
341346
clock.tick(1);
342347
});
343348

@@ -355,7 +360,7 @@ describe('internal api', () => {
355360
debugState.token.resolve('my-debug-token');
356361

357362
activate(app, FAKE_SITE_KEY);
358-
addTokenListener(app, fakeListener);
363+
addTokenListener(app, fakePlatformLoggingProvider, fakeListener);
359364
});
360365

361366
it('does NOT start token refresher in debug mode', () => {
@@ -365,7 +370,7 @@ describe('internal api', () => {
365370
debugState.token.resolve('my-debug-token');
366371

367372
activate(app, FAKE_SITE_KEY);
368-
addTokenListener(app, () => {});
373+
addTokenListener(app, fakePlatformLoggingProvider, () => {});
369374

370375
const state = getState(app);
371376
expect(state.tokenRefresher).is.undefined;
@@ -375,7 +380,7 @@ describe('internal api', () => {
375380
describe('removeTokenListener', () => {
376381
it('should remove token listeners', () => {
377382
const listener = (): void => {};
378-
addTokenListener(app, listener);
383+
addTokenListener(app, fakePlatformLoggingProvider, listener);
379384
expect(getState(app).tokenListeners.length).to.equal(1);
380385

381386
removeTokenListener(app, listener);
@@ -385,7 +390,7 @@ describe('internal api', () => {
385390
it('should stop proactively refreshing token after deleting the last listener', () => {
386391
const listener = (): void => {};
387392

388-
addTokenListener(app, listener);
393+
addTokenListener(app, fakePlatformLoggingProvider, listener);
389394
expect(getState(app).tokenListeners.length).to.equal(1);
390395
expect(getState(app).tokenRefresher?.isRunning()).to.be.true;
391396

0 commit comments

Comments
 (0)