author | Jed Parsons <jparsons@mozilla.com> |
Tue, 20 Nov 2012 20:28:34 -0500 | |
changeset 113852 | 0b37a6293086382db3ad3e95e0cb4b8d3380c471 |
parent 113851 | 71f90d16059d7fb67aad1d992c7857614d528e58 |
child 113853 | 0f76932d28c58881dd87455b031b71e90770c7b1 |
push id | 23891 |
push user | emorley@mozilla.com |
push date | Wed, 21 Nov 2012 15:30:36 +0000 |
treeherder | mozilla-central@905492e644e3 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | benadida |
bugs | 790141 |
milestone | 20.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/b2g/chrome/content/identity.js +++ b/b2g/chrome/content/identity.js @@ -50,16 +50,19 @@ var func = null; /* * Message back to the SignInToWebsite pipe. Message should be an * object with the following keys: * * method: one of 'login', 'logout', 'ready' * assertion: optional assertion */ function identityCall(message) { + if (options._internal) { + message._internal = options._internal; + } sendAsyncMessage(kIdentityControllerDoMethod, message); } /* * To close the dialog, we first tell the gecko SignInToWebsite manager that it * can clean up. Then we tell the gaia component that we are finished. It is * necessary to notify gecko first, so that the message can be sent before gaia * destroys our context. @@ -73,38 +76,42 @@ function closeIdentityDialog() { /* * doInternalWatch - call the internal.watch api and relay the results * up to the controller. */ 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(); } }, JSON.stringify(options), function(...things) { - log("internal: ", things); + log("(watch) internal: ", things); } ); } } function doInternalRequest() { log("doInternalRequest:", options && isLoaded); 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(); }, options); } } function doInternalLogout(aOptions) {
--- a/b2g/components/SignInToWebsite.jsm +++ b/b2g/components/SignInToWebsite.jsm @@ -300,17 +300,21 @@ this.SignInToWebsiteController = { } switch(message.method) { case "ready": IdentityService.doReady(aRpId); 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": IdentityService.doLogout(aRpId); break; default: log("WARNING: wonky method call:", message.method);
--- a/dom/identity/DOMIdentity.jsm +++ b/dom/identity/DOMIdentity.jsm @@ -94,24 +94,29 @@ function RPWatchContext(aOptions, aTarge // id and origin are required if (! (this.id && this.origin)) { throw new Error("id and origin are required for RP watch context"); } // 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); }, doLogout: function RPWatchContext_onlogout() { log("doLogout: " + this.id); let message = new IDDOMMessage({id: this.id}); this._mm.sendAsyncMessage("Identity:RP:Watch:OnLogout", message); },
--- a/dom/identity/nsDOMIdentity.js +++ b/dom/identity/nsDOMIdentity.js @@ -27,16 +27,18 @@ function nsDOMIdentity(aIdentityInternal this._identityInternal = aIdentityInternal; } nsDOMIdentity.prototype = { __exposedProps__: { // Relying Party (RP) watch: 'r', request: 'r', logout: 'r', + get: 'r', + getVerifiedEmail: 'r', // Provisioning beginProvisioning: 'r', genKeyPair: 'r', registerCertificate: 'r', raiseProvisioningFailure: 'r', // Authentication @@ -46,17 +48,16 @@ nsDOMIdentity.prototype = { }, // nsIDOMIdentity /** * Relying Party (RP) APIs */ watch: function nsDOMIdentity_watch(aOptions) { - this._log("watch"); if (this._rpWatcher) { throw new Error("navigator.id.watch was already called"); } if (!aOptions || typeof(aOptions) !== "object") { throw new Error("options argument to watch is required"); } @@ -105,18 +106,21 @@ nsDOMIdentity.prototype = { this._rpWatcher = aOptions; this._identityInternal._mm.sendAsyncMessage("Identity:RP:Watch", message); }, request: function nsDOMIdentity_request(aOptions) { 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; } // Has the caller called watch() before this? if (!this._rpWatcher) { throw new Error("navigator.id.request called before navigator.id.watch"); } if (this._rpCalls > MAX_RP_CALLS) { @@ -161,16 +165,80 @@ nsDOMIdentity.prototype = { throw new Error("navigator.id.logout called too many times"); } this._rpCalls++; let message = this.DOMIdentityMessage(); 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 */ beginProvisioning: function nsDOMIdentity_beginProvisioning(aCallback) { this._log("beginProvisioning"); if (this._beginProvisioningCallback) { throw new Error("navigator.id.beginProvisioning already called."); @@ -319,46 +387,54 @@ nsDOMIdentity.prototype = { return; } this._initializeState(); Services.obs.notifyObservers(null, "identity-DOM-state-reset", this._id); break; 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; } if (this._rpWatcher.onlogout) { this._rpWatcher.onlogout(); } break; 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; } if (this._rpWatcher.onready) { this._rpWatcher.onready(); } break; 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; } if (this._onCancelRequestCallback) { this._onCancelRequestCallback(); } break; case "Identity:IDP:CallBeginProvisioningCallback": @@ -427,17 +503,16 @@ nsDOMIdentity.prototype = { objectCopy(aOptions, message); // outer window id message.id = this._id; // window origin message.origin = this._origin; - dump("nsDOM message: " + JSON.stringify(message) + "\n"); return message; }, }; /** * Internal functions that shouldn't be exposed to content. */
--- a/toolkit/identity/MinimalIdentity.jsm +++ b/toolkit/identity/MinimalIdentity.jsm @@ -42,33 +42,35 @@ function makeMessageObject(aRpCaller) { let options = {}; options.id = aRpCaller.id; options.origin = aRpCaller.origin; // 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) if (!Object.hasOwnProperty(this, option) && option[0] !== '_' && typeof aRpCaller[option] !== 'function') { options[option] = aRpCaller[option]; } }); if (! (options.id && options.origin)) { let err = "id and origin required in relying-party message"; reportError(err); throw new Error(err); } - dump("message object is: " + JSON.stringify(options) + "\n"); return options; } function IDService() { Services.obs.addObserver(this, "quit-application-granted", false); // Services.obs.addObserver(this, "identity-auth-complete", false); // simplify, it's one object @@ -123,17 +125,16 @@ IDService.prototype = { * - doLogin() * - doLogout() * - doError() * - doCancel() * */ 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); log("sending identity-controller-watch:", options); Services.obs.notifyObservers({wrappedJSObject: options},"identity-controller-watch", null); }, /** @@ -172,24 +173,24 @@ IDService.prototype = { }, /* * once the UI-and-display-logic components have received * notifications, they call back with direct invocation of the * 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) { let rp = this._rpFlows[aRpCallerId]; if (!rp) { dump("WARNING: doLogout found no rp to go with callerId " + aRpCallerId + "\n"); return; }