From e9377d16faa12a9d45f7a34fda97946b9bf008bd Mon Sep 17 00:00:00 2001 From: Derek Burgman Date: Thu, 26 May 2022 20:35:36 -0500 Subject: [PATCH] feat: added firebase appCheck support to client --- apps/demo/src/environments/base.ts | 3 ++ apps/demo/src/root.firebase.module.ts | 2 +- .../dbx-firebase/src/lib/firebase/appcheck.ts | 6 +++ .../src/lib/firebase/firebase.module.ts | 46 +++++++++++++++++-- .../dbx-firebase/src/lib/firebase/index.ts | 1 + .../dbx-firebase/src/lib/firebase/options.ts | 5 ++ 6 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 packages/dbx-firebase/src/lib/firebase/appcheck.ts diff --git a/apps/demo/src/environments/base.ts b/apps/demo/src/environments/base.ts index 3ae074c31..7913a6d3a 100644 --- a/apps/demo/src/environments/base.ts +++ b/apps/demo/src/environments/base.ts @@ -34,6 +34,9 @@ export const base: DemoEnvironment = { ...firebaseInfo.emulators, useEmulators: true, host: '0.0.0.0' + }, + appCheck: { + reCaptchaV3: '6LfojyAgAAAAADvgGBkWUbRJy-4660ZgkLFOtMvS' } } }; diff --git a/apps/demo/src/root.firebase.module.ts b/apps/demo/src/root.firebase.module.ts index a031c9063..75bd3ca9b 100644 --- a/apps/demo/src/root.firebase.module.ts +++ b/apps/demo/src/root.firebase.module.ts @@ -1,5 +1,5 @@ import { FirestoreContext } from '@dereekb/firebase'; -import { DbxFirebaseFirestoreCollectionModule, DbxFirebaseEmulatorModule, DbxFirebaseDefaultFirebaseProvidersModule, DbxFirebaseAuthModule, DbxFirebaseFunctionsModule } from '@dereekb/dbx-firebase'; +import { DbxFirebaseFirestoreCollectionModule, DbxFirebaseEmulatorModule, DbxFirebaseDefaultFirebaseProvidersModule, DbxFirebaseAuthModule, DbxFirebaseFunctionsModule, DbxFirebaseDefaultAppCheckProviderModule } from '@dereekb/dbx-firebase'; import { NgModule } from '@angular/core'; import { environment } from './environments/environment'; import { DemoFirebaseFunctionsGetter, DemoFirestoreCollections, DEMO_FIREBASE_FUNCTIONS_CONFIG, makeDemoFirebaseFunctions, makeDemoFirestoreCollections } from '@dereekb/demo-firebase'; diff --git a/packages/dbx-firebase/src/lib/firebase/appcheck.ts b/packages/dbx-firebase/src/lib/firebase/appcheck.ts new file mode 100644 index 000000000..30aa4ed45 --- /dev/null +++ b/packages/dbx-firebase/src/lib/firebase/appcheck.ts @@ -0,0 +1,6 @@ +import { AppCheckOptions } from '@firebase/app-check'; + +export interface DbxFirebaseAppCheckConfig extends Partial> { + reCaptchaV3: string; + disabled?: boolean; +} diff --git a/packages/dbx-firebase/src/lib/firebase/firebase.module.ts b/packages/dbx-firebase/src/lib/firebase/firebase.module.ts index 3b3024d64..9e2351bb4 100644 --- a/packages/dbx-firebase/src/lib/firebase/firebase.module.ts +++ b/packages/dbx-firebase/src/lib/firebase/firebase.module.ts @@ -1,10 +1,12 @@ import { ModuleWithProviders, NgModule, Injector, InjectionToken } from '@angular/core'; import { FirebaseOptions, initializeApp } from 'firebase/app'; +import { initializeAppCheck, ReCaptchaV3Provider } from 'firebase/app-check'; import { FirebaseApp, provideFirebaseApp } from '@angular/fire/app'; import { provideStorage, getStorage, connectStorageEmulator } from '@angular/fire/storage'; import { provideFunctions, getFunctions, connectFunctionsEmulator } from '@angular/fire/functions'; import { provideFirestore, getFirestore, connectFirestoreEmulator, enableIndexedDbPersistence } from '@angular/fire/firestore'; import { provideAuth, getAuth, connectAuthEmulator } from '@angular/fire/auth'; +import { AppCheck, provideAppCheck } from '@angular/fire/app-check'; import { DbxFirebaseParsedEmulatorsConfig } from './emulators'; import { DbxFirebaseOptions } from './options'; @@ -30,7 +32,40 @@ import { DbxFirebaseOptions } from './options'; }) as any) ] }) -export class DbxFirebaseDefaultFirestoreProviderModule {} +export class DbxFirebaseDefaultFirestoreProviderModule { } + +/** + * Default firebase app check provider module. + */ +@NgModule({ + imports: [ + provideAppCheck(((injector: Injector) => { + const firebaseApp = injector.get(FirebaseApp); + const firebaseOptions = injector.get(DBX_FIREBASE_OPTIONS_TOKEN); + const appCheckOptions = firebaseOptions.appCheck; + const appCheckKnowinglyDisabled = appCheckOptions?.disabled === true || firebaseOptions.emulators?.useEmulators === true; + + let appCheck: AppCheck; + + if (appCheckOptions && !appCheckKnowinglyDisabled) { + // Only enabled outside of app-check environments. The emulators will not use appcheck. + appCheck = initializeAppCheck(firebaseApp, { + provider: new ReCaptchaV3Provider(appCheckOptions.reCaptchaV3), + isTokenAutoRefreshEnabled: appCheckOptions.isTokenAutoRefreshEnabled ?? true + }); + } else { + appCheck = undefined as unknown as AppCheck; + + if (!appCheckKnowinglyDisabled) { + console.error('dbx-firebase: No appcheck configuration for the app, and not specifically disabled in config either.'); + } + } + + return appCheck; + }) as any) + ] +}) +export class DbxFirebaseDefaultAppCheckProviderModule { } /** * Default firebase auth provider module. @@ -50,7 +85,7 @@ export class DbxFirebaseDefaultFirestoreProviderModule {} }) as any) ] }) -export class DbxFirebaseDefaultAuthProviderModule {} +export class DbxFirebaseDefaultAuthProviderModule { } /** * Default firebase storage provider module. @@ -70,7 +105,7 @@ export class DbxFirebaseDefaultAuthProviderModule {} }) as any) ] }) -export class DbxFirebaseDefaultStorageProviderModule {} +export class DbxFirebaseDefaultStorageProviderModule { } /** * Default firebase functions provider module. @@ -93,7 +128,7 @@ export class DbxFirebaseDefaultStorageProviderModule {} }) as any) ] }) -export class DbxFirebaseDefaultFunctionsProviderModule {} +export class DbxFirebaseDefaultFunctionsProviderModule { } export const DBX_FIREBASE_OPTIONS_TOKEN = new InjectionToken('DbxFirebaseOptions'); @@ -106,6 +141,7 @@ export const DBX_FIREBASE_OPTIONS_TOKEN = new InjectionToken('DbxFirebaseOptions const firebaseOptions = injector.get(DBX_FIREBASE_OPTIONS_TOKEN); return initializeApp(firebaseOptions); }) as any), + DbxFirebaseDefaultAppCheckProviderModule, DbxFirebaseDefaultFirestoreProviderModule, DbxFirebaseDefaultAuthProviderModule, DbxFirebaseDefaultStorageProviderModule, @@ -113,6 +149,7 @@ export const DBX_FIREBASE_OPTIONS_TOKEN = new InjectionToken('DbxFirebaseOptions ] }) export class DbxFirebaseDefaultFirebaseProvidersModule { + static forRoot(firebaseOptions: FirebaseOptions): ModuleWithProviders { return { ngModule: DbxFirebaseDefaultFirebaseProvidersModule, @@ -124,4 +161,5 @@ export class DbxFirebaseDefaultFirebaseProvidersModule { ] }; } + } diff --git a/packages/dbx-firebase/src/lib/firebase/index.ts b/packages/dbx-firebase/src/lib/firebase/index.ts index 198a2b9e0..bd79d31ce 100644 --- a/packages/dbx-firebase/src/lib/firebase/index.ts +++ b/packages/dbx-firebase/src/lib/firebase/index.ts @@ -1,3 +1,4 @@ +export * from './appcheck'; export * from './emulators'; export * from './firebase.module'; export * from './firebase.emulator.module'; diff --git a/packages/dbx-firebase/src/lib/firebase/options.ts b/packages/dbx-firebase/src/lib/firebase/options.ts index d70be5d8e..11bdcdb9b 100644 --- a/packages/dbx-firebase/src/lib/firebase/options.ts +++ b/packages/dbx-firebase/src/lib/firebase/options.ts @@ -1,9 +1,14 @@ import { FirebaseOptions } from 'firebase/app'; import { DbxFirebaseLoginModuleRootConfig } from '../auth/login/firebase.login.module'; +import { DbxFirebaseAppCheckConfig } from './appcheck'; import { DbxFirebaseEmulatorsConfig } from './emulators'; export interface DbxFirebaseOptions extends FirebaseOptions, Pick { emulators: DbxFirebaseEmulatorsConfig; + /** + * Firebase AppCheck handling + */ + appCheck?: DbxFirebaseAppCheckConfig; /** * Passed to the Functions initialization to set the domain to use when sending requests. */