Skip to content

Commit 657c853

Browse files
authored
Add AppCheck integration to functions-exp (#4892)
1 parent 2e6d95a commit 657c853

File tree

5 files changed

+54
-3
lines changed

5 files changed

+54
-3
lines changed

packages-exp/functions-exp/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
"dependencies": {
5353
"@firebase/component": "0.5.3",
5454
"@firebase/messaging-types": "0.5.0",
55+
"@firebase/auth-interop-types": "0.1.6",
56+
"@firebase/app-check-interop-types": "0.1.0",
5557
"@firebase/util": "1.1.0",
5658
"node-fetch": "2.6.1",
5759
"tslib": "^2.1.0"

packages-exp/functions-exp/src/config.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ import {
2424
InstanceFactory
2525
} from '@firebase/component';
2626
import { FUNCTIONS_TYPE } from './constants';
27+
import { AppCheckInternalComponentName } from '@firebase/app-check-interop-types';
2728

29+
const APP_CHECK_INTERNAL_NAME: AppCheckInternalComponentName =
30+
'app-check-internal';
2831
export function registerFunctions(fetchImpl: typeof fetch): void {
2932
const factory: InstanceFactory<'functions-exp'> = (
3033
container: ComponentContainer,
@@ -34,12 +37,14 @@ export function registerFunctions(fetchImpl: typeof fetch): void {
3437
const app = container.getProvider('app-exp').getImmediate();
3538
const authProvider = container.getProvider('auth-internal');
3639
const messagingProvider = container.getProvider('messaging');
40+
const appCheckProvider = container.getProvider(APP_CHECK_INTERNAL_NAME);
3741

3842
// eslint-disable-next-line @typescript-eslint/no-explicit-any
3943
return new FunctionsService(
4044
app,
4145
authProvider,
4246
messagingProvider,
47+
appCheckProvider,
4348
regionOrCustomDomain,
4449
fetchImpl
4550
);

packages-exp/functions-exp/src/context.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ import {
2424
} from '@firebase/messaging-types';
2525

2626
import { Provider } from '@firebase/component';
27+
import {
28+
AppCheckInternalComponentName,
29+
FirebaseAppCheckInternal
30+
} from '@firebase/app-check-interop-types';
2731

2832
/**
2933
* The metadata that should be supplied with function calls.
@@ -32,6 +36,7 @@ import { Provider } from '@firebase/component';
3236
export interface Context {
3337
authToken?: string;
3438
messagingToken?: string;
39+
appCheckToken: string | null;
3540
}
3641

3742
/**
@@ -41,9 +46,11 @@ export interface Context {
4146
export class ContextProvider {
4247
private auth: FirebaseAuthInternal | null = null;
4348
private messaging: FirebaseMessaging | null = null;
49+
private appCheck: FirebaseAppCheckInternal | null = null;
4450
constructor(
4551
authProvider: Provider<FirebaseAuthInternalName>,
46-
messagingProvider: Provider<FirebaseMessagingName>
52+
messagingProvider: Provider<FirebaseMessagingName>,
53+
appCheckProvider: Provider<AppCheckInternalComponentName>
4754
) {
4855
this.auth = authProvider.getImmediate({ optional: true });
4956
this.messaging = messagingProvider.getImmediate({
@@ -67,6 +74,15 @@ export class ContextProvider {
6774
}
6875
);
6976
}
77+
78+
if (!this.appCheck) {
79+
appCheckProvider.get().then(
80+
appCheck => (this.appCheck = appCheck),
81+
() => {
82+
/* get() never rejects */
83+
}
84+
);
85+
}
7086
}
7187

7288
async getAuthToken(): Promise<string | undefined> {
@@ -103,9 +119,22 @@ export class ContextProvider {
103119
}
104120
}
105121

122+
async getAppCheckToken(): Promise<string | null> {
123+
if (this.appCheck) {
124+
const result = await this.appCheck.getToken();
125+
// If getToken() fails, it will still return a dummy token that also has
126+
// an error field containing the error message. We will send any token
127+
// provided here and show an error if/when it is rejected by the functions
128+
// endpoint.
129+
return result.token;
130+
}
131+
return null;
132+
}
133+
106134
async getContext(): Promise<Context> {
107135
const authToken = await this.getAuthToken();
108136
const messagingToken = await this.getMessagingToken();
109-
return { authToken, messagingToken };
137+
const appCheckToken = await this.getAppCheckToken();
138+
return { authToken, messagingToken, appCheckToken };
110139
}
111140
}

packages-exp/functions-exp/src/service.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { encode, decode } from './serializer';
2727
import { Provider } from '@firebase/component';
2828
import { FirebaseAuthInternalName } from '@firebase/auth-interop-types';
2929
import { FirebaseMessagingName } from '@firebase/messaging-types';
30+
import { AppCheckInternalComponentName } from '@firebase/app-check-interop-types';
3031

3132
export const DEFAULT_REGION = 'us-central1';
3233

@@ -86,10 +87,15 @@ export class FunctionsService implements _FirebaseService {
8687
readonly app: FirebaseApp,
8788
authProvider: Provider<FirebaseAuthInternalName>,
8889
messagingProvider: Provider<FirebaseMessagingName>,
90+
appCheckProvider: Provider<AppCheckInternalComponentName>,
8991
regionOrCustomDomain: string = DEFAULT_REGION,
9092
readonly fetchImpl: typeof fetch
9193
) {
92-
this.contextProvider = new ContextProvider(authProvider, messagingProvider);
94+
this.contextProvider = new ContextProvider(
95+
authProvider,
96+
messagingProvider,
97+
appCheckProvider
98+
);
9399
// Cancels all ongoing requests when resolved.
94100
this.cancelAllRequests = new Promise(resolve => {
95101
this.deleteService = () => {
@@ -234,6 +240,9 @@ async function call(
234240
if (context.messagingToken) {
235241
headers['Firebase-Instance-ID-Token'] = context.messagingToken;
236242
}
243+
if (context.appCheckToken !== null) {
244+
headers['X-Firebase-AppCheck'] = context.appCheckToken;
245+
}
237246

238247
// Default timeout to 70s, but let the options override it.
239248
const timeout = options.timeout || 70000;

packages-exp/functions-exp/test/utils.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { FirebaseOptions, FirebaseApp } from '@firebase/app-exp';
1919
import { Provider, ComponentContainer } from '@firebase/component';
2020
import { FirebaseAuthInternalName } from '@firebase/auth-interop-types';
2121
import { FirebaseMessagingName } from '@firebase/messaging-types';
22+
import { AppCheckInternalComponentName } from '@firebase/app-check-interop-types';
2223
import { FunctionsService } from '../src/service';
2324
import { useFunctionsEmulator } from '../src/api';
2425
import nodeFetch from 'node-fetch';
@@ -51,6 +52,10 @@ export function createTestService(
5152
messagingProvider = new Provider<FirebaseMessagingName>(
5253
'messaging',
5354
new ComponentContainer('test')
55+
),
56+
appCheckProvider = new Provider<AppCheckInternalComponentName>(
57+
'app-check-internal',
58+
new ComponentContainer('test')
5459
)
5560
): FunctionsService {
5661
const fetchImpl: typeof fetch =
@@ -59,6 +64,7 @@ export function createTestService(
5964
app,
6065
authProvider,
6166
messagingProvider,
67+
appCheckProvider,
6268
region,
6369
fetchImpl
6470
);

0 commit comments

Comments
 (0)