diff options
Diffstat (limited to 'services/fxaccounts/FxAccountsOAuthClient.jsm')
-rw-r--r-- | services/fxaccounts/FxAccountsOAuthClient.jsm | 269 |
1 files changed, 0 insertions, 269 deletions
diff --git a/services/fxaccounts/FxAccountsOAuthClient.jsm b/services/fxaccounts/FxAccountsOAuthClient.jsm deleted file mode 100644 index c59f1a8691..0000000000 --- a/services/fxaccounts/FxAccountsOAuthClient.jsm +++ /dev/null @@ -1,269 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Firefox Accounts OAuth browser login helper. - * Uses the WebChannel component to receive OAuth messages and complete login flows. - */ - -this.EXPORTED_SYMBOLS = ["FxAccountsOAuthClient"]; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Log.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/FxAccountsCommon.js"); -XPCOMUtils.defineLazyModuleGetter(this, "WebChannel", - "resource://gre/modules/WebChannel.jsm"); -Cu.importGlobalProperties(["URL"]); - -/** - * Create a new FxAccountsOAuthClient for browser some service. - * - * @param {Object} options Options - * @param {Object} options.parameters - * Opaque alphanumeric token to be included in verification links - * @param {String} options.parameters.client_id - * OAuth id returned from client registration - * @param {String} options.parameters.state - * A value that will be returned to the client as-is upon redirection - * @param {String} options.parameters.oauth_uri - * The FxA OAuth server uri - * @param {String} options.parameters.content_uri - * The FxA Content server uri - * @param {String} [options.parameters.scope] - * Optional. A colon-separated list of scopes that the user has authorized - * @param {String} [options.parameters.action] - * Optional. If provided, should be either signup, signin or force_auth. - * @param {String} [options.parameters.email] - * Optional. Required if options.paramters.action is 'force_auth'. - * @param {Boolean} [options.parameters.keys] - * Optional. If true then relier-specific encryption keys will be - * available in the second argument to onComplete. - * @param [authorizationEndpoint] {String} - * Optional authorization endpoint for the OAuth server - * @constructor - */ -this.FxAccountsOAuthClient = function(options) { - this._validateOptions(options); - this.parameters = options.parameters; - this._configureChannel(); - - let authorizationEndpoint = options.authorizationEndpoint || "/authorization"; - - try { - this._fxaOAuthStartUrl = new URL(this.parameters.oauth_uri + authorizationEndpoint + "?"); - } catch (e) { - throw new Error("Invalid OAuth Url"); - } - - let params = this._fxaOAuthStartUrl.searchParams; - params.append("client_id", this.parameters.client_id); - params.append("state", this.parameters.state); - params.append("scope", this.parameters.scope || ""); - params.append("action", this.parameters.action || "signin"); - params.append("webChannelId", this._webChannelId); - if (this.parameters.keys) { - params.append("keys", "true"); - } - // Only append if we actually have a value. - if (this.parameters.email) { - params.append("email", this.parameters.email); - } -}; - -this.FxAccountsOAuthClient.prototype = { - /** - * Function that gets called once the OAuth flow is complete. - * The callback will receive an object with code and state properties. - * If the keys parameter was specified and true, the callback will receive - * a second argument with kAr and kBr properties. - */ - onComplete: null, - /** - * Function that gets called if there is an error during the OAuth flow, - * for example due to a state mismatch. - * The callback will receive an Error object as its argument. - */ - onError: null, - /** - * Configuration object that stores all OAuth parameters. - */ - parameters: null, - /** - * WebChannel that is used to communicate with content page. - */ - _channel: null, - /** - * Boolean to indicate if this client has completed an OAuth flow. - */ - _complete: false, - /** - * The url that opens the Firefox Accounts OAuth flow. - */ - _fxaOAuthStartUrl: null, - /** - * WebChannel id. - */ - _webChannelId: null, - /** - * WebChannel origin, used to validate origin of messages. - */ - _webChannelOrigin: null, - /** - * Opens a tab at "this._fxaOAuthStartUrl". - * Registers a WebChannel listener and sets up a callback if needed. - */ - launchWebFlow: function () { - if (!this._channelCallback) { - this._registerChannel(); - } - - if (this._complete) { - throw new Error("This client already completed the OAuth flow"); - } else { - let opener = Services.wm.getMostRecentWindow("navigator:browser").gBrowser; - opener.selectedTab = opener.addTab(this._fxaOAuthStartUrl.href); - } - }, - - /** - * Release all resources that are in use. - */ - tearDown: function() { - this.onComplete = null; - this.onError = null; - this._complete = true; - this._channel.stopListening(); - this._channel = null; - }, - - /** - * Configures WebChannel id and origin - * - * @private - */ - _configureChannel: function() { - this._webChannelId = "oauth_" + this.parameters.client_id; - - // if this.parameters.content_uri is present but not a valid URI, then this will throw an error. - try { - this._webChannelOrigin = Services.io.newURI(this.parameters.content_uri, null, null); - } catch (e) { - throw e; - } - }, - - /** - * Create a new channel with the WebChannelBroker, setup a callback listener - * @private - */ - _registerChannel: function() { - /** - * Processes messages that are called back from the FxAccountsChannel - * - * @param webChannelId {String} - * Command webChannelId - * @param message {Object} - * Command message - * @param sendingContext {Object} - * Channel message event sendingContext - * @private - */ - let listener = function (webChannelId, message, sendingContext) { - if (message) { - let command = message.command; - let data = message.data; - let target = sendingContext && sendingContext.browser; - - switch (command) { - case "oauth_complete": - // validate the returned state and call onComplete or onError - let result = null; - let err = null; - - if (this.parameters.state !== data.state) { - err = new Error("OAuth flow failed. State doesn't match"); - } else if (this.parameters.keys && !data.keys) { - err = new Error("OAuth flow failed. Keys were not returned"); - } else { - result = { - code: data.code, - state: data.state - }; - } - - // if the message asked to close the tab - if (data.closeWindow && target) { - // for e10s reasons the best way is to use the TabBrowser to close the tab. - let tabbrowser = target.getTabBrowser(); - - if (tabbrowser) { - let tab = tabbrowser.getTabForBrowser(target); - - if (tab) { - tabbrowser.removeTab(tab); - log.debug("OAuth flow closed the tab."); - } else { - log.debug("OAuth flow failed to close the tab. Tab not found in TabBrowser."); - } - } else { - log.debug("OAuth flow failed to close the tab. TabBrowser not found."); - } - } - - if (err) { - log.debug(err.message); - if (this.onError) { - this.onError(err); - } - } else { - log.debug("OAuth flow completed."); - if (this.onComplete) { - if (this.parameters.keys) { - this.onComplete(result, data.keys); - } else { - this.onComplete(result); - } - } - } - - // onComplete will be called for this client only once - // calling onComplete again will result in a failure of the OAuth flow - this.tearDown(); - break; - } - } - }; - - this._channelCallback = listener.bind(this); - this._channel = new WebChannel(this._webChannelId, this._webChannelOrigin); - this._channel.listen(this._channelCallback); - log.debug("Channel registered: " + this._webChannelId + " with origin " + this._webChannelOrigin.prePath); - }, - - /** - * Validates the required FxA OAuth parameters - * - * @param options {Object} - * OAuth client options - * @private - */ - _validateOptions: function (options) { - if (!options || !options.parameters) { - throw new Error("Missing 'parameters' configuration option"); - } - - ["oauth_uri", "client_id", "content_uri", "state"].forEach(option => { - if (!options.parameters[option]) { - throw new Error("Missing 'parameters." + option + "' parameter"); - } - }); - - if (options.parameters.action == "force_auth" && !options.parameters.email) { - throw new Error("parameters.email is required for action 'force_auth'"); - } - }, -}; |