Skip to content

Commit

Permalink
Add a way to specify emulator host/port for Auth
Browse files Browse the repository at this point in the history
  • Loading branch information
avolkovi committed Sep 18, 2020
1 parent 0986b92 commit 3fdce5d
Show file tree
Hide file tree
Showing 13 changed files with 635 additions and 40 deletions.
2 changes: 1 addition & 1 deletion packages/auth/buildtools/run_demo.sh
Expand Up @@ -34,4 +34,4 @@ cp ../firebase/firebase-auth.js demo/public/dist/firebase-auth.js
cp ../firebase/firebase-database.js demo/public/dist/firebase-database.js
# Serve demo app.
cd demo
`yarn bin`/firebase serve --only hosting,functions
`yarn bin`/firebase emulators:start
102 changes: 98 additions & 4 deletions packages/auth/src/auth.js
Expand Up @@ -184,6 +184,12 @@ fireauth.Auth = function(app) {
* is currently only used to log FirebaseUI.
*/
this.frameworks_ = [];

/**
* @private {?fireauth.constants.EmulatorSettings} The current
* emulator settings.
*/
this.emulatorConfig_ = null;
};
goog.inherits(fireauth.Auth, goog.events.EventTarget);

Expand All @@ -202,6 +208,20 @@ fireauth.Auth.LanguageCodeChangeEvent = function(languageCode) {
goog.inherits(fireauth.Auth.LanguageCodeChangeEvent, goog.events.Event);


/**
* Emulator config change custom event.
* @param {?fireauth.constants.EmulatorSettings} emulatorConfig The new
* emulator settings.
* @constructor
* @extends {goog.events.Event}
*/
fireauth.Auth.EmulatorConfigChangeEvent = function(emulatorConfig) {
goog.events.Event.call(this, fireauth.constants.AuthEventType.EMULATOR_CONFIG_CHANGED);
this.emulatorConfig = emulatorConfig;
};
goog.inherits(fireauth.Auth.EmulatorConfigChangeEvent, goog.events.Event);


/**
* Framework change custom event.
* @param {!Array<string>} frameworks The new frameworks array.
Expand Down Expand Up @@ -272,6 +292,34 @@ fireauth.Auth.prototype.useDeviceLanguage = function() {
};


/**
* Sets the emulator configuration (go/firebase-emulator-connection-api).
* @param {string} hostname The hostname for the Auth emulator.
* @param {number} port The port for the Auth emulator.
*/
fireauth.Auth.prototype.useEmulator = function(hostname, port) {
// Don't do anything if no change detected.
if (!this.emulatorConfig_ ||
hostname !== this.emulatorConfig_.hostname ||
port !== this.emulatorConfig_.port) {
this.emulatorConfig_ = { hostname: hostname, port: port };
// Disable app verification.
this.settings_().setAppVerificationDisabledForTesting(true);
// Update custom Firebase locale field.
this.rpcHandler_.updateEmulatorConfig(this.emulatorConfig_);
// Notify external language code change listeners.
this.notifyEmulatorConfigListeners_();
}
}

/**
* @return {?fireauth.constants.EmulatorSettings}
*/
fireauth.Auth.prototype.getEmulatorConfig = function () {
return this.emulatorConfig_;
}


/**
* @param {string} frameworkId The framework identifier.
*/
Expand Down Expand Up @@ -396,7 +444,15 @@ fireauth.Auth.prototype.notifyLanguageCodeListeners_ = function() {
};



/**
* Notifies all external listeners of the emulator config change.
* @private
*/
fireauth.Auth.prototype.notifyEmulatorConfigListeners_ = function() {
// Notify external listeners on the language code change.
this.dispatchEvent(
new fireauth.Auth.EmulatorConfigChangeEvent(this.emulatorConfig_));
}


/**
Expand Down Expand Up @@ -449,7 +505,10 @@ fireauth.Auth.prototype.initAuthEventManager_ = function() {
// By this time currentUser should be ready if available and will be able
// to resolve linkWithRedirect if detected.
self.authEventManager_ = fireauth.AuthEventManager.getManager(
authDomain, apiKey, self.app_().name);
authDomain,
apiKey,
self.app_().name,
self.emulatorConfig_);
// Subscribe Auth instance.
self.authEventManager_.subscribe(self);
// Subscribe current user by enabling popup and redirect on that user.
Expand All @@ -471,7 +530,10 @@ fireauth.Auth.prototype.initAuthEventManager_ = function() {
/** @type {!fireauth.AuthUser} */ (self.redirectUser_));
// Set the user Firebase frameworks for the redirect user.
self.setUserFramework_(
/** @type {!fireauth.AuthUser} */ (self.redirectUser_));
/** @type {!fireauth.AuthUser} */(self.redirectUser_));
// Set the user Emulator configuration for the redirect user.
self.setUserEmulatorConfig_(
/** @type {!fireauth.AuthUser} */(self.redirectUser_));
// Reference to redirect user no longer needed.
self.redirectUser_ = null;
}
Expand Down Expand Up @@ -650,7 +712,8 @@ fireauth.Auth.prototype.signInWithPopup = function(provider) {
firebase.SDK_VERSION || null,
null,
null,
this.getTenantId());
this.getTenantId(),
this.emulatorConfig_);
}
// The popup must have a name, otherwise when successive popups are triggered
// they will all render in the same instance and none will succeed since the
Expand Down Expand Up @@ -856,6 +919,7 @@ fireauth.Auth.prototype.signInWithIdTokenResponse =
options['apiKey'] = self.app_().options['apiKey'];
options['authDomain'] = self.app_().options['authDomain'];
options['appName'] = self.app_().name;
options['emulatorConfig'] = self.emulatorConfig_;
// Wait for state to be ready.
// This is used internally and is also used for redirect sign in so there is
// no need for waiting for redirect result to resolve since redirect result
Expand Down Expand Up @@ -911,6 +975,9 @@ fireauth.Auth.prototype.setCurrentUser_ = function(user) {
// Set the current frameworks used on the user and set current Auth instance
// as the framework change dispatcher.
this.setUserFramework_(user);
// If a user is available, set the emulator config on it and set current
// Auth instance as emulator config change dispatcher.
this.setUserEmulatorConfig_(user);
}
};

Expand Down Expand Up @@ -1179,6 +1246,22 @@ fireauth.Auth.prototype.setUserLanguage_ = function(user) {
};


/**
* Updates the emulator config on the provided user and configures the user
* to listen to the Auth instance for any emulator config changes.
* @param {!fireauth.AuthUser} user The user to whose emulator config needs
* to be set.
* @private
*/
fireauth.Auth.prototype.setUserEmulatorConfig_ = function(user) {
// Sets the current emulator config on the user.
user.setEmulatorConfig(this.emulatorConfig_);
// Sets current Auth instance as emulator config change dispatcher on the
// user.
user.setEmulatorConfigChangeDispatcher(this);
}


/**
* Handles user state changes.
* @param {!fireauth.AuthUser} user The user which triggered the state changes.
Expand Down Expand Up @@ -1679,6 +1762,17 @@ fireauth.Auth.prototype.app_ = function() {
};



/**
* @return {!fireauth.AuthSettings} The AuthSettings object this auth object
* is connected to.
* @private
*/
fireauth.Auth.prototype.settings_ = function() {
return this['settings'];
}


/**
* @return {!fireauth.RpcHandler} The RPC handler.
*/
Expand Down
50 changes: 38 additions & 12 deletions packages/auth/src/autheventmanager.js
Expand Up @@ -47,9 +47,11 @@ goog.require('goog.array');
* @param {string} apiKey The API key for sending backend Auth requests.
* @param {string} appName The App ID for the Auth instance that triggered this
* request.
* @param {?fireauth.constants.EmulatorSettings=} emulatorConfig The emulator
* configuration.
* @constructor
*/
fireauth.AuthEventManager = function(authDomain, apiKey, appName) {
fireauth.AuthEventManager = function(authDomain, apiKey, appName, emulatorConfig) {
/**
* @private {!Object<string, boolean>} The map of processed auth event IDs.
*/
Expand All @@ -62,6 +64,8 @@ fireauth.AuthEventManager = function(authDomain, apiKey, appName) {
this.apiKey_ = apiKey;
/** @private {string} The App name. */
this.appName_ = appName;
/** @private @const {?fireauth.constants.EmulatorSettings|undefined} The emulator config. */
this.emulatorConfig_ = emulatorConfig;
/**
* @private {!Array<!fireauth.AuthEventHandler>} List of subscribed handlers.
*/
Expand Down Expand Up @@ -111,9 +115,12 @@ fireauth.AuthEventManager = function(authDomain, apiKey, appName) {
*/
this.oauthSignInHandler_ =
fireauth.AuthEventManager.instantiateOAuthSignInHandler(
this.authDomain_, this.apiKey_, this.appName_,
firebase.SDK_VERSION || null,
fireauth.constants.clientEndpoint);
this.authDomain_,
this.apiKey_,
this.appName_,
firebase.SDK_VERSION || null,
fireauth.constants.clientEndpoint,
this.emulatorConfig_);
};


Expand Down Expand Up @@ -149,22 +156,35 @@ fireauth.AuthEventManager.prototype.getPopupAuthEventProcessor = function() {
* request.
* @param {?string} version The SDK client version.
* @param {?string=} opt_endpointId The endpoint ID (staging, test Gaia, etc).
* @param {?fireauth.constants.EmulatorSettings=} emulatorConfig The emulator
* configuration.
* @return {!fireauth.OAuthSignInHandler} The OAuth sign in handler depending
* on the current environment.
*/
fireauth.AuthEventManager.instantiateOAuthSignInHandler =
function(authDomain, apiKey, appName, version, opt_endpointId) {
function(authDomain, apiKey, appName, version, opt_endpointId, emulatorConfig) {
// This assumes that android/iOS file environment must be a Cordova
// environment which is not true. This is the best way currently available
// to instantiate this synchronously without waiting for checkIfCordova to
// resolve. If it is determined that the Cordova was falsely detected, it will
// be caught via actionable public popup and redirect methods.
return fireauth.util.isAndroidOrIosCordovaScheme() ?
new fireauth.CordovaHandler(
authDomain, apiKey, appName, version, undefined, undefined,
opt_endpointId) :
authDomain,
apiKey,
appName,
version,
undefined,
undefined,
opt_endpointId,
emulatorConfig) :
new fireauth.iframeclient.IfcHandler(
authDomain, apiKey, appName, version, opt_endpointId);
authDomain,
apiKey,
appName,
version,
opt_endpointId,
emulatorConfig);
};


Expand All @@ -179,8 +199,12 @@ fireauth.AuthEventManager.prototype.reset = function() {

this.oauthSignInHandler_ =
fireauth.AuthEventManager.instantiateOAuthSignInHandler(
this.authDomain_, this.apiKey_, this.appName_,
firebase.SDK_VERSION || null);
this.authDomain_,
this.apiKey_,
this.appName_,
firebase.SDK_VERSION || null,
null,
this.emulatorConfig_);
this.processedEvents_ = {};
};

Expand Down Expand Up @@ -662,14 +686,16 @@ fireauth.AuthEventManager.getKey_ = function(apiKey, appName) {
* @param {string} apiKey The API key for sending backend Auth requests.
* @param {string} appName The Auth instance that initiated the Auth event
* manager.
* @param {?fireauth.constants.EmulatorSettings=} emulatorConfig The emulator
* configuration.
* @return {!fireauth.AuthEventManager} the requested manager instance.
*/
fireauth.AuthEventManager.getManager = function(authDomain, apiKey, appName) {
fireauth.AuthEventManager.getManager = function(authDomain, apiKey, appName, emulatorConfig) {
// Construct storage key.
var key = fireauth.AuthEventManager.getKey_(apiKey, appName);
if (!fireauth.AuthEventManager.manager_[key]) {
fireauth.AuthEventManager.manager_[key] =
new fireauth.AuthEventManager(authDomain, apiKey, appName);
new fireauth.AuthEventManager(authDomain, apiKey, appName, emulatorConfig);
}
return fireauth.AuthEventManager.manager_[key];
};
Expand Down
61 changes: 59 additions & 2 deletions packages/auth/src/authuser.js
Expand Up @@ -182,7 +182,10 @@ fireauth.AuthUser =
this.apiKey_,
// Get the client Auth endpoint used.
fireauth.constants.getEndpointConfig(fireauth.constants.clientEndpoint),
clientFullVersion);
clientFullVersion);
if (appOptions['emulatorConfig']) {
this.rpcHandler_.updateEmulatorConfig(appOptions['emulatorConfig']);
}
// TODO: Consider having AuthUser take a fireauth.StsTokenManager
// instance instead of a token response but make sure lastAccessToken_ also
// initialized at the right time. In this case initializeFromIdTokenResponse
Expand Down Expand Up @@ -249,6 +252,20 @@ fireauth.AuthUser =
*/
this.languageCodeChangeEventDispatcher_ = null;

/**
* @private {function(!goog.events.Event)} The on emulator config changed
* event handler.
*/
this.onEmulatorConfigChanged_ = function (event) {
// Update the emulator config.
self.setEmulatorConfig(event.emulatorConfig);
};
/**
* @private {?goog.events.EventTarget} The emulator code change event
* dispatcher.
*/
this.emulatorConfigChangeEventDispatcher_ = null;

/** @private {!Array<string>} The current Firebase frameworks. */
this.frameworks_ = [];
/**
Expand Down Expand Up @@ -288,6 +305,17 @@ fireauth.AuthUser.prototype.setLanguageCode = function(languageCode) {
};


/**
* Updates the emulator config.
* @param {?fireauth.constants.EmulatorSettings} emulatorConfig The current
* emulator config to use in user requests.
*/
fireauth.AuthUser.prototype.setEmulatorConfig = function(emulatorConfig) {
// Update the emulator config.
this.rpcHandler_.updateEmulatorConfig(emulatorConfig);
};


/** @return {?string} The current user's language code. */
fireauth.AuthUser.prototype.getLanguageCode = function() {
return this.languageCode_;
Expand Down Expand Up @@ -322,6 +350,32 @@ fireauth.AuthUser.prototype.setLanguageCodeChangeDispatcher =
};


/**
* Listens to emulator config changes triggered by the provided dispatcher.
* @param {?goog.events.EventTarget} dispatcher The emulator config changed
* event dispatcher.
*/
fireauth.AuthUser.prototype.setEmulatorConfigChangeDispatcher = function(dispatcher) {
// Remove any previous listener.
if (this.emulatorConfigChangeEventDispatcher_) {
goog.events.unlisten(
this.emulatorConfigChangeEventDispatcher_,
fireauth.constants.AuthEventType.EMULATOR_CONFIG_CHANGED,
this.onEmulatorConfigChanged_);
}
// Update current dispatcher.
this.emulatorConfigChangeEventDispatcher_ = dispatcher;
// Using an event listener makes it easy for non-currentUsers to detect
// emulator changes on the parent Auth instance. A developer could still
// call APIs that require localization on signed out user references.
if (dispatcher) {
goog.events.listen(
dispatcher, fireauth.constants.AuthEventType.EMULATOR_CONFIG_CHANGED,
this.onEmulatorConfigChanged_);
}
}


/**
* Updates the Firebase frameworks on the current user.
* @param {!Array<string>} framework The list of Firebase frameworks.
Expand Down Expand Up @@ -1043,7 +1097,8 @@ fireauth.AuthUser.prototype.notifyUserInvalidatedListeners_ = function() {
* @return {!goog.Promise<undefined>}
* @private
*/
fireauth.AuthUser.prototype.setUserAccountInfoFromToken_ = function(idToken) {
fireauth.AuthUser.prototype.setUserAccountInfoFromToken_ = function (idToken) {
debugger
return this.rpcHandler_.getAccountInfoByIdToken(idToken)
.then(goog.bind(this.parseAccountInfo_, this));
};
Expand Down Expand Up @@ -2176,6 +2231,8 @@ fireauth.AuthUser.prototype.destroy = function() {
}
// Stop listening to language code changes.
this.setLanguageCodeChangeDispatcher(null);
// Stop listening to emulator config changes.
this.setEmulatorConfigChangeDispatcher(null);
// Stop listening to framework changes.
this.setFrameworkChangeDispatcher(null);
// Empty pending promises array.
Expand Down

0 comments on commit 3fdce5d

Please sign in to comment.