Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

App Check heartbeat implementation #5967

Merged
merged 6 commits into from
Mar 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/polite-donkeys-divide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@firebase/app-check': patch
---

Update platform logging to use new endpoint.
12 changes: 6 additions & 6 deletions packages/app-check/src/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import '../test/setup';
import { expect } from 'chai';
import { stub, SinonStub, useFakeTimers } from 'sinon';
import { FirebaseApp } from '@firebase/app';
import { getFakeApp, getFakePlatformLoggingProvider } from '../test/util';
import { getFakeApp, getFakeHeartbeatServiceProvider } from '../test/util';
import {
getExchangeRecaptchaV3TokenRequest,
exchangeToken,
Expand Down Expand Up @@ -86,7 +86,7 @@ describe('client', () => {

const response = await exchangeToken(
getExchangeRecaptchaV3TokenRequest(app, 'fake-custom-token'),
getFakePlatformLoggingProvider('a/1.2.3 fire-app-check/2.3.4')
getFakeHeartbeatServiceProvider('a/1.2.3 fire-app-check/2.3.4')
);

expect(
Expand Down Expand Up @@ -114,7 +114,7 @@ describe('client', () => {
try {
await exchangeToken(
getExchangeRecaptchaV3TokenRequest(app, 'fake-custom-token'),
getFakePlatformLoggingProvider()
getFakeHeartbeatServiceProvider()
);
} catch (e) {
expect(e).instanceOf(FirebaseError);
Expand Down Expand Up @@ -143,7 +143,7 @@ describe('client', () => {
try {
await exchangeToken(
getExchangeRecaptchaV3TokenRequest(app, 'fake-custom-token'),
getFakePlatformLoggingProvider()
getFakeHeartbeatServiceProvider()
);
} catch (e) {
expect(e).instanceOf(FirebaseError);
Expand Down Expand Up @@ -171,7 +171,7 @@ describe('client', () => {
try {
await exchangeToken(
getExchangeRecaptchaV3TokenRequest(app, 'fake-custom-token'),
getFakePlatformLoggingProvider()
getFakeHeartbeatServiceProvider()
);
} catch (e) {
expect(e).instanceOf(FirebaseError);
Expand Down Expand Up @@ -205,7 +205,7 @@ describe('client', () => {
try {
await exchangeToken(
getExchangeRecaptchaV3TokenRequest(app, 'fake-custom-token'),
getFakePlatformLoggingProvider()
getFakeHeartbeatServiceProvider()
);
} catch (e) {
expect(e).instanceOf(FirebaseError);
Expand Down
13 changes: 8 additions & 5 deletions packages/app-check/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,20 @@ interface AppCheckRequest {

export async function exchangeToken(
{ url, body }: AppCheckRequest,
platformLoggerProvider: Provider<'platform-logger'>
heartbeatServiceProvider: Provider<'heartbeat'>
): Promise<AppCheckTokenInternal> {
const headers: HeadersInit = {
'Content-Type': 'application/json'
};
// If platform logger exists, add the platform info string to the header.
const platformLogger = platformLoggerProvider.getImmediate({
// If heartbeat service exists, add heartbeat header string to the header.
const heartbeatService = heartbeatServiceProvider.getImmediate({
hsubox76 marked this conversation as resolved.
Show resolved Hide resolved
optional: true
});
if (platformLogger) {
headers['X-Firebase-Client'] = platformLogger.getPlatformInfoString();
if (heartbeatService) {
const heartbeatsHeader = await heartbeatService.getHeartbeatsHeader();
if (heartbeatsHeader) {
headers['X-Firebase-Client'] = heartbeatsHeader;
}
}
const options: RequestInit = {
method: 'POST',
Expand Down
6 changes: 3 additions & 3 deletions packages/app-check/src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import { getState } from './state';
export class AppCheckService implements AppCheck, _FirebaseService {
constructor(
public app: FirebaseApp,
public platformLoggerProvider: Provider<'platform-logger'>
public heartbeatServiceProvider: Provider<'heartbeat'>
) {}
_delete(): Promise<void> {
const { tokenObservers } = getState(this.app);
Expand All @@ -45,9 +45,9 @@ export class AppCheckService implements AppCheck, _FirebaseService {

export function factory(
app: FirebaseApp,
platformLoggerProvider: Provider<'platform-logger'>
heartbeatServiceProvider: Provider<'heartbeat'>
): AppCheckService {
return new AppCheckService(app, platformLoggerProvider);
return new AppCheckService(app, heartbeatServiceProvider);
}

export function internalFactory(
Expand Down
4 changes: 2 additions & 2 deletions packages/app-check/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ function registerAppCheck(): void {
container => {
// getImmediate for FirebaseApp will always succeed
const app = container.getProvider('app').getImmediate();
const platformLoggerProvider = container.getProvider('platform-logger');
return factory(app, platformLoggerProvider);
const heartbeatServiceProvider = container.getProvider('heartbeat');
return factory(app, heartbeatServiceProvider);
},
ComponentType.PUBLIC
)
Expand Down
2 changes: 1 addition & 1 deletion packages/app-check/src/internal-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export async function getToken(
if (!state.exchangeTokenPromise) {
state.exchangeTokenPromise = exchangeToken(
getExchangeDebugTokenRequest(app, await getDebugToken()),
appCheck.platformLoggerProvider
appCheck.heartbeatServiceProvider
).then(token => {
state.exchangeTokenPromise = undefined;
return token;
Expand Down
16 changes: 8 additions & 8 deletions packages/app-check/src/providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import { getDurationString } from './util';
*/
export class ReCaptchaV3Provider implements AppCheckProvider {
private _app?: FirebaseApp;
private _platformLoggerProvider?: Provider<'platform-logger'>;
private _heartbeatServiceProvider?: Provider<'heartbeat'>;
/**
* Throttle requests on certain error codes to prevent too many retries
* in a short time.
Expand All @@ -66,7 +66,7 @@ export class ReCaptchaV3Provider implements AppCheckProvider {
throwIfThrottled(this._throttleData);

// Top-level `getToken()` has already checked that App Check is initialized
// and therefore this._app and this._platformLoggerProvider are available.
// and therefore this._app and this._heartbeatServiceProvider are available.
const attestedClaimsToken = await getReCAPTCHAToken(this._app!).catch(
_e => {
// reCaptcha.execute() throws null which is not very descriptive.
Expand All @@ -77,7 +77,7 @@ export class ReCaptchaV3Provider implements AppCheckProvider {
try {
result = await exchangeToken(
getExchangeRecaptchaV3TokenRequest(this._app!, attestedClaimsToken),
this._platformLoggerProvider!
this._heartbeatServiceProvider!
);
} catch (e) {
if ((e as FirebaseError).code === AppCheckError.FETCH_STATUS_ERROR) {
Expand Down Expand Up @@ -105,7 +105,7 @@ export class ReCaptchaV3Provider implements AppCheckProvider {
*/
initialize(app: FirebaseApp): void {
this._app = app;
this._platformLoggerProvider = _getProvider(app, 'platform-logger');
this._heartbeatServiceProvider = _getProvider(app, 'heartbeat');
initializeRecaptchaV3(app, this._siteKey).catch(() => {
/* we don't care about the initialization result */
});
Expand All @@ -131,7 +131,7 @@ export class ReCaptchaV3Provider implements AppCheckProvider {
*/
export class ReCaptchaEnterpriseProvider implements AppCheckProvider {
private _app?: FirebaseApp;
private _platformLoggerProvider?: Provider<'platform-logger'>;
private _heartbeatServiceProvider?: Provider<'heartbeat'>;
/**
* Throttle requests on certain error codes to prevent too many retries
* in a short time.
Expand All @@ -150,7 +150,7 @@ export class ReCaptchaEnterpriseProvider implements AppCheckProvider {
async getToken(): Promise<AppCheckTokenInternal> {
throwIfThrottled(this._throttleData);
// Top-level `getToken()` has already checked that App Check is initialized
// and therefore this._app and this._platformLoggerProvider are available.
// and therefore this._app and this._heartbeatServiceProvider are available.
const attestedClaimsToken = await getReCAPTCHAToken(this._app!).catch(
_e => {
// reCaptcha.execute() throws null which is not very descriptive.
Expand All @@ -164,7 +164,7 @@ export class ReCaptchaEnterpriseProvider implements AppCheckProvider {
this._app!,
attestedClaimsToken
),
this._platformLoggerProvider!
this._heartbeatServiceProvider!
);
} catch (e) {
if ((e as FirebaseError).code === AppCheckError.FETCH_STATUS_ERROR) {
Expand Down Expand Up @@ -192,7 +192,7 @@ export class ReCaptchaEnterpriseProvider implements AppCheckProvider {
*/
initialize(app: FirebaseApp): void {
this._app = app;
this._platformLoggerProvider = _getProvider(app, 'platform-logger');
this._heartbeatServiceProvider = _getProvider(app, 'heartbeat');
initializeRecaptchaEnterprise(app, this._siteKey).catch(() => {
/* we don't care about the initialization result */
});
Expand Down
18 changes: 11 additions & 7 deletions packages/app-check/test/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
} from '@firebase/component';
import { AppCheckService } from '../src/factory';
import { AppCheck, CustomProvider } from '../src';
import { HeartbeatService } from '@firebase/app/dist/app/src/types';

export const FAKE_SITE_KEY = 'fake-site-key';

Expand All @@ -55,15 +56,15 @@ export function getFakeApp(overrides: Record<string, any> = {}): FirebaseApp {
export function getFakeAppCheck(app: FirebaseApp): AppCheck {
return {
app,
platformLoggerProvider: getFakePlatformLoggingProvider()
heartbeatServiceProvider: getFakeHeartbeatServiceProvider()
} as AppCheck;
}

export function getFullApp(): FirebaseApp {
const app = initializeApp(fakeConfig);
_registerComponent(
new Component(
'platform-logger',
'heartbeat',
() => {
return {} as any;
},
Expand Down Expand Up @@ -92,19 +93,22 @@ export function getFakeCustomTokenProvider(): CustomProvider {
});
}

export function getFakePlatformLoggingProvider(
export function getFakeHeartbeatServiceProvider(
fakeLogString: string = 'a/1.2.3 b/2.3.4'
): Provider<'platform-logger'> {
): Provider<'heartbeat'> {
const container = new ComponentContainer('test');
container.addComponent(
new Component(
'platform-logger',
() => ({ getPlatformInfoString: () => fakeLogString }),
'heartbeat',
() =>
({
getHeartbeatsHeader: () => Promise.resolve(fakeLogString)
} as HeartbeatService),
ComponentType.PRIVATE
)
);

return container.getProvider('platform-logger');
return container.getProvider('heartbeat');
}

export function getFakeGreCAPTCHA(
Expand Down