diff --git a/b2g/chrome/content/identity.js b/b2g/chrome/content/identity.js index 3d51b2b0544..c8b38abbb84 100644 --- a/b2g/chrome/content/identity.js +++ b/b2g/chrome/content/identity.js @@ -55,6 +55,9 @@ var func = null; * assertion: optional assertion */ function identityCall(message) { + if (options._internal) { + message._internal = options._internal; + } sendAsyncMessage(kIdentityControllerDoMethod, message); } @@ -78,7 +81,7 @@ function doInternalWatch() { log("doInternalWatch:", options, isLoaded); if (options && isLoaded) { let BrowserID = content.wrappedJSObject.BrowserID; - BrowserID.internal.watch(function(aParams) { + BrowserID.internal.watch(function(aParams, aInternalParams) { identityCall(aParams); if (aParams.method === "ready") { closeIdentityDialog(); @@ -86,7 +89,7 @@ function doInternalWatch() { }, JSON.stringify(options), function(...things) { - log("internal: ", things); + log("(watch) internal: ", things); } ); } @@ -97,9 +100,13 @@ function doInternalRequest() { if (options && isLoaded) { content.wrappedJSObject.BrowserID.internal.get( options.origin, - function(assertion) { + function(assertion, internalParams) { + internalParams = internalParams || {}; if (assertion) { - identityCall({method: 'login', assertion: assertion}); + identityCall({ + method: 'login', + assertion: assertion, + _internalParams: internalParams}); } closeIdentityDialog(); }, diff --git a/b2g/components/SignInToWebsite.jsm b/b2g/components/SignInToWebsite.jsm index 8f40065eeb6..1183d3c43e3 100644 --- a/b2g/components/SignInToWebsite.jsm +++ b/b2g/components/SignInToWebsite.jsm @@ -305,7 +305,11 @@ this.SignInToWebsiteController = { break; case "login": - IdentityService.doLogin(aRpId, message.assertion); + if (message._internalParams) { + IdentityService.doLogin(aRpId, message.assertion, message._internalParams); + } else { + IdentityService.doLogin(aRpId, message.assertion); + } break; case "logout": diff --git a/dom/identity/DOMIdentity.jsm b/dom/identity/DOMIdentity.jsm index cffb6866100..e15e0050447 100644 --- a/dom/identity/DOMIdentity.jsm +++ b/dom/identity/DOMIdentity.jsm @@ -99,14 +99,19 @@ function RPWatchContext(aOptions, aTargetMM) { // default for no loggedInUser is undefined, not null this.loggedInUser = aOptions.loggedInUser; + // Maybe internal + this._internal = aOptions._internal; + this._mm = aTargetMM; } RPWatchContext.prototype = { - doLogin: function RPWatchContext_onlogin(aAssertion) { + doLogin: function RPWatchContext_onlogin(aAssertion, aMaybeInternalParams) { log("doLogin: " + this.id); - let message = new IDDOMMessage({id: this.id}); - message.assertion = aAssertion; + let message = new IDDOMMessage({id: this.id, assertion: aAssertion}); + if (aMaybeInternalParams) { + message._internalParams = aMaybeInternalParams; + } this._mm.sendAsyncMessage("Identity:RP:Watch:OnLogin", message); }, diff --git a/dom/identity/nsDOMIdentity.js b/dom/identity/nsDOMIdentity.js index 9477a976200..8c5dd826e5a 100644 --- a/dom/identity/nsDOMIdentity.js +++ b/dom/identity/nsDOMIdentity.js @@ -32,6 +32,8 @@ nsDOMIdentity.prototype = { watch: 'r', request: 'r', logout: 'r', + get: 'r', + getVerifiedEmail: 'r', // Provisioning beginProvisioning: 'r', @@ -51,7 +53,6 @@ nsDOMIdentity.prototype = { */ watch: function nsDOMIdentity_watch(aOptions) { - this._log("watch"); if (this._rpWatcher) { throw new Error("navigator.id.watch was already called"); } @@ -110,8 +111,11 @@ nsDOMIdentity.prototype = { let util = this._window.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDOMWindowUtils); - // Do not allow call of request() outside of a user input handler. - if (!util.isHandlingUserInput) { + // The only time we permit calling of request() outside of a user + // input handler is when we are handling the (deprecated) get() or + // getVerifiedEmail() calls, which make use of an RP context + // marked as _internal. + if (!util.isHandlingUserInput && !aOptions._internal) { return; } @@ -166,6 +170,70 @@ nsDOMIdentity.prototype = { this._identityInternal._mm.sendAsyncMessage("Identity:RP:Logout", message); }, + /* + * Get an assertion. This function is deprecated. RPs are + * encouraged to use the observer API instead (watch + request). + */ + get: function nsDOMIdentity_get(aCallback, aOptions) { + var opts = {}; + aOptions = aOptions || {}; + + // We use the observer API (watch + request) to implement get(). + // Because the caller can call get() and getVerifiedEmail() as + // many times as they want, we lift the restriction that watch() can + // only be called once. + this._rpWatcher = null; + + // This flag tells internal_api.js (in the shim) to record in the + // login parameters whether the assertion was acquired silently or + // with user interaction. + opts._internal = true; + + opts.privacyPolicy = aOptions.privacyPolicy || undefined; + opts.termsOfService = aOptions.termsOfService || undefined; + opts.privacyURL = aOptions.privacyURL || undefined; + opts.tosURL = aOptions.tosURL || undefined; + opts.siteName = aOptions.siteName || undefined; + opts.siteLogo = aOptions.siteLogo || undefined; + + if (checkDeprecated(aOptions, "silent")) { + // Silent has been deprecated, do nothing. Placing the check here + // prevents the callback from being called twice, once with null and + // once after internalWatch has been called. See issue #1532: + // https://github.com/mozilla/browserid/issues/1532 + if (aCallback) { + setTimeout(function() { aCallback(null); }, 0); + } + return; + } + + // Get an assertion by using our observer api: watch + request. + var self = this; + this.watch({ + oncancel: function get_oncancel() { + if (aCallback) { + aCallback(null); + aCallback = null; + } + }, + onlogin: function get_onlogin(assertion, internalParams) { + if (assertion && aCallback && internalParams && !internalParams.silent) { + aCallback(assertion); + aCallback = null; + } + }, + onlogout: function get_onlogout() {}, + onready: function get_onready() { + self.request(opts); + } + }); + }, + + getVerifiedEmail: function nsDOMIdentity_getVerifiedEmail(aCallback) { + Cu.reportError("WARNING: getVerifiedEmail has been deprecated"); + this.get(aCallback, {}); + }, + /** * Identity Provider (IDP) Provisioning APIs */ @@ -324,16 +392,22 @@ nsDOMIdentity.prototype = { case "Identity:RP:Watch:OnLogin": // Do we have a watcher? if (!this._rpWatcher) { + dump("WARNING: Received OnLogin message, but there is no RP watcher\n"); return; } if (this._rpWatcher.onlogin) { - this._rpWatcher.onlogin(msg.assertion); + if (this._rpWatcher._internal) { + this._rpWatcher.onlogin(msg.assertion, msg._internalParams); + } else { + this._rpWatcher.onlogin(msg.assertion); + } } break; case "Identity:RP:Watch:OnLogout": // Do we have a watcher? if (!this._rpWatcher) { + dump("WARNING: Received OnLogout message, but there is no RP watcher\n"); return; } @@ -344,6 +418,7 @@ nsDOMIdentity.prototype = { case "Identity:RP:Watch:OnReady": // Do we have a watcher? if (!this._rpWatcher) { + dump("WARNING: Received OnReady message, but there is no RP watcher\n"); return; } @@ -354,6 +429,7 @@ nsDOMIdentity.prototype = { case "Identity:RP:Request:OnCancel": // Do we have a watcher? if (!this._rpWatcher) { + dump("WARNING: Received OnCancel message, but there is no RP watcher\n"); return; } @@ -432,7 +508,6 @@ nsDOMIdentity.prototype = { // window origin message.origin = this._origin; - dump("nsDOM message: " + JSON.stringify(message) + "\n"); return message; }, diff --git a/toolkit/identity/MinimalIdentity.jsm b/toolkit/identity/MinimalIdentity.jsm index 137dd0bc50b..fc77598161e 100644 --- a/toolkit/identity/MinimalIdentity.jsm +++ b/toolkit/identity/MinimalIdentity.jsm @@ -47,6 +47,9 @@ function makeMessageObject(aRpCaller) { // loggedInUser can be undefined, null, or a string options.loggedInUser = aRpCaller.loggedInUser; + // Special flag for internal calls + options._internal = aRpCaller._internal; + Object.keys(aRpCaller).forEach(function(option) { // Duplicate the callerobject, scrubbing out functions and other // internal variables (like _mm, the message manager object) @@ -63,7 +66,6 @@ function makeMessageObject(aRpCaller) { throw new Error(err); } - dump("message object is: " + JSON.stringify(options) + "\n"); return options; } @@ -128,7 +130,6 @@ IDService.prototype = { */ watch: function watch(aRpCaller) { // store the caller structure and notify the UI observers - dump("RP - watch: " + JSON.stringify(aRpCaller) + "\n"); this._rpFlows[aRpCaller.id] = aRpCaller; let options = makeMessageObject(aRpCaller); @@ -177,14 +178,14 @@ IDService.prototype = { * following functions (doLogin, doLogout, or doReady) */ - doLogin: function doLogin(aRpCallerId, aAssertion) { + doLogin: function doLogin(aRpCallerId, aAssertion, aInternalParams) { let rp = this._rpFlows[aRpCallerId]; if (!rp) { dump("WARNING: doLogin found no rp to go with callerId " + aRpCallerId + "\n"); return; } - rp.doLogin(aAssertion); + rp.doLogin(aAssertion, aInternalParams); }, doLogout: function doLogout(aRpCallerId) {