Skip to content

Commit

Permalink
fix(auth): providerData issue (#420)
Browse files Browse the repository at this point in the history
* fix(auth): providerData issue

* fix(tests): Auth specs
  • Loading branch information
davideast authored Aug 12, 2016
1 parent 6219ac1 commit 1ebb726
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 73 deletions.
17 changes: 8 additions & 9 deletions src/auth/auth.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { auth, initializeApp } from 'firebase';
import {ReflectiveInjector, provide, Provider} from '@angular/core';
import { ReflectiveInjector, provide, Provider } from '@angular/core';
import { Observable } from 'rxjs/Observable'
import { Observer } from 'rxjs/Observer';
import {
Expand All @@ -23,8 +23,8 @@ import {
} from '../angularfire2';
import { COMMON_CONFIG } from '../test-config';

import {AuthBackend} from './auth_backend';
import {FirebaseSdkAuthBackend} from './firebase_sdk_auth_backend';
import { AuthBackend } from './auth_backend';
import { FirebaseSdkAuthBackend } from './firebase_sdk_auth_backend';

// Set providers from firebase so no firebase.auth.GoogleProvider() necessary
const {
Expand Down Expand Up @@ -66,7 +66,6 @@ const anonymouseFirebaseUser = <firebase.User> {

const githubCredential = {
credential: {
accessToken: 'ACCESS_TOKEN',
provider: 'github.com'
},
user: firebaseUser
Expand All @@ -77,15 +76,15 @@ const googleCredential = {
user: firebaseUser
}

const AngularFireAuthState = <FirebaseAuthState>{
const AngularFireAuthState = {
provider: 0,
auth: firebaseUser,
uid: '12345',
github: {
accessToken: 'GH_ACCESS_TOKEN',
provider: 'github.com'
}
};
displayName: 'FirebaseUser',
providerId: 'github.com'
} as firebase.UserInfo
} as FirebaseAuthState;

describe('Zones', () => {
it('should call operators and subscriber in the same zone as when service was initialized', (done) => {
Expand Down
9 changes: 4 additions & 5 deletions src/auth/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
AuthProviders,
AuthMethods,
EmailPasswordCredentials,
OAuthCredential,
AuthConfiguration,
FirebaseAuthState,
stripProviderId
Expand All @@ -29,7 +28,7 @@ export const firebaseAuthConfig = (config: AuthConfiguration): any => {

@Injectable()
export class AngularFireAuth extends ReplaySubject<FirebaseAuthState> {
private _credentialCache: {[key:string]: OAuthCredential} = {};
private _credentialCache: {[key:string]: any} = {};
constructor(private _authBackend: AuthBackend,
@Inject(WindowLocation) loc: any,
@Optional() @Inject(FirebaseAuthConfig) private _config?: AuthConfiguration) {
Expand All @@ -46,7 +45,7 @@ export class AngularFireAuth extends ReplaySubject<FirebaseAuthState> {
.map((userCredential: firebase.auth.UserCredential) => {
if (userCredential && userCredential.credential) {
authState = attachCredentialToAuthState(authState, userCredential.credential, userCredential.credential.provider);
this._credentialCache[userCredential.credential.provider] = <OAuthCredential>userCredential.credential;
this._credentialCache[userCredential.credential.provider] = userCredential.credential;
}
return authState;
});
Expand Down Expand Up @@ -102,8 +101,8 @@ export class AngularFireAuth extends ReplaySubject<FirebaseAuthState> {
return this._authBackend.authWithOAuthPopup(config.provider, this._scrubConfig(config))
.then((userCredential: firebase.auth.UserCredential) => {
// Incorrect type information
this._credentialCache[userCredential.credential.provider] = <OAuthCredential>userCredential.credential;
return authDataToAuthState(userCredential.user, <OAuthCredential>(<any>userCredential).credential);
this._credentialCache[userCredential.credential.provider] = userCredential.credential;
return authDataToAuthState(userCredential.user, (<any>userCredential).credential);
});
case AuthMethods.Redirect:
// Gets around typings issue since this method doesn't resolve with a user.
Expand Down
62 changes: 29 additions & 33 deletions src/auth/auth_backend.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import {
authDataToAuthState,
AuthProviders,
FirebaseAuthState,
CommonOAuthCredential,
GoogleCredential,
TwitterCredential
FirebaseAuthState
} from './auth_backend';

const baseFBUser = {
Expand All @@ -25,94 +22,93 @@ const baseAuthState: FirebaseAuthState = {
auth: <firebase.User>baseFBUser
};

const baseGithubCredential: CommonOAuthCredential = {
accessToken: 'GH_ACCESS_TOKEN',
provider: 'github.com'
};
const baseGithubCredential = {
providerId: 'github.com',
displayName: 'GithubAlice'
} as firebase.UserInfo;

const baseFacebookCredential: CommonOAuthCredential = {
accessToken: 'FB_ACCESS_TOKEN',
provider: 'facebook.com'
};
const baseFacebookCredential = {
displayName: 'FacebookFranny',
providerId: 'facebook.com'
} as firebase.UserInfo;

const baseGoogleCredential: GoogleCredential = {
idToken: 'GOOGLE_ID_TOKEN',
provider: 'google.com'
};
const baseGoogleCredential = {
displayName: 'GoogleGerry',
providerId: 'google.com'
} as firebase.UserInfo;

const baseTwitterCredential: TwitterCredential = {
accessToken: 'TWITTER_ACCESS_TOKEN',
provider: 'twitter.com',
secret: 'TWITTER_SECRET'
};
const baseTwitterCredential = {
displayName: 'TwitterTiffany',
providerId: 'twitter.com',
} as firebase.UserInfo;

describe('auth_backend', () => {
describe('authDataToAuthState', () => {
it('Github: should return a FirebaseAuthState object with full provider data', () => {
let githubUser = Object.assign({}, baseFBUser, {
providerData: [{providerId: 'github.com'}]
});
}) as firebase.User;
let expectedAuthState = Object.assign({}, baseAuthState, {
github: baseGithubCredential,
auth: githubUser
});

let actualAuthState = authDataToAuthState(githubUser, baseGithubCredential);
expect(actualAuthState.github.accessToken).toEqual(baseGithubCredential.accessToken);
expect(actualAuthState.github.displayName).toEqual(baseGithubCredential.displayName);
});
});

it('Google: should return a FirebaseAuthState object with full provider data', () => {
let googleUser = Object.assign({}, baseFBUser, {
providerData: [{providerId: 'google.com'}]
});
}) as firebase.User;
let expectedAuthState = Object.assign({}, baseAuthState, {
google: baseGoogleCredential,
auth: googleUser
});

let actualAuthState = authDataToAuthState(googleUser, baseGoogleCredential);
expect(actualAuthState.google.idToken).toEqual(baseGoogleCredential.idToken);
expect(actualAuthState.google.displayName).toEqual(baseGoogleCredential.displayName);
});

it('Twitter: should return a FirebaseAuthState object with full provider data', () => {
let twitterUser = Object.assign({}, baseFBUser, {
providerData: [{providerId: 'twitter.com'}]
});
}) as firebase.User;
let expectedAuthState = Object.assign({}, baseAuthState, {
twitter: baseTwitterCredential,
auth: twitterUser
});

let actualAuthState = authDataToAuthState(twitterUser, baseTwitterCredential);
expect(actualAuthState.twitter.secret).toEqual(baseTwitterCredential.secret);
expect(actualAuthState.twitter.displayName).toEqual(baseTwitterCredential.displayName);
});

it('Facebook: should return a FirebaseAuthState object with full provider data', () => {
let facebookUser = Object.assign({}, baseFBUser, {
providerData: [{providerId: 'facebook.com'}]
});
}) as firebase.User;
let expectedAuthState = Object.assign({}, baseAuthState, {
facebook: baseFacebookCredential,
auth: facebookUser
});

let actualAuthState = authDataToAuthState(facebookUser, baseFacebookCredential);
expect(actualAuthState.facebook.accessToken).toEqual(baseFacebookCredential.accessToken);
expect(actualAuthState.facebook.displayName).toEqual(baseFacebookCredential.displayName);
});


it('Anonymous: should return a FirebaseAuthState object', () => {
let anonymouseFirebaseUser = Object.assign({}, baseFBUser, {
let anonymousFirebaseUser = Object.assign({}, baseFBUser, {
providerData: [],
isAnonymous: true
});
}) as firebase.User;
let expectedAuthState = Object.assign({}, baseAuthState, {
facebook: baseFacebookCredential,
auth: anonymouseFirebaseUser
auth: anonymousFirebaseUser
});

let actualAuthState = authDataToAuthState(anonymouseFirebaseUser);
let actualAuthState = authDataToAuthState(anonymousFirebaseUser);
expect(actualAuthState.anonymous).toEqual(true);
});
});
39 changes: 14 additions & 25 deletions src/auth/auth_backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,30 +46,14 @@ export interface FirebaseAuthState {
provider: AuthProviders;
auth: firebase.User;
expires?: number;
github?: CommonOAuthCredential;
google?: GoogleCredential;
twitter?: TwitterCredential;
facebook?: CommonOAuthCredential;
github?: firebase.UserInfo;
google?: firebase.UserInfo;
twitter?: firebase.UserInfo;
facebook?: firebase.UserInfo;
anonymous?: boolean;
}

export interface CommonOAuthCredential {
accessToken: string;
provider: 'github.com' | 'google.com' | 'twitter.com' | 'facebook.com';
}

export interface GoogleCredential {
idToken: string;
provider: 'google.com';
}

export interface TwitterCredential extends CommonOAuthCredential {
secret: string;
}

export type OAuthCredential = CommonOAuthCredential | GoogleCredential | TwitterCredential;

export function authDataToAuthState(authData: any, providerData?: OAuthCredential): FirebaseAuthState {
export function authDataToAuthState(authData: firebase.User, providerData?: firebase.UserInfo): FirebaseAuthState {
if (!authData) return null;
let providerId;
let { uid } = authData;
Expand All @@ -79,25 +63,30 @@ export function authDataToAuthState(authData: any, providerData?: OAuthCredentia
authState.provider = AuthProviders.Anonymous;
authState.anonymous = true;
return authState;
} else if (authData.providerData[0] === undefined || authData.providerData[0] === null) {
// There is no provider data, user is likely custom
providerId = 'custom';
authState.provider = AuthProviders.Custom;
return authState;
} else {
providerId = authData.providerData[0].providerId;
}

switch (providerId) {
case 'github.com':
authState.github = <CommonOAuthCredential>providerData;
authState.github = providerData;
authState.provider = AuthProviders.Github;
break;
case 'twitter.com':
authState.twitter = <TwitterCredential>providerData;
authState.twitter = providerData;
authState.provider = AuthProviders.Twitter;
break;
case 'facebook.com':
authState.facebook = <CommonOAuthCredential>providerData;
authState.facebook = providerData;
authState.provider = AuthProviders.Facebook;
break;
case 'google.com':
authState.google = <GoogleCredential>providerData;
authState.google = providerData;
authState.provider = AuthProviders.Google;
break;
case 'password':
Expand Down
2 changes: 1 addition & 1 deletion src/auth/firebase_sdk_auth_backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export class FirebaseSdkAuthBackend extends AuthBackend {
})
.map((user: firebase.User) => {
if (!user) return null;
return authDataToAuthState(user);
return authDataToAuthState(user, user.providerData[0]);
})
/**
* TODO: since the auth service automatically subscribes to this before
Expand Down

0 comments on commit 1ebb726

Please sign in to comment.