Skip to content

Commit

Permalink
feat: added authRolesObsWithClaimsService
Browse files Browse the repository at this point in the history
- Can now generate a DbxFirebaseAuthServiceDelegate with a claimsService
- moved demo-components models into models folder. Updated template to reflect changes
- added additional Set utility functions
  • Loading branch information
dereekb committed May 29, 2022
1 parent 9bfb6fd commit 10055ae
Show file tree
Hide file tree
Showing 35 changed files with 132 additions and 58 deletions.
20 changes: 3 additions & 17 deletions apps/demo-api/src/app/common/firebase/auth.service.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,12 @@
import { DEMO_AUTH_CLAIMS_SERVICE } from '@dereekb/demo-firebase';
import { CallableContextWithAuthData, AbstractFirebaseServerAuthContext, AbstractFirebaseServerAuthService, AbstractFirebaseServerAuthUserContext } from '@dereekb/firebase-server';
import { AuthClaims, AuthClaimsUpdate, AuthRoleSet, AUTH_ADMIN_ROLE, AuthRoleClaimsFactoryConfig, authRoleClaimsService } from '@dereekb/util';

export type DemoApiAuthClaims = {
/**
* Admin role
*/
a?: number;
};

export class DemoApiFirebaseServerAuthUserContext extends AbstractFirebaseServerAuthUserContext<DemoApiAuthService> {}

export class DemoApiFirebaseServerAuthContext extends AbstractFirebaseServerAuthContext<DemoApiFirebaseServerAuthContext, DemoApiFirebaseServerAuthUserContext, DemoApiAuthService> {}

export class DemoApiAuthService extends AbstractFirebaseServerAuthService<DemoApiFirebaseServerAuthUserContext, DemoApiFirebaseServerAuthContext> {
static readonly DEMO_API_CLAIMS_CONFIG: AuthRoleClaimsFactoryConfig<DemoApiAuthClaims> = {
a: {
roles: AUTH_ADMIN_ROLE
}
};

static readonly DEMO_API_CLAIMS_SERVICE = authRoleClaimsService(DemoApiAuthService.DEMO_API_CLAIMS_CONFIG);

protected _context(context: CallableContextWithAuthData): DemoApiFirebaseServerAuthContext {
return new DemoApiFirebaseServerAuthContext(this, context);
}
Expand All @@ -30,10 +16,10 @@ export class DemoApiAuthService extends AbstractFirebaseServerAuthService<DemoAp
}

readRoles(claims: AuthClaims): AuthRoleSet {
return DemoApiAuthService.DEMO_API_CLAIMS_SERVICE.toRoles(claims);
return DEMO_AUTH_CLAIMS_SERVICE.toRoles(claims);
}

claimsForRoles(roles: AuthRoleSet): AuthClaimsUpdate {
return DemoApiAuthService.DEMO_API_CLAIMS_SERVICE.toClaims(roles);
return DEMO_AUTH_CLAIMS_SERVICE.toClaims(roles);
}
}
13 changes: 10 additions & 3 deletions apps/demo/src/root.firebase.module.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import { FirestoreContext } from '@dereekb/firebase';
import { DbxFirebaseFirestoreCollectionModule, DbxFirebaseEmulatorModule, DbxFirebaseDefaultFirebaseProvidersModule, DbxFirebaseAuthModule, DbxFirebaseFunctionsModule, DbxFirebaseDefaultAppCheckProviderModule } from '@dereekb/dbx-firebase';
import { DbxFirebaseFirestoreCollectionModule, DbxFirebaseEmulatorModule, DbxFirebaseDefaultFirebaseProvidersModule, DbxFirebaseAuthModule, DbxFirebaseFunctionsModule, defaultDbxFirebaseAuthServiceDelegateWithClaimsService, DbxFirebaseAuthServiceDelegate } 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';
import { DemoFirebaseFunctionsGetter, DemoFirestoreCollections, DEMO_AUTH_CLAIMS_SERVICE, DEMO_FIREBASE_FUNCTIONS_CONFIG, makeDemoFirebaseFunctions, makeDemoFirestoreCollections } from '@dereekb/demo-firebase';

export function demoAuthDelegateFactory(): DbxFirebaseAuthServiceDelegate {
return defaultDbxFirebaseAuthServiceDelegateWithClaimsService({
claimsService: DEMO_AUTH_CLAIMS_SERVICE,
addAuthUserStateToRoles: true
});
}

@NgModule({
imports: [
Expand All @@ -19,7 +26,7 @@ import { DemoFirebaseFunctionsGetter, DemoFirestoreCollections, DEMO_FIREBASE_FU
functionsConfigMap: DEMO_FIREBASE_FUNCTIONS_CONFIG
}),
DbxFirebaseAuthModule.forRoot({
delegateFactory: undefined // todo
delegateFactory: demoAuthDelegateFactory
})
],
providers: []
Expand Down
14 changes: 14 additions & 0 deletions components/demo-firebase/src/lib/auth/claims.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { AUTH_ADMIN_ROLE, authRoleClaimsService } from '@dereekb/util';

export type DemoApiAuthClaims = {
/**
* Admin role
*/
a?: number;
};

export const DEMO_AUTH_CLAIMS_SERVICE = authRoleClaimsService<DemoApiAuthClaims>({
a: {
roles: AUTH_ADMIN_ROLE
}
});
1 change: 1 addition & 0 deletions components/demo-firebase/src/lib/auth/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './claims';
3 changes: 1 addition & 2 deletions components/demo-firebase/src/lib/collection.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { FirestoreContext } from '@dereekb/firebase';
import { guestbookEntryFirestoreCollectionFactory, GuestbookEntryFirestoreCollectionFactory, guestbookEntryFirestoreCollectionGroup, GuestbookEntryFirestoreCollectionGroup, guestbookFirestoreCollection, GuestbookFirestoreCollection, GuestbookFirestoreCollections } from './guestbook';
import { profileFirestoreCollection, ProfileFirestoreCollection, ProfileFirestoreCollections, profilePrivateDataFirestoreCollectionFactory, ProfilePrivateDataFirestoreCollectionFactory } from './profile/profile';
import { guestbookEntryFirestoreCollectionFactory, GuestbookEntryFirestoreCollectionFactory, guestbookEntryFirestoreCollectionGroup, GuestbookEntryFirestoreCollectionGroup, guestbookFirestoreCollection, GuestbookFirestoreCollection, GuestbookFirestoreCollections, profileFirestoreCollection, ProfileFirestoreCollection, ProfileFirestoreCollections, profilePrivateDataFirestoreCollectionFactory, ProfilePrivateDataFirestoreCollectionFactory } from './models';

export abstract class DemoFirestoreCollections implements ProfileFirestoreCollections, GuestbookFirestoreCollections {
abstract readonly guestbookFirestoreCollection: GuestbookFirestoreCollection;
Expand Down
4 changes: 1 addition & 3 deletions components/demo-firebase/src/lib/functions.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { ProfileFunctionTypeMap } from './profile/profile.api';
import { FirebaseFunctionGetter, FirebaseFunctionsConfigMap, lazyFirebaseFunctionsFactory } from '@dereekb/firebase';
import { Functions } from 'firebase/functions';
import { guestbookFunctionMap, GuestbookFunctions, GuestbookFunctionTypeMap } from './guestbook';
import { profileFunctionMap, ProfileFunctions } from './profile';
import { ProfileFunctionTypeMap, guestbookFunctionMap, GuestbookFunctions, GuestbookFunctionTypeMap, profileFunctionMap, ProfileFunctions } from './models';

/**
* FirebaseFunctionsMap type for Demo
Expand Down
4 changes: 2 additions & 2 deletions components/demo-firebase/src/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * from './guestbook';
export * from './profile';
export * from './auth';
export * from './models';
export * from './collection';
export * from './functions';
2 changes: 2 additions & 0 deletions components/demo-firebase/src/lib/models/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './guestbook';
export * from './profile';
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { addToSetCopy, AuthClaims, AuthClaimsObject, AuthRoleClaimsService, AuthRoleSet } from '@dereekb/util';
import { map, Observable, switchMap } from 'rxjs';
import { DbxFirebaseAuthService, DbxFirebaseAuthServiceDelegate, DEFAULT_DBX_FIREBASE_AUTH_SERVICE_DELEGATE } from './firebase.auth.service';

export interface AuthRolesObsWithClaimsServiceConfig<T extends AuthClaimsObject> {
readonly claimsService: AuthRoleClaimsService<T>;
/**
* Whether or not to also add the current AuthUserState value to decoded roles.
*/
readonly addAuthUserStateToRoles?: boolean;
}

export function authRolesObsWithClaimsService<T extends AuthClaimsObject>(config: AuthRolesObsWithClaimsServiceConfig<T>): (dbxFirebaseAuthService: DbxFirebaseAuthService) => Observable<AuthRoleSet> {
const { addAuthUserStateToRoles: addAuthUserState, claimsService } = config;

return (dbxFirebaseAuthService: DbxFirebaseAuthService): Observable<AuthRoleSet> => {
let obs = dbxFirebaseAuthService.idTokenResult$.pipe(map((x) => claimsService.toRoles(x.claims as AuthClaims<T>)));

if (addAuthUserState) {
obs = obs.pipe(switchMap((authRoleSet: AuthRoleSet) => dbxFirebaseAuthService.authUserState$.pipe(map((userState) => addToSetCopy(authRoleSet, userState)))));
}

return obs;
};
}

export interface DefaultDbxFirebaseAuthServiceDelegateWithClaimsServiceConfig<T extends AuthClaimsObject> extends AuthRolesObsWithClaimsServiceConfig<T> {}

export function defaultDbxFirebaseAuthServiceDelegateWithClaimsService<T extends AuthClaimsObject>(config: DefaultDbxFirebaseAuthServiceDelegateWithClaimsServiceConfig<T>): DbxFirebaseAuthServiceDelegate {
return {
authUserStateObs: DEFAULT_DBX_FIREBASE_AUTH_SERVICE_DELEGATE.authUserStateObs,
authRolesObs: authRolesObsWithClaimsService(config),
isOnboarded: DEFAULT_DBX_FIREBASE_AUTH_SERVICE_DELEGATE.isOnboarded
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { AuthUserState, DbxAuthService, loggedOutObsFromIsLoggedIn, loggedInObsF
import { Auth, authState, User, IdTokenResult, ParsedToken, GoogleAuthProvider, signInWithPopup, AuthProvider, PopupRedirectResolver, signInAnonymously, signInWithEmailAndPassword, UserCredential, FacebookAuthProvider, GithubAuthProvider, TwitterAuthProvider, createUserWithEmailAndPassword } from '@angular/fire/auth';
import { Observable, timeout, startWith, distinctUntilChanged, shareReplay, map, switchMap } from 'rxjs';
import { AuthRoleSet, Maybe } from '@dereekb/util';
import { authUserStateFromFirebaseAuthService } from './firebase.auth.rxjs';
import { AuthUserInfo, authUserInfoFromAuthUser } from '../auth';
import { sendPasswordResetEmail } from 'firebase/auth';
import { authUserStateFromFirebaseAuthService } from './firebase.auth.rxjs';

// MARK: Delegate
export abstract class DbxFirebaseAuthServiceDelegate {
abstract authUserStateObs(dbxFirebaseAuthService: DbxFirebaseAuthService): Observable<AuthUserState>;
abstract authRolesObs(dbxFirebaseAuthService: DbxFirebaseAuthService): Observable<AuthRoleSet>;
Expand All @@ -26,6 +27,7 @@ export const DEFAULT_DBX_FIREBASE_AUTH_SERVICE_DELEGATE: DbxFirebaseAuthServiceD
}
};

// MARK: Service
@Injectable()
export class DbxFirebaseAuthService implements DbxAuthService {
private readonly _authState$: Observable<Maybe<User>> = authState(this.firebaseAuth);
Expand Down
1 change: 1 addition & 0 deletions packages/dbx-firebase/src/lib/auth/service/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './firebase.auth.rxjs';
export * from './firebase.auth.service';
export * from './firebase.auth.service.delegate';
14 changes: 14 additions & 0 deletions packages/util/src/lib/set/set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,24 @@ export function asSet<T>(values: IterableOrValue<T>): Set<T> {
return set;
}

export function copySetAndDo<T>(set: Set<T>, fn: (set: Set<T>) => void): Set<T> {
const newSet = new Set(set);
fn(newSet);
return newSet;
}

export function addToSetCopy<T>(set: Set<T>, values: Maybe<IterableOrValue<T>>): Set<T> {
return copySetAndDo(set, (x) => addToSet(x, values));
}

export function addToSet<T>(set: Set<T>, values: Maybe<IterableOrValue<T>>) {
useIterableOrValue(values, (x) => set.add(x));
}

export function removeFromSetCopy<T>(set: Set<T>, values: Maybe<IterableOrValue<T>>): Set<T> {
return copySetAndDo(set, (x) => removeFromSet(x, values));
}

export function removeFromSet<T>(set: Set<T>, values: Maybe<IterableOrValue<T>>) {
useIterableOrValue(values, (x) => set.delete(x));
}
Expand Down
20 changes: 13 additions & 7 deletions setup/setup-project.sh
Original file line number Diff line number Diff line change
Expand Up @@ -453,13 +453,19 @@ download_firebase_ts_file "src/lib/index.ts"
download_firebase_ts_file "src/lib/collection.ts"
download_firebase_ts_file "src/lib/functions.ts"

# Example Folder
mkdir $FIREBASE_COMPONENTS_FOLDER/src/lib/example
download_firebase_ts_file "src/lib/example/example.action.ts"
download_firebase_ts_file "src/lib/example/example.api.ts"
download_firebase_ts_file "src/lib/example/example.query.ts"
download_firebase_ts_file "src/lib/example/example.ts"
download_firebase_ts_file "src/lib/example/index.ts"
# Auth Folder
mkdir $FIREBASE_COMPONENTS_FOLDER/src/lib/auth
download_firebase_ts_file "src/lib/auth/claims.ts"
download_firebase_ts_file "src/lib/auth/index.ts"

# Model/Example Folder
mkdir $FIREBASE_COMPONENTS_FOLDER/src/lib/models
mkdir $FIREBASE_COMPONENTS_FOLDER/src/lib/models/example
download_firebase_ts_file "src/lib/models/example/example.action.ts"
download_firebase_ts_file "src/lib/models/example/example.api.ts"
download_firebase_ts_file "src/lib/models/example/example.query.ts"
download_firebase_ts_file "src/lib/models/example/example.ts"
download_firebase_ts_file "src/lib/models/example/index.ts"

git add --all
git commit --no-verify -m "checkpoint: setup api components"
Expand Down
20 changes: 3 additions & 17 deletions setup/templates/apps/api/src/app/common/firebase/auth.service.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import { CallableContextWithAuthData, AbstractFirebaseServerAuthContext, AbstractFirebaseServerAuthService, AbstractFirebaseServerAuthUserContext } from "@dereekb/firebase-server";
import { AuthClaims, AuthClaimsUpdate, AuthRoleSet, AuthRoleClaimsFactoryConfig, authRoleClaimsService, AUTH_ADMIN_ROLE } from "@dereekb/util";

export type APP_CODE_PREFIXApiAuthClaims = {
/**
* Admin role
*/
a?: number;
}
import { APP_CODE_PREFIX_UPPER_AUTH_CLAIMS_SERVICE } from 'FIREBASE_COMPONENTS_NAME';

export class APP_CODE_PREFIXApiFirebaseServerAuthUserContext extends AbstractFirebaseServerAuthUserContext<APP_CODE_PREFIXApiAuthService> {

Expand All @@ -18,14 +12,6 @@ export class APP_CODE_PREFIXApiFirebaseServerAuthContext extends AbstractFirebas

export class APP_CODE_PREFIXApiAuthService extends AbstractFirebaseServerAuthService<APP_CODE_PREFIXApiFirebaseServerAuthUserContext, APP_CODE_PREFIXApiFirebaseServerAuthContext> {

static readonly APP_CODE_PREFIX_UPPER_API_CLAIMS_CONFIG: AuthRoleClaimsFactoryConfig<APP_CODE_PREFIXApiAuthClaims> = {
a: {
roles: AUTH_ADMIN_ROLE
}
};

static readonly APP_CODE_PREFIX_UPPER_API_CLAIMS_SERVICE = authRoleClaimsService(APP_CODE_PREFIXApiAuthService.APP_CODE_PREFIX_UPPER_API_CLAIMS_CONFIG);

protected _context(context: CallableContextWithAuthData): APP_CODE_PREFIXApiFirebaseServerAuthContext {
return new APP_CODE_PREFIXApiFirebaseServerAuthContext(this, context);
}
Expand All @@ -35,11 +21,11 @@ export class APP_CODE_PREFIXApiAuthService extends AbstractFirebaseServerAuthSer
}

readRoles(claims: AuthClaims): AuthRoleSet {
return APP_CODE_PREFIXApiAuthService.APP_CODE_PREFIX_UPPER_API_CLAIMS_SERVICE.toRoles(claims);
return APP_CODE_PREFIX_UPPER_AUTH_CLAIMS_SERVICE.toRoles(claims);
}

claimsForRoles(roles: AuthRoleSet): AuthClaimsUpdate {
return APP_CODE_PREFIXApiAuthService.APP_CODE_PREFIX_UPPER_API_CLAIMS_SERVICE.toClaims(roles);
return APP_CODE_PREFIX_UPPER_AUTH_CLAIMS_SERVICE.toClaims(roles);
}

}
13 changes: 10 additions & 3 deletions setup/templates/apps/app/src/root.firebase.module.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import { FirestoreContext } from '@dereekb/firebase';
import { DbxFirebaseFirestoreCollectionModule, DbxFirebaseEmulatorModule, DbxFirebaseDefaultFirebaseProvidersModule, DbxFirebaseAuthModule, DbxFirebaseFunctionsModule } from '@dereekb/dbx-firebase';
import { DbxFirebaseFirestoreCollectionModule, DbxFirebaseEmulatorModule, DbxFirebaseDefaultFirebaseProvidersModule, DbxFirebaseAuthModule, DbxFirebaseFunctionsModule, defaultDbxFirebaseAuthServiceDelegateWithClaimsService, DbxFirebaseAuthServiceDelegate } from '@dereekb/dbx-firebase';
import { NgModule } from '@angular/core';
import { environment } from './environments/environment';
import { APP_CODE_PREFIXFirebaseFunctionsGetter, APP_CODE_PREFIXFirestoreCollections, APP_CODE_PREFIX_UPPER_FIREBASE_FUNCTIONS_CONFIG, makeAPP_CODE_PREFIXFirebaseFunctions, makeAPP_CODE_PREFIXFirestoreCollections } from 'FIREBASE_COMPONENTS_NAME';
import { APP_CODE_PREFIXFirebaseFunctionsGetter, APP_CODE_PREFIXFirestoreCollections, APP_CODE_PREFIX_UPPER_FIREBASE_FUNCTIONS_CONFIG, makeAPP_CODE_PREFIXFirebaseFunctions, makeAPP_CODE_PREFIXFirestoreCollections, APP_CODE_PREFIX_UPPER_AUTH_CLAIMS_SERVICE } from 'FIREBASE_COMPONENTS_NAME';

export function APP_CODE_PREFIX_LOWERAuthDelegateFactory(): DbxFirebaseAuthServiceDelegate {
return defaultDbxFirebaseAuthServiceDelegateWithClaimsService({
claimsService: APP_CODE_PREFIX_UPPER_AUTH_CLAIMS_SERVICE,
addAuthUserStateToRoles: true
});
}

@NgModule({
imports: [
Expand All @@ -19,7 +26,7 @@ import { APP_CODE_PREFIXFirebaseFunctionsGetter, APP_CODE_PREFIXFirestoreCollect
functionsConfigMap: APP_CODE_PREFIX_UPPER_FIREBASE_FUNCTIONS_CONFIG
}),
DbxFirebaseAuthModule.forRoot({
delegateFactory: undefined // todo
delegateFactory: APP_CODE_PREFIX_LOWERAuthDelegateFactory
})
],
providers: []
Expand Down
14 changes: 14 additions & 0 deletions setup/templates/components/firebase/src/lib/auth/claims.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { AUTH_ADMIN_ROLE, authRoleClaimsService } from '@dereekb/util';

export type APP_CODE_PREFIXApiAuthClaims = {
/**
* Admin role
*/
a?: number;
}

export const APP_CODE_PREFIX_UPPER_AUTH_CLAIMS_SERVICE = authRoleClaimsService<APP_CODE_PREFIXApiAuthClaims>({
a: {
roles: AUTH_ADMIN_ROLE
}
});
1 change: 1 addition & 0 deletions setup/templates/components/firebase/src/lib/auth/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './claims';
3 changes: 1 addition & 2 deletions setup/templates/components/firebase/src/lib/functions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { ExampleFunctionTypeMap } from './example/example.api';
import { FirebaseFunctionGetter, FirebaseFunctionsConfigMap, lazyFirebaseFunctionsFactory } from '@dereekb/firebase';
import { Functions } from 'firebase/functions';
import { exampleFunctionMap, ExampleFunctions } from './example';
import {ExampleFunctionTypeMap, exampleFunctionMap, ExampleFunctions } from './models';

export type APP_CODE_PREFIXFirebaseFunctionsMap = {
exampleFunctions: ExampleFunctionTypeMap;
Expand Down
3 changes: 2 additions & 1 deletion setup/templates/components/firebase/src/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './example';
export * from './auth';
export * from './models';
export * from './collection';
export * from './functions';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './example';

0 comments on commit 10055ae

Please sign in to comment.