Skip to content

Commit b9d535a

Browse files
authored
Merge 36dd305 into 3ea1e1f
2 parents 3ea1e1f + 36dd305 commit b9d535a

File tree

7 files changed

+233
-125
lines changed

7 files changed

+233
-125
lines changed

.changeset/loud-lamps-camp.md

Lines changed: 5 additions & 0 deletions
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

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
*/
1717
import '../test/setup';
1818
import { expect } from 'chai';
19-
import { stub, spy } from 'sinon';
19+
import { stub, spy, SinonStub } from 'sinon';
2020
import {
2121
activate,
2222
setTokenAutoRefreshEnabled,
@@ -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,35 @@ describe('api', () => {
126131
});
127132
});
128133
describe('onTokenChanged()', () => {
134+
let storageReadStub: SinonStub;
135+
let storageWriteStub: SinonStub;
136+
const fakePlatformLoggingProvider = getFakePlatformLoggingProvider();
137+
const fakeRecaptchaToken = 'fake-recaptcha-token';
138+
const fakeRecaptchaAppCheckToken = {
139+
token: 'fake-recaptcha-app-check-token',
140+
expireTimeMillis: Date.now() + 60000,
141+
issuedAtTimeMillis: 0
142+
};
143+
144+
beforeEach(() => {
145+
storageReadStub = stub(storage, 'readTokenFromStorage').resolves(
146+
undefined
147+
);
148+
storageWriteStub = stub(storage, 'writeTokenToStorage');
149+
});
129150
afterEach(() => {
151+
storageReadStub.restore();
152+
storageWriteStub.restore();
130153
clearState();
131154
removegreCAPTCHAScriptsOnPage();
132155
});
133156
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-
};
157+
const app = getFakeApp();
158+
activate(app, FAKE_SITE_KEY, false);
143159
stub(reCAPTCHA, 'getToken').returns(Promise.resolve(fakeRecaptchaToken));
144160
stub(client, 'exchangeToken').returns(
145161
Promise.resolve(fakeRecaptchaAppCheckToken)
146162
);
147-
stub(storage, 'writeTokenToStorage').returns(Promise.resolve(undefined));
148163

149164
const listener1 = (): void => {
150165
throw new Error();
@@ -183,20 +198,12 @@ describe('api', () => {
183198
});
184199

185200
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-
};
201+
const app = getFakeApp();
202+
activate(app, FAKE_SITE_KEY, false);
195203
stub(reCAPTCHA, 'getToken').returns(Promise.resolve(fakeRecaptchaToken));
196204
stub(client, 'exchangeToken').returns(
197205
Promise.resolve(fakeRecaptchaAppCheckToken)
198206
);
199-
stub(storage, 'writeTokenToStorage').returns(Promise.resolve(undefined));
200207

201208
const listener1 = (): void => {
202209
throw new Error();
@@ -238,11 +245,8 @@ describe('api', () => {
238245
stub(logger.logger, 'error');
239246
const app = getFakeApp();
240247
activate(app, FAKE_SITE_KEY, false);
241-
const fakePlatformLoggingProvider = getFakePlatformLoggingProvider();
242-
const fakeRecaptchaToken = 'fake-recaptcha-token';
243248
stub(reCAPTCHA, 'getToken').returns(Promise.resolve(fakeRecaptchaToken));
244249
stub(client, 'exchangeToken').rejects('exchange error');
245-
stub(storage, 'writeTokenToStorage').returns(Promise.resolve(undefined));
246250

247251
const listener1 = spy();
248252

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

Lines changed: 3 additions & 1 deletion
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

Lines changed: 15 additions & 3 deletions
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)