Skip to content

Commit 5d31e21

Browse files
authored
Cache App Check debug token (#5055)
1 parent 56a6a9d commit 5d31e21

File tree

7 files changed

+181
-185
lines changed

7 files changed

+181
-185
lines changed

.changeset/loud-lamps-camp.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@firebase/app-check': patch
3+
---
4+
5+
Fix an error causing App Check to log `HTTP status 429` errors in debug mode.

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

+21-23
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
getFakeApp,
2929
getFakeCustomTokenProvider,
3030
getFakePlatformLoggingProvider,
31+
getFakeGreCAPTCHA,
3132
removegreCAPTCHAScriptsOnPage
3233
} from '../test/util';
3334
import { clearState, getState } from './state';
@@ -37,8 +38,12 @@ import * as internalApi from './internal-api';
3738
import * as client from './client';
3839
import * as storage from './storage';
3940
import * as logger from './logger';
41+
import * as util from './util';
4042

4143
describe('api', () => {
44+
beforeEach(() => {
45+
stub(util, 'getRecaptcha').returns(getFakeGreCAPTCHA());
46+
});
4247
describe('activate()', () => {
4348
let app: FirebaseApp;
4449

@@ -126,25 +131,29 @@ describe('api', () => {
126131
});
127132
});
128133
describe('onTokenChanged()', () => {
134+
const fakePlatformLoggingProvider = getFakePlatformLoggingProvider();
135+
const fakeRecaptchaToken = 'fake-recaptcha-token';
136+
const fakeRecaptchaAppCheckToken = {
137+
token: 'fake-recaptcha-app-check-token',
138+
expireTimeMillis: Date.now() + 60000,
139+
issuedAtTimeMillis: 0
140+
};
141+
142+
beforeEach(() => {
143+
stub(storage, 'readTokenFromStorage').resolves(undefined);
144+
stub(storage, 'writeTokenToStorage');
145+
});
129146
afterEach(() => {
130147
clearState();
131148
removegreCAPTCHAScriptsOnPage();
132149
});
133150
it('Listeners work when using top-level parameters pattern', async () => {
134-
const app = getFakeApp({ automaticDataCollectionEnabled: true });
135-
activate(app, FAKE_SITE_KEY, true);
136-
const fakePlatformLoggingProvider = getFakePlatformLoggingProvider();
137-
const fakeRecaptchaToken = 'fake-recaptcha-token';
138-
const fakeRecaptchaAppCheckToken = {
139-
token: 'fake-recaptcha-app-check-token',
140-
expireTimeMillis: 123,
141-
issuedAtTimeMillis: 0
142-
};
151+
const app = getFakeApp();
152+
activate(app, FAKE_SITE_KEY, false);
143153
stub(reCAPTCHA, 'getToken').returns(Promise.resolve(fakeRecaptchaToken));
144154
stub(client, 'exchangeToken').returns(
145155
Promise.resolve(fakeRecaptchaAppCheckToken)
146156
);
147-
stub(storage, 'writeTokenToStorage').returns(Promise.resolve(undefined));
148157

149158
const listener1 = (): void => {
150159
throw new Error();
@@ -183,20 +192,12 @@ describe('api', () => {
183192
});
184193

185194
it('Listeners work when using Observer pattern', async () => {
186-
const app = getFakeApp({ automaticDataCollectionEnabled: true });
187-
activate(app, FAKE_SITE_KEY, true);
188-
const fakePlatformLoggingProvider = getFakePlatformLoggingProvider();
189-
const fakeRecaptchaToken = 'fake-recaptcha-token';
190-
const fakeRecaptchaAppCheckToken = {
191-
token: 'fake-recaptcha-app-check-token',
192-
expireTimeMillis: 123,
193-
issuedAtTimeMillis: 0
194-
};
195+
const app = getFakeApp();
196+
activate(app, FAKE_SITE_KEY, false);
195197
stub(reCAPTCHA, 'getToken').returns(Promise.resolve(fakeRecaptchaToken));
196198
stub(client, 'exchangeToken').returns(
197199
Promise.resolve(fakeRecaptchaAppCheckToken)
198200
);
199-
stub(storage, 'writeTokenToStorage').returns(Promise.resolve(undefined));
200201

201202
const listener1 = (): void => {
202203
throw new Error();
@@ -238,11 +239,8 @@ describe('api', () => {
238239
stub(logger.logger, 'error');
239240
const app = getFakeApp();
240241
activate(app, FAKE_SITE_KEY, false);
241-
const fakePlatformLoggingProvider = getFakePlatformLoggingProvider();
242-
const fakeRecaptchaToken = 'fake-recaptcha-token';
243242
stub(reCAPTCHA, 'getToken').returns(Promise.resolve(fakeRecaptchaToken));
244243
stub(client, 'exchangeToken').rejects('exchange error');
245-
stub(storage, 'writeTokenToStorage').returns(Promise.resolve(undefined));
246244

247245
const listener1 = spy();
248246

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ describe('client', () => {
5252
});
5353

5454
it('returns a AppCheck token', async () => {
55-
useFakeTimers();
55+
// To get a consistent expireTime/issuedAtTime.
56+
const clock = useFakeTimers();
5657
fetchStub.returns(
5758
Promise.resolve({
5859
status: 200,
@@ -77,6 +78,7 @@ describe('client', () => {
7778
expireTimeMillis: 3600,
7879
issuedAtTimeMillis: 0
7980
});
81+
clock.restore();
8082
});
8183

8284
it('throws when there is a network error', async () => {

packages/app-check/src/factory.ts

+15-3
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,21 @@ import {
3636
import { Provider } from '@firebase/component';
3737
import { PartialObserver } from '@firebase/util';
3838

39+
import { FirebaseService } from '@firebase/app-types/private';
40+
import { getState } from './state';
41+
3942
export function factory(
4043
app: FirebaseApp,
4144
platformLoggerProvider: Provider<'platform-logger'>
42-
): FirebaseAppCheck {
45+
): FirebaseAppCheck & FirebaseService {
4346
return {
47+
app,
4448
activate: (
4549
siteKeyOrProvider: string | AppCheckProvider,
4650
isTokenAutoRefreshEnabled?: boolean
4751
) => activate(app, siteKeyOrProvider, isTokenAutoRefreshEnabled),
4852
setTokenAutoRefreshEnabled: (isTokenAutoRefreshEnabled: boolean) =>
4953
setTokenAutoRefreshEnabled(app, isTokenAutoRefreshEnabled),
50-
5154
getToken: forceRefresh =>
5255
getToken(app, platformLoggerProvider, forceRefresh),
5356
onTokenChanged: (
@@ -68,7 +71,16 @@ export function factory(
6871
onNextOrObserver as (tokenResult: AppCheckTokenResult) => void,
6972
onError,
7073
onCompletion
71-
)
74+
),
75+
INTERNAL: {
76+
delete: () => {
77+
const { tokenObservers } = getState(app);
78+
for (const tokenObserver of tokenObservers) {
79+
removeTokenListener(app, tokenObserver.next);
80+
}
81+
return Promise.resolve();
82+
}
83+
}
7284
};
7385
}
7486

0 commit comments

Comments
 (0)