2017-02-14 11:41:27 +00:00
|
|
|
// @flow
|
|
|
|
import User from './user';
|
2017-06-29 16:24:34 +00:00
|
|
|
import ModuleBase from './../../utils/ModuleBase';
|
2017-09-23 15:14:35 +00:00
|
|
|
import INTERNALS from './../../internals';
|
2017-08-25 11:16:23 +00:00
|
|
|
import ConfirmationResult from './ConfirmationResult';
|
2017-03-17 23:51:26 +00:00
|
|
|
|
|
|
|
// providers
|
2017-09-21 16:42:09 +00:00
|
|
|
import EmailAuthProvider from './providers/EmailAuthProvider';
|
2017-09-24 12:57:59 +00:00
|
|
|
import PhoneAuthProvider from './providers/PhoneAuthProvider';
|
2017-09-21 16:42:09 +00:00
|
|
|
import GoogleAuthProvider from './providers/GoogleAuthProvider';
|
|
|
|
import GithubAuthProvider from './providers/GithubAuthProvider';
|
|
|
|
import TwitterAuthProvider from './providers/TwitterAuthProvider';
|
|
|
|
import FacebookAuthProvider from './providers/FacebookAuthProvider';
|
2017-09-24 12:57:59 +00:00
|
|
|
|
|
|
|
import PhoneAuthListener from './PhoneAuthListener';
|
2017-02-14 11:41:27 +00:00
|
|
|
|
2017-06-29 16:24:34 +00:00
|
|
|
export default class Auth extends ModuleBase {
|
2017-08-17 16:58:28 +00:00
|
|
|
static _NAMESPACE = 'auth';
|
|
|
|
static _NATIVE_MODULE = 'RNFirebaseAuth';
|
|
|
|
|
2017-05-25 22:39:06 +00:00
|
|
|
_user: User | null;
|
2017-09-25 20:29:40 +00:00
|
|
|
_native: Object;
|
|
|
|
_getAppEventName: Function;
|
2017-02-14 11:41:27 +00:00
|
|
|
_authResult: AuthResultType | null;
|
|
|
|
authenticated: boolean;
|
|
|
|
|
2017-06-29 16:24:34 +00:00
|
|
|
constructor(firebaseApp: Object, options: Object = {}) {
|
2017-08-17 16:58:28 +00:00
|
|
|
super(firebaseApp, options, true);
|
2017-02-14 11:41:27 +00:00
|
|
|
this._user = null;
|
|
|
|
this._authResult = null;
|
|
|
|
this.authenticated = false;
|
2017-09-24 12:17:20 +00:00
|
|
|
|
2017-07-12 14:49:33 +00:00
|
|
|
this.addListener(
|
|
|
|
// sub to internal native event - this fans out to
|
2017-09-21 15:48:54 +00:00
|
|
|
// public event name: onAuthStateChanged
|
|
|
|
this._getAppEventName('auth_state_changed'),
|
2017-07-12 14:49:33 +00:00
|
|
|
this._onAuthStateChanged.bind(this),
|
|
|
|
);
|
2017-09-24 12:17:20 +00:00
|
|
|
|
2017-09-25 22:06:13 +00:00
|
|
|
this.addListener(
|
|
|
|
// sub to internal native event - this fans out to
|
|
|
|
// public events based on event.type
|
|
|
|
this._getAppEventName('phone_auth_state_changed'),
|
|
|
|
this._onPhoneAuthStateChanged.bind(this),
|
|
|
|
);
|
|
|
|
|
2017-09-21 15:48:54 +00:00
|
|
|
this.addListener(
|
|
|
|
// sub to internal native event - this fans out to
|
|
|
|
// public event name: onIdTokenChanged
|
|
|
|
this._getAppEventName('auth_id_token_changed'),
|
|
|
|
this._onIdTokenChanged.bind(this),
|
|
|
|
);
|
2017-07-17 19:56:08 +00:00
|
|
|
|
|
|
|
this._native.addAuthStateListener();
|
2017-09-21 15:48:54 +00:00
|
|
|
this._native.addIdTokenListener();
|
2017-02-14 11:41:27 +00:00
|
|
|
}
|
|
|
|
|
2017-09-25 22:06:13 +00:00
|
|
|
/**
|
|
|
|
* Route a phone state change event to the correct listeners
|
|
|
|
* @param event
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
_onPhoneAuthStateChanged(event: Object) {
|
|
|
|
const eventKey = `phone:auth:${event.requestKey}:${event.type}`;
|
|
|
|
this.emit(eventKey, event.state);
|
|
|
|
}
|
|
|
|
|
2017-02-14 11:41:27 +00:00
|
|
|
/**
|
|
|
|
* Internal auth changed listener
|
|
|
|
* @param auth
|
2017-03-13 20:02:44 +00:00
|
|
|
* @param emit
|
2017-02-14 11:41:27 +00:00
|
|
|
* @private
|
|
|
|
*/
|
2017-03-17 23:40:12 +00:00
|
|
|
_onAuthStateChanged(auth: AuthResultType, emit: boolean = true) {
|
2017-02-14 11:41:27 +00:00
|
|
|
this._authResult = auth;
|
|
|
|
this.authenticated = auth ? auth.authenticated || false : false;
|
|
|
|
if (auth && auth.user && !this._user) this._user = new User(this, auth);
|
|
|
|
else if ((!auth || !auth.user) && this._user) this._user = null;
|
|
|
|
else if (this._user) this._user._updateValues(auth);
|
2017-09-21 15:48:54 +00:00
|
|
|
if (emit) this.emit(this._getAppEventName('onAuthStateChanged'), this._user);
|
2017-03-13 20:02:44 +00:00
|
|
|
return auth ? this._user : null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove auth change listener
|
|
|
|
* @param listener
|
|
|
|
*/
|
|
|
|
_offAuthStateChanged(listener: Function) {
|
|
|
|
this.log.info('Removing onAuthStateChanged listener');
|
2017-09-21 15:48:54 +00:00
|
|
|
this.removeListener(this._getAppEventName('onAuthStateChanged'), listener);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal auth changed listener
|
|
|
|
* @param auth
|
|
|
|
* @param emit
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
_onIdTokenChanged(auth: AuthResultType, emit: boolean = true) {
|
|
|
|
this._authResult = auth;
|
|
|
|
this.authenticated = auth ? auth.authenticated || false : false;
|
|
|
|
if (auth && auth.user && !this._user) this._user = new User(this, auth);
|
|
|
|
else if ((!auth || !auth.user) && this._user) this._user = null;
|
|
|
|
else if (this._user) this._user._updateValues(auth);
|
|
|
|
if (emit) this.emit(this._getAppEventName('onIdTokenChanged'), this._user);
|
|
|
|
return auth ? this._user : null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove id token change listener
|
|
|
|
* @param listener
|
|
|
|
*/
|
|
|
|
_offIdTokenChanged(listener: Function) {
|
|
|
|
this.log.info('Removing onIdTokenChanged listener');
|
|
|
|
this.removeListener(this._getAppEventName('onIdTokenChanged'), listener);
|
2017-03-13 20:02:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Intercept all user actions and send their results to
|
|
|
|
* auth state change before resolving
|
|
|
|
* @param promise
|
2017-09-25 22:06:13 +00:00
|
|
|
* @returns {Promise.<*>}
|
2017-03-13 20:02:44 +00:00
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
_interceptUserValue(promise) {
|
|
|
|
return promise.then((result) => {
|
|
|
|
if (!result) return this._onAuthStateChanged(null, false);
|
|
|
|
if (result.user) return this._onAuthStateChanged(result, false);
|
2017-03-17 23:40:12 +00:00
|
|
|
if (result.uid) return this._onAuthStateChanged({ authenticated: true, user: result }, false);
|
2017-03-13 20:02:44 +00:00
|
|
|
return result;
|
|
|
|
});
|
2017-02-14 11:41:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* WEB API
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Listen for auth changes.
|
|
|
|
* @param listener
|
|
|
|
*/
|
|
|
|
onAuthStateChanged(listener: Function) {
|
|
|
|
this.log.info('Creating onAuthStateChanged listener');
|
2017-09-21 15:48:54 +00:00
|
|
|
this.on(this._getAppEventName('onAuthStateChanged'), listener);
|
2017-06-13 01:09:12 +00:00
|
|
|
if (this._authResult) listener(this._user || null);
|
2017-02-14 11:41:27 +00:00
|
|
|
return this._offAuthStateChanged.bind(this, listener);
|
|
|
|
}
|
|
|
|
|
2017-09-21 15:48:54 +00:00
|
|
|
/**
|
|
|
|
* Listen for id token changes.
|
|
|
|
* @param listener
|
|
|
|
*/
|
|
|
|
onIdTokenChanged(listener: Function) {
|
|
|
|
this.log.info('Creating onIdTokenChanged listener');
|
|
|
|
this.on(this._getAppEventName('onIdTokenChanged'), listener);
|
|
|
|
if (this._authResult) listener(this._user || null);
|
|
|
|
return this._offIdTokenChanged.bind(this, listener);
|
|
|
|
}
|
|
|
|
|
2017-02-14 11:41:27 +00:00
|
|
|
/**
|
2017-03-13 20:02:44 +00:00
|
|
|
* Sign the current user out
|
|
|
|
* @return {Promise}
|
2017-02-14 11:41:27 +00:00
|
|
|
*/
|
2017-03-13 20:02:44 +00:00
|
|
|
signOut(): Promise<null> {
|
2017-06-30 16:23:32 +00:00
|
|
|
return this._interceptUserValue(this._native.signOut());
|
2017-02-14 11:41:27 +00:00
|
|
|
}
|
|
|
|
|
2017-03-13 17:23:41 +00:00
|
|
|
/**
|
|
|
|
* Sign a user in anonymously
|
2017-03-13 20:02:44 +00:00
|
|
|
* @return {Promise} A promise resolved upon completion
|
2017-03-13 17:23:41 +00:00
|
|
|
*/
|
|
|
|
signInAnonymously(): Promise<Object> {
|
2017-06-30 16:23:32 +00:00
|
|
|
return this._interceptUserValue(this._native.signInAnonymously());
|
2017-03-13 17:23:41 +00:00
|
|
|
}
|
|
|
|
|
2017-02-14 11:41:27 +00:00
|
|
|
/**
|
|
|
|
* Create a user with the email/password functionality
|
|
|
|
* @param {string} email The user's email
|
|
|
|
* @param {string} password The user's password
|
|
|
|
* @return {Promise} A promise indicating the completion
|
|
|
|
*/
|
|
|
|
createUserWithEmailAndPassword(email: string, password: string): Promise<Object> {
|
2017-06-30 16:23:32 +00:00
|
|
|
return this._interceptUserValue(this._native.createUserWithEmailAndPassword(email, password));
|
2017-02-14 11:41:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sign a user in with email/password
|
|
|
|
* @param {string} email The user's email
|
|
|
|
* @param {string} password The user's password
|
|
|
|
* @return {Promise} A promise that is resolved upon completion
|
|
|
|
*/
|
|
|
|
signInWithEmailAndPassword(email: string, password: string): Promise<Object> {
|
2017-06-30 16:23:32 +00:00
|
|
|
return this._interceptUserValue(this._native.signInWithEmailAndPassword(email, password));
|
2017-02-14 11:41:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sign the user in with a custom auth token
|
|
|
|
* @param {string} customToken A self-signed custom auth token.
|
|
|
|
* @return {Promise} A promise resolved upon completion
|
|
|
|
*/
|
|
|
|
signInWithCustomToken(customToken: string): Promise<Object> {
|
2017-06-30 16:23:32 +00:00
|
|
|
return this._interceptUserValue(this._native.signInWithCustomToken(customToken));
|
2017-02-14 11:41:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sign the user in with a third-party authentication provider
|
|
|
|
* @return {Promise} A promise resolved upon completion
|
|
|
|
*/
|
|
|
|
signInWithCredential(credential: CredentialType): Promise<Object> {
|
2017-08-19 04:22:07 +00:00
|
|
|
return this._interceptUserValue(
|
|
|
|
this._native.signInWithCredential(
|
2017-09-21 16:42:09 +00:00
|
|
|
credential.providerId, credential.token, credential.secret,
|
2017-08-19 04:22:07 +00:00
|
|
|
),
|
|
|
|
);
|
2017-02-14 11:41:27 +00:00
|
|
|
}
|
|
|
|
|
2017-08-25 11:16:23 +00:00
|
|
|
/**
|
|
|
|
* Asynchronously signs in using a phone number.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
signInWithPhoneNumber(phoneNumber: string): Promise<Object> {
|
|
|
|
return this._native.signInWithPhoneNumber(phoneNumber).then((result) => {
|
|
|
|
return new ConfirmationResult(this, result.verificationId);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-09-24 12:57:59 +00:00
|
|
|
/**
|
|
|
|
* Returns a PhoneAuthListener to listen to phone verification events,
|
|
|
|
* on the final completion event a PhoneAuthCredential can be generated for
|
|
|
|
* authentication purposes.
|
|
|
|
*
|
|
|
|
* @param phoneNumber
|
|
|
|
* @param autoVerifyTimeout Android Only
|
|
|
|
* @returns {PhoneAuthListener}
|
|
|
|
*/
|
|
|
|
verifyPhoneNumber(phoneNumber: string, autoVerifyTimeout?: number): PhoneAuthListener {
|
|
|
|
return new PhoneAuthListener(this, phoneNumber, autoVerifyTimeout);
|
|
|
|
}
|
|
|
|
|
2017-02-14 11:41:27 +00:00
|
|
|
/**
|
|
|
|
* Send reset password instructions via email
|
|
|
|
* @param {string} email The email to send password reset instructions
|
|
|
|
*/
|
|
|
|
sendPasswordResetEmail(email: string): Promise<Object> {
|
2017-06-30 16:23:32 +00:00
|
|
|
return this._native.sendPasswordResetEmail(email);
|
2017-02-14 11:41:27 +00:00
|
|
|
}
|
|
|
|
|
2017-07-04 17:22:18 +00:00
|
|
|
/**
|
|
|
|
* Completes the password reset process, given a confirmation code and new password.
|
|
|
|
*
|
|
|
|
* @link https://firebase.google.com/docs/reference/js/firebase.auth.Auth#confirmPasswordReset
|
|
|
|
* @param code
|
|
|
|
* @param newPassword
|
|
|
|
* @return {Promise.<Null>}
|
|
|
|
*/
|
2017-09-25 20:29:40 +00:00
|
|
|
confirmPasswordReset(code: string, newPassword: string): Promise<null> {
|
2017-09-24 12:17:20 +00:00
|
|
|
return this._native.confirmPasswordReset(code, newPassword);
|
2017-07-04 17:22:18 +00:00
|
|
|
}
|
|
|
|
|
2017-07-05 13:16:35 +00:00
|
|
|
/**
|
|
|
|
* Applies a verification code sent to the user by email or other out-of-band mechanism.
|
|
|
|
*
|
|
|
|
* @link https://firebase.google.com/docs/reference/js/firebase.auth.Auth#applyActionCode
|
|
|
|
* @param code
|
|
|
|
* @return {Promise.<Null>}
|
|
|
|
*/
|
2017-09-25 20:29:40 +00:00
|
|
|
applyActionCode(code: string): Promise<any> {
|
2017-09-24 12:17:20 +00:00
|
|
|
return this._native.applyActionCode(code);
|
2017-07-05 13:16:35 +00:00
|
|
|
}
|
|
|
|
|
2017-07-05 13:56:18 +00:00
|
|
|
/**
|
|
|
|
* Checks a verification code sent to the user by email or other out-of-band mechanism.
|
|
|
|
*
|
|
|
|
* @link https://firebase.google.com/docs/reference/js/firebase.auth.Auth#checkActionCode
|
|
|
|
* @param code
|
2017-09-25 20:29:40 +00:00
|
|
|
* @return {Promise.<any>|Promise<ActionCodeInfo>}
|
2017-07-05 13:56:18 +00:00
|
|
|
*/
|
2017-09-25 20:29:40 +00:00
|
|
|
checkActionCode(code: string): Promise<any> {
|
2017-09-24 12:17:20 +00:00
|
|
|
return this._native.checkActionCode(code);
|
2017-07-05 13:56:18 +00:00
|
|
|
}
|
2017-07-04 17:22:18 +00:00
|
|
|
|
2017-02-14 11:41:27 +00:00
|
|
|
/**
|
|
|
|
* Get the currently signed in user
|
|
|
|
* @return {Promise}
|
|
|
|
*/
|
|
|
|
getCurrentUser(): Promise<Object> {
|
2017-06-30 16:23:32 +00:00
|
|
|
return this._interceptUserValue(this._native.getCurrentUser());
|
2017-02-14 11:41:27 +00:00
|
|
|
}
|
|
|
|
|
2017-05-25 13:45:03 +00:00
|
|
|
/**
|
|
|
|
* Returns a list of authentication providers that can be used to sign in a given user (identified by its main email address).
|
|
|
|
* @return {Promise}
|
|
|
|
*/
|
2017-05-25 14:30:39 +00:00
|
|
|
fetchProvidersForEmail(email: string): Promise<Array<String>> {
|
2017-06-30 16:23:32 +00:00
|
|
|
return this._native.fetchProvidersForEmail(email);
|
2017-05-25 13:45:03 +00:00
|
|
|
}
|
|
|
|
|
2017-02-14 11:41:27 +00:00
|
|
|
/**
|
|
|
|
* Get the currently signed in user
|
|
|
|
* @return {Promise}
|
|
|
|
*/
|
2017-05-25 22:39:06 +00:00
|
|
|
get currentUser(): User | null {
|
2017-02-14 11:41:27 +00:00
|
|
|
return this._user;
|
|
|
|
}
|
|
|
|
|
|
|
|
get namespace(): string {
|
|
|
|
return 'firebase:auth';
|
|
|
|
}
|
2017-09-23 15:14:35 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* KNOWN UNSUPPORTED METHODS
|
|
|
|
*/
|
|
|
|
|
|
|
|
getRedirectResult() {
|
|
|
|
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD(Auth, 'getRedirectResult'));
|
|
|
|
}
|
|
|
|
|
|
|
|
setPersistence() {
|
|
|
|
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD(Auth, 'setPersistence'));
|
|
|
|
}
|
|
|
|
|
|
|
|
signInAndRetrieveDataWithCredential() {
|
|
|
|
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD(Auth, 'signInAndRetrieveDataWithCredential'));
|
|
|
|
}
|
|
|
|
|
|
|
|
signInWithPopup() {
|
|
|
|
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD(Auth, 'signInWithPopup'));
|
|
|
|
}
|
|
|
|
|
|
|
|
signInWithRedirect() {
|
|
|
|
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD(Auth, 'signInWithRedirect'));
|
|
|
|
}
|
2017-02-14 11:41:27 +00:00
|
|
|
}
|
2017-03-27 18:11:26 +00:00
|
|
|
|
|
|
|
export const statics = {
|
|
|
|
EmailAuthProvider,
|
2017-08-12 18:07:51 +00:00
|
|
|
PhoneAuthProvider,
|
|
|
|
GoogleAuthProvider,
|
2017-03-27 18:11:26 +00:00
|
|
|
GithubAuthProvider,
|
2017-08-12 18:07:51 +00:00
|
|
|
TwitterAuthProvider,
|
|
|
|
FacebookAuthProvider,
|
2017-09-24 12:57:59 +00:00
|
|
|
PhoneAuthState: {
|
2017-09-24 12:17:20 +00:00
|
|
|
CODE_SENT: 'sent',
|
|
|
|
AUTO_VERIFY_TIMEOUT: 'timeout',
|
2017-09-24 12:57:59 +00:00
|
|
|
AUTO_VERIFIED: 'verified',
|
2017-09-24 12:17:20 +00:00
|
|
|
ERROR: 'error',
|
|
|
|
},
|
2017-03-27 18:11:26 +00:00
|
|
|
};
|