-
Notifications
You must be signed in to change notification settings - Fork 2.2k
/
Copy pathauth.ts
190 lines (171 loc) · 7.42 KB
/
auth.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
import { Provider, Inject, provide, Injectable, Optional } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Observer } from 'rxjs/Observer';
import { ReplaySubject } from 'rxjs/ReplaySubject';
import { FirebaseApp, FirebaseAuthConfig, WindowLocation } from '../tokens';
import * as utils from '../utils';
import {
authDataToAuthState,
AuthBackend,
AuthProviders,
AuthMethods,
EmailPasswordCredentials,
AuthConfiguration,
FirebaseAuthState,
stripProviderId
} from './auth_backend';
import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/operator/take';
import 'rxjs/add/operator/concat';
import 'rxjs/add/operator/skip';
import 'rxjs/add/observable/of';
const kBufferSize = 1;
export const firebaseAuthConfig = (config: AuthConfiguration): any => {
return { provide: FirebaseAuthConfig, useValue: config }
};
@Injectable()
export class AngularFireAuth extends ReplaySubject<FirebaseAuthState> {
private _credentialCache: {[key:string]: any} = {};
constructor(private _authBackend: AuthBackend,
@Inject(WindowLocation) loc: any,
@Optional() @Inject(FirebaseAuthConfig) private _config?: AuthConfiguration) {
super(kBufferSize);
let firstPass = true;
this._authBackend.onAuth()
.mergeMap((authState: FirebaseAuthState) => {
if (firstPass) {
firstPass = false;
if(['http:', 'https:'].indexOf(loc.protocol) > -1) {
// Only call getRedirectResult() in a browser
return this._authBackend.getRedirectResult()
.map((userCredential: firebase.auth.UserCredential) => {
if (userCredential && userCredential.credential) {
authState = attachCredentialToAuthState(authState, userCredential.credential, userCredential.credential.provider);
this._credentialCache[userCredential.credential.provider] = userCredential.credential;
}
return authState;
});
}
}
return Observable.of(authState);
})
.subscribe((authData: FirebaseAuthState) => this._emitAuthData(authData));
}
public login(config?: AuthConfiguration): firebase.Promise<FirebaseAuthState>;
// If logging in with email and password
public login(credentials?: EmailPasswordCredentials | firebase.auth.AuthCredential | string): firebase.Promise<FirebaseAuthState>;
public login(credentials: EmailPasswordCredentials | firebase.auth.AuthCredential | string, config?: AuthConfiguration): firebase.Promise<FirebaseAuthState>;
public login(obj1?: any, obj2?: AuthConfiguration): firebase.Promise<FirebaseAuthState> {
let config: AuthConfiguration = null;
let credentials: EmailPasswordCredentials | firebase.auth.AuthCredential | string = null;
if (arguments.length > 2) {
return this._reject('Login only accepts a maximum of two arguments.');
} else if (arguments.length == 2) {
credentials = obj1;
config = obj2;
} else if (arguments.length == 1) {
// Check if obj1 is password credentials
if (obj1.password && obj1.email) {
credentials = obj1;
config = {};
} else {
config = obj1;
}
}
config = this._mergeConfigs(config);
if (!utils.isPresent(config.method)) {
return this._reject('You must provide a login method');
}
let providerMethods = [AuthMethods.Popup, AuthMethods.Redirect, AuthMethods.OAuthToken];
if (providerMethods.indexOf(config.method) != -1) {
if (!utils.isPresent(config.provider)) {
return this._reject('You must include a provider to use this auth method.');
}
}
let credentialsMethods = [AuthMethods.Password, AuthMethods.OAuthToken, AuthMethods.CustomToken];
if (credentialsMethods.indexOf(config.method) != -1) {
if (!credentials) {
return this._reject('You must include credentials to use this auth method.');
}
}
switch (config.method) {
case AuthMethods.Popup:
return this._authBackend.authWithOAuthPopup(config.provider, this._scrubConfig(config))
.then((userCredential: firebase.auth.UserCredential) => {
// Incorrect type information
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.
// The method really only does anything with an error, since it redirects.
return <Promise<FirebaseAuthState>>(<any>this._authBackend).authWithOAuthRedirect(config.provider, this._scrubConfig(config));
case AuthMethods.Anonymous:
return this._authBackend.authAnonymously(this._scrubConfig(config));
case AuthMethods.Password:
return this._authBackend.authWithPassword(<EmailPasswordCredentials>credentials);
case AuthMethods.OAuthToken:
return this._authBackend.authWithOAuthToken(<firebase.auth.AuthCredential>credentials,
this._scrubConfig(config));
case AuthMethods.CustomToken:
return this._authBackend.authWithCustomToken(<string>credentials);
}
}
public logout(): void {
this._authBackend.unauth();
}
public getAuth(): FirebaseAuthState {
console.warn(`WARNING: the getAuth() API has changed behavior since adding support for Firebase 3.
This will return null for the initial value when the page loads, even if the user is actually logged in.
Please observe the actual authState asynchronously by subscribing to the auth service: af.auth.subscribe().
The getAuth method will be removed in future releases`);
return this._authBackend.getAuth()
}
public createUser(credentials: EmailPasswordCredentials): firebase.Promise<FirebaseAuthState> {
return this._authBackend.createUser(credentials);
}
/**
* Merges the config object that is passed in with the configuration
* provided through DI. Giving precendence to the one that was passed.
*/
private _mergeConfigs(config: AuthConfiguration): AuthConfiguration {
if (this._config == null)
return config;
return Object.assign({}, this._config, config);
}
private _reject(msg: string): firebase.Promise<FirebaseAuthState> {
return (<Promise<FirebaseAuthState>>new Promise((res, rej) => {
return rej(msg);
}));
}
private _scrubConfig(config: AuthConfiguration, scrubProvider = true): any {
let scrubbed = Object.assign({}, config);
if (scrubProvider) {
delete scrubbed.provider;
}
delete scrubbed.method;
return scrubbed;
}
private _emitAuthData(authData: FirebaseAuthState): void {
if (authData == null) {
this.next(null);
} else {
if (authData.auth && authData.auth.providerData && authData.auth.providerData[0]) {
let providerId = authData.auth.providerData[0].providerId;
let providerCredential = this._credentialCache[providerId];
if (providerCredential) {
authData = attachCredentialToAuthState(authData, providerCredential, providerId);
}
}
this.next(authData);
}
}
}
function attachCredentialToAuthState (authState: FirebaseAuthState, credential, providerId: string): FirebaseAuthState {
if (!authState) return authState;
// TODO make authState immutable
authState[stripProviderId(providerId)] = credential;
return authState;
}
// TODO: Deprecate
export class FirebaseAuth extends AngularFireAuth {}