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 73e0e47
Show file tree
Hide file tree
Showing 8 changed files with 449 additions and 5 deletions.
83 changes: 80 additions & 3 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,32 @@ 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 };
// 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 +442,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 @@ -471,7 +525,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 +707,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 @@ -911,6 +969,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 +1240,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
53 changes: 53 additions & 0 deletions packages/auth/src/authuser.js
Expand Up @@ -249,6 +249,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 +302,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 +347,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 @@ -2176,6 +2227,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
15 changes: 15 additions & 0 deletions packages/auth/src/defines.js
Expand Up @@ -39,6 +39,8 @@ fireauth.constants.OperationType = {
* @enum {string}
*/
fireauth.constants.AuthEventType = {
/** Dispatched when emulator config is changed. */
EMULATOR_CONFIG_CHANGED: 'emulatorConfigChanged',
/** Dispatched when Firebase framework is changed. */
FRAMEWORK_CHANGED: 'frameworkChanged',
/** Dispatched when language code is changed. */
Expand Down Expand Up @@ -166,3 +168,16 @@ fireauth.constants.SAML_PREFIX = 'saml.';

/** @const {string} The required OIDC provider ID prefix. */
fireauth.constants.OIDC_PREFIX = 'oidc.';

/**
* The settings of an Auth emulator. The fields are:
* <ul>
* <li>hostname: defines the hostname where the emulator is running.</li>
* <li>port: defines the port where the emulator is running.</li>
* </ul>
* @typedef {{
* hostname: string,
* port: number
* }}
*/
fireauth.constants.EmulatorSettings;
7 changes: 7 additions & 0 deletions packages/auth/src/exports_auth.js
Expand Up @@ -197,6 +197,13 @@ fireauth.exportlib.exportPrototypeMethods(
name: 'useDeviceLanguage',
args: []
},
useEmulator: {
name: 'useEmulator',
args: [
fireauth.args.string('hostname'),
fireauth.args.number('port')
]
},
verifyPasswordResetCode: {
name: 'verifyPasswordResetCode',
args: [fireauth.args.string('code')]
Expand Down
47 changes: 45 additions & 2 deletions packages/auth/src/rpchandler.js
Expand Up @@ -26,6 +26,7 @@ goog.provide('fireauth.XmlHttpFactory');
goog.require('fireauth.AuthError');
goog.require('fireauth.AuthErrorWithCredential');
goog.require('fireauth.authenum.Error');
goog.require('fireauth.constants');
goog.require('fireauth.idp');
goog.require('fireauth.idp.ProviderId');
goog.require('fireauth.object');
Expand Down Expand Up @@ -110,10 +111,10 @@ fireauth.RpcHandler = function(apiKey, opt_config, opt_firebaseClientVersion) {
this.secureTokenHeaders_ = goog.object.clone(
config['secureTokenHeaders'] ||
fireauth.RpcHandler.DEFAULT_SECURE_TOKEN_HEADERS_);
/** @private @const {string} The Firebase Auth endpoint. */
/** @private {string} The Firebase Auth endpoint. */
this.firebaseEndpoint_ = config['firebaseEndpoint'] ||
fireauth.RpcHandler.FIREBASE_ENDPOINT_;
/** @private @const {string} The identity platform endpoint. */
/** @private {string} The identity platform endpoint. */
this.identityPlatformEndpoint_ = config['identityPlatformEndpoint'] ||
fireauth.RpcHandler.IDENTITY_PLATFORM_ENDPOINT_;
/**
Expand Down Expand Up @@ -435,6 +436,48 @@ fireauth.RpcHandler.prototype.updateCustomLocaleHeader =
};


/**
* Updates the emulator configuration.
* @param {?fireauth.constants.EmulatorSettings} emulatorConfig The new
* emulator config.
*/
fireauth.RpcHandler.prototype.updateEmulatorConfig = function(emulatorConfig) {
if (!emulatorConfig) {
return;
}
// If an emulator config is provided, update the endpoints.
this.secureTokenEndpoint_ =
fireauth.RpcHandler.generateEmululatorEndpointUrl_(
fireauth.RpcHandler.SECURE_TOKEN_ENDPOINT_, emulatorConfig);
this.firebaseEndpoint_ =
fireauth.RpcHandler.generateEmululatorEndpointUrl_(
fireauth.RpcHandler.FIREBASE_ENDPOINT_, emulatorConfig);
this.identityPlatformEndpoint_ =
fireauth.RpcHandler.generateEmululatorEndpointUrl_(
fireauth.RpcHandler.IDENTITY_PLATFORM_ENDPOINT_, emulatorConfig);
}


/**
* Creates an endpoint URL intended for use by the emulator.
*
* According to go/firebase-auth-emulator-dd
* @param {string} endpoint the production endpoint URL.
* @param {?fireauth.constants.EmulatorSettings} emulatorConfig The emulator
* config.
* @return {string} The emulator endpoint URL.
* @private
*/
fireauth.RpcHandler.generateEmululatorEndpointUrl_ = function(endpoint, emulatorConfig) {
const uri = goog.Uri.parse(endpoint);
uri.setScheme("http");
uri.setPath(uri.getDomain() + uri.getPath());
uri.setDomain(emulatorConfig.hostname);
uri.setPort(emulatorConfig.port);
return uri.toString();
}


/**
* Updates the X-Client-Version in the header.
* @param {?string} clientVersion The new client version.
Expand Down

0 comments on commit 73e0e47

Please sign in to comment.