Skip to content

Commit

Permalink
fix: added error handling to DbxFirebaseAuthService authUserState
Browse files Browse the repository at this point in the history
  • Loading branch information
dereekb committed Aug 30, 2022
1 parent d745f2a commit 206132f
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 7 deletions.
15 changes: 10 additions & 5 deletions packages/dbx-core/src/lib/auth/router/provider/uirouter/hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { TransitionHookFn, Transition, HookResult, StateService, UIInjector, Tra
import { catchError, map, first, firstValueFrom, Observable, of, switchMap } from 'rxjs';
import { asSegueRef, asSegueRefString, SegueRefOrSegueRefRouterLink } from './../../../../router/segue';
import { DbxAuthService } from '../../../service/auth.service';
import { FactoryWithRequiredInput, getValueFromGetter, isGetter, Maybe } from '@dereekb/util';
import { FactoryWithRequiredInput, getValueFromGetter, isGetter, Maybe, Milliseconds } from '@dereekb/util';
import { Injector } from '@angular/core';
import { timeoutStartWith } from '@dereekb/rxjs';

Expand Down Expand Up @@ -34,6 +34,11 @@ export interface AuthTransitionHookOptions {
* The state to redirect the user to. Defaults to defaultRedirectTarget.
*/
errorRedirectTarget?: string;

/**
* Timeout time for the decision obs. Defaults to 1000ms.
*/
timeoutTime?: Milliseconds;
}

export interface AuthTransitionHookConfig extends AuthTransitionHookOptions {
Expand All @@ -54,7 +59,7 @@ export interface AuthTransitionStateData {
* This generates a TransitionHookFn that can be used with redirecting routes.
*/
export function makeAuthTransitionHook(config: AuthTransitionHookConfig): TransitionHookFn {
const { defaultRedirectTarget, errorRedirectTarget = defaultRedirectTarget } = config;
const { defaultRedirectTarget, errorRedirectTarget = defaultRedirectTarget, timeoutTime = 1000 } = config;

// https://ui-router.github.io/ng2/docs/latest/modules/transition.html#hookresult
const assertIsAuthenticated: TransitionHookFn = (transition: Transition): HookResult => {
Expand Down Expand Up @@ -105,8 +110,8 @@ export function makeAuthTransitionHook(config: AuthTransitionHookConfig): Transi
}

const resultObs = decisionObs.pipe(
// after 10 seconds of no transition working, redirect with a false decision
timeoutStartWith(false as AuthTransitionDecision, 10 * 1000),
// after the timeoutTime seconds of no transition working, redirect with a false decision
timeoutStartWith(false as AuthTransitionDecision, timeoutTime),
first(),
switchMap((decision: AuthTransitionDecision): Observable<HookResult> => {
if (typeof decision === 'boolean') {
Expand All @@ -121,7 +126,7 @@ export function makeAuthTransitionHook(config: AuthTransitionHookConfig): Transi
}
}),
catchError((x) => {
console.warn('Encountered error in auth transition hook.', x);
console.warn(`Encountered error in auth transition hook. Attempting redirect to ${errorRedirectTarget}.`, x);
return of($state.target(errorRedirectTarget, { location: true })); // Redirect to home
})
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { filterMaybe, isNot, timeoutStartWith } from '@dereekb/rxjs';
import { Injectable, Optional } from '@angular/core';
import { AuthUserState, DbxAuthService, loggedOutObsFromIsLoggedIn, loggedInObsFromIsLoggedIn, AuthUserIdentifier, authUserIdentifier } from '@dereekb/dbx-core';
import { Auth, authState, idToken, User, IdTokenResult, ParsedToken, GoogleAuthProvider, signInWithPopup, AuthProvider, PopupRedirectResolver, signInAnonymously, signInWithEmailAndPassword, UserCredential, FacebookAuthProvider, GithubAuthProvider, TwitterAuthProvider, createUserWithEmailAndPassword } from '@angular/fire/auth';
import { of, Observable, distinctUntilChanged, shareReplay, map, switchMap, firstValueFrom } from 'rxjs';
import { of, Observable, distinctUntilChanged, shareReplay, map, switchMap, firstValueFrom, catchError } from 'rxjs';
import { AuthClaims, AuthClaimsObject, AuthRoleClaimsService, AuthRoleSet, AUTH_ADMIN_ROLE, cachedGetter, Maybe } from '@dereekb/util';
import { AuthUserInfo, authUserInfoFromAuthUser, firebaseAuthTokenFromUser } from '../auth';
import { sendPasswordResetEmail } from 'firebase/auth';
Expand Down Expand Up @@ -93,7 +93,11 @@ export class DbxFirebaseAuthService implements DbxAuthService {
constructor(readonly firebaseAuth: Auth, @Optional() delegate: DbxFirebaseAuthServiceDelegate) {
delegate = delegate ?? DEFAULT_DBX_FIREBASE_AUTH_SERVICE_DELEGATE;

const delegateAuthUserStateObs = delegate.authUserStateObs(this).pipe(distinctUntilChanged(), shareReplay(1));
const delegateAuthUserStateObs = delegate.authUserStateObs(this).pipe(
catchError(() => of('error' as AuthUserState)),
distinctUntilChanged(),
shareReplay(1)
);

if (delegate.fullControlOfAuthUserState) {
this.authUserState$ = delegateAuthUserStateObs;
Expand Down

0 comments on commit 206132f

Please sign in to comment.