Skip to content

Commit 785a217

Browse files
authored
Initialize App Check debug mode in initializeAppCheck (#5512)
1 parent 4e7aba4 commit 785a217

File tree

6 files changed

+73
-8
lines changed

6 files changed

+73
-8
lines changed

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

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,13 @@ import * as logger from './logger';
3838
import * as client from './client';
3939
import * as storage from './storage';
4040
import * as internalApi from './internal-api';
41+
import * as indexeddb from './indexeddb';
42+
import * as debug from './debug';
4143
import { deleteApp, FirebaseApp } from '@firebase/app';
4244
import { CustomProvider, ReCaptchaV3Provider } from './providers';
4345
import { AppCheckService } from './factory';
4446
import { AppCheckToken } from './public-types';
47+
import { getDebugToken } from './debug';
4548

4649
describe('api', () => {
4750
let app: FirebaseApp;
@@ -118,6 +121,49 @@ describe('api', () => {
118121
})
119122
).to.equal(appCheckInstance);
120123
});
124+
it('starts debug mode on first call', async () => {
125+
let token: string = '';
126+
const fakeWrite = (tokenToWrite: string): Promise<void> => {
127+
token = tokenToWrite;
128+
return Promise.resolve();
129+
};
130+
stub(indexeddb, 'writeDebugTokenToIndexedDB').callsFake(fakeWrite);
131+
stub(indexeddb, 'readDebugTokenFromIndexedDB').resolves(token);
132+
const consoleStub = stub(console, 'log');
133+
self.FIREBASE_APPCHECK_DEBUG_TOKEN = true;
134+
initializeAppCheck(app, {
135+
provider: new ReCaptchaV3Provider(FAKE_SITE_KEY)
136+
});
137+
// Ensure getDebugToken() call inside `initializeAppCheck()`
138+
// has time to resolve, and double check its value matches that
139+
// written to indexedDB.
140+
expect(await getDebugToken()).to.equal(token);
141+
expect(consoleStub.args[0][0]).to.include(token);
142+
self.FIREBASE_APPCHECK_DEBUG_TOKEN = undefined;
143+
});
144+
it('does not call initializeDebugMode on second call', async () => {
145+
self.FIREBASE_APPCHECK_DEBUG_TOKEN = 'abcdefg';
146+
const consoleStub = stub(console, 'log');
147+
const initializeDebugModeSpy = spy(debug, 'initializeDebugMode');
148+
// First call, should call initializeDebugMode()
149+
initializeAppCheck(app, {
150+
provider: new ReCaptchaV3Provider(FAKE_SITE_KEY)
151+
});
152+
expect(initializeDebugModeSpy).to.be.called;
153+
initializeDebugModeSpy.resetHistory();
154+
// Second call, should not call initializeDebugMode()
155+
initializeAppCheck(app, {
156+
provider: new ReCaptchaV3Provider(FAKE_SITE_KEY)
157+
});
158+
const token = await getDebugToken();
159+
expect(token).to.equal('abcdefg');
160+
// Two console logs of the token, for each initializeAppCheck call.
161+
expect(consoleStub.args[0][0]).to.include(token);
162+
expect(consoleStub.args[1][0]).to.include(token);
163+
expect(consoleStub.args[1][0]).to.equal(consoleStub.args[0][0]);
164+
expect(initializeDebugModeSpy).to.not.be.called;
165+
self.FIREBASE_APPCHECK_DEBUG_TOKEN = undefined;
166+
});
121167

122168
it('initialize reCAPTCHA when a ReCaptchaV3Provider is provided', () => {
123169
const initReCAPTCHAStub = stub(reCAPTCHA, 'initialize').returns(

packages/app-check/src/api.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
PartialObserver
2424
} from './public-types';
2525
import { ERROR_FACTORY, AppCheckError } from './errors';
26-
import { getState, setState, AppCheckState } from './state';
26+
import { getState, setState, AppCheckState, getDebugState } from './state';
2727
import { FirebaseApp, getApp, _getProvider } from '@firebase/app';
2828
import { getModularInstance, ErrorFn, NextFn } from '@firebase/util';
2929
import { AppCheckService } from './factory';
@@ -35,6 +35,7 @@ import {
3535
isValid
3636
} from './internal-api';
3737
import { readTokenFromStorage } from './storage';
38+
import { getDebugToken, initializeDebugMode, isDebugMode } from './debug';
3839

3940
declare module '@firebase/component' {
4041
interface NameServiceMapping {
@@ -57,6 +58,23 @@ export function initializeAppCheck(
5758
app = getModularInstance(app);
5859
const provider = _getProvider(app, 'app-check');
5960

61+
// Ensure initializeDebugMode() is only called once.
62+
if (!getDebugState().initialized) {
63+
initializeDebugMode();
64+
}
65+
66+
// Log a message containing the debug token when `initializeAppCheck()`
67+
// is called in debug mode.
68+
if (isDebugMode()) {
69+
// Do not block initialization to get the token for the message.
70+
void getDebugToken().then(token =>
71+
// Not using logger because I don't think we ever want this accidentally hidden.
72+
console.log(
73+
`App Check debug token: ${token}. You will need to add it to your app's App Check settings in the Firebase console for it to work.`
74+
)
75+
);
76+
}
77+
6078
if (provider.isInitialized()) {
6179
const existingInstance = provider.getImmediate();
6280
const initialOptions = provider.getOptions() as unknown as AppCheckOptions;

packages/app-check/src/debug.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,18 @@ export async function getDebugToken(): Promise<string> {
4646

4747
export function initializeDebugMode(): void {
4848
const globals = getGlobal();
49+
const debugState = getDebugState();
50+
// Set to true if this function has been called, whether or not
51+
// it enabled debug mode.
52+
debugState.initialized = true;
53+
4954
if (
5055
typeof globals.FIREBASE_APPCHECK_DEBUG_TOKEN !== 'string' &&
5156
globals.FIREBASE_APPCHECK_DEBUG_TOKEN !== true
5257
) {
5358
return;
5459
}
5560

56-
const debugState = getDebugState();
5761
debugState.enabled = true;
5862
const deferredToken = new Deferred<string>();
5963
debugState.token = deferredToken;

packages/app-check/src/index.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import {
2828
} from '@firebase/component';
2929
import { _AppCheckComponentName } from './public-types';
3030
import { factory, internalFactory } from './factory';
31-
import { initializeDebugMode } from './debug';
3231
import { _AppCheckInternalComponentName } from './types';
3332
import { name, version } from '../package.json';
3433

@@ -82,4 +81,3 @@ function registerAppCheck(): void {
8281
}
8382

8483
registerAppCheck();
85-
initializeDebugMode();

packages/app-check/src/state.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export interface ReCAPTCHAState {
4141
}
4242

4343
export interface DebugState {
44+
initialized: boolean;
4445
enabled: boolean;
4546
token?: Deferred<string>;
4647
}
@@ -52,6 +53,7 @@ export const DEFAULT_STATE: AppCheckState = {
5253
};
5354

5455
const DEBUG_STATE: DebugState = {
56+
initialized: false,
5557
enabled: false
5658
};
5759

@@ -68,6 +70,7 @@ export function clearState(): void {
6870
APP_CHECK_STATES.clear();
6971
DEBUG_STATE.enabled = false;
7072
DEBUG_STATE.token = undefined;
73+
DEBUG_STATE.initialized = false;
7174
}
7275

7376
export function getDebugState(): DebugState {

packages/app-check/src/storage.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,6 @@ export async function readOrCreateDebugTokenFromStorage(): Promise<string> {
8787
writeDebugTokenToIndexedDB(newToken).catch(e =>
8888
logger.warn(`Failed to persist debug token to IndexedDB. Error: ${e}`)
8989
);
90-
// Not using logger because I don't think we ever want this accidentally hidden?
91-
console.log(
92-
`App Check debug token: ${newToken}. You will need to add it to your app's App Check settings in the Firebase console for it to work`
93-
);
9490
return newToken;
9591
} else {
9692
return existingDebugToken;

0 commit comments

Comments
 (0)