From a81b79511e3a05ec8f68e55f64a8ef60c3dc7f96 Mon Sep 17 00:00:00 2001 From: Jed Parsons Date: Wed, 27 Mar 2013 11:19:09 -0400 Subject: [PATCH] Bug 845546 - Port b2g identity implementation to desktop. r=benadida --- browser/base/content/browser-identity.js | 149 +++++ browser/base/content/browser.css | 30 - browser/base/content/urlbarBindings.xml | 276 ++------ browser/base/jar.mn | 1 + browser/modules/SignInToWebsite.jsm | 600 ++++++++++++------ dom/identity/DOMIdentity.jsm | 44 +- dom/identity/nsDOMIdentity.js | 51 +- modules/libpref/src/init/all.js | 2 +- toolkit/identity/Identity.jsm | 39 +- toolkit/identity/IdentityProvider.jsm | 64 +- toolkit/identity/IdentityUtils.jsm | 16 +- toolkit/identity/LogUtils.jsm | 153 +++-- toolkit/identity/MinimalIdentity.jsm | 258 +------- toolkit/identity/RelyingParty.jsm | 45 +- toolkit/identity/Sandbox.jsm | 24 +- toolkit/identity/jwcrypto.jsm | 20 +- toolkit/identity/tests/unit/head_identity.js | 13 +- .../tests/unit/test_crypto_service.js | 18 +- toolkit/identity/tests/unit/test_jwcrypto.js | 13 +- toolkit/identity/tests/unit/test_log_utils.js | 35 +- .../tests/unit/test_minimalidentity.js | 6 - 21 files changed, 909 insertions(+), 948 deletions(-) create mode 100644 browser/base/content/browser-identity.js diff --git a/browser/base/content/browser-identity.js b/browser/base/content/browser-identity.js new file mode 100644 index 00000000000..8fbc80f5b16 --- /dev/null +++ b/browser/base/content/browser-identity.js @@ -0,0 +1,149 @@ +/* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +/* 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/. */ + +// This JS shim contains the callbacks to fire DOMRequest events for +// navigator.pay API within the payment processor's scope. + +'use strict'; + +let { classes: Cc, interfaces: Ci, utils: Cu } = Components; +Cu.import('resource://gre/modules/XPCOMUtils.jsm'); + +XPCOMUtils.defineLazyGetter(this, "logger", function() { + Cu.import('resource://gre/modules/identity/LogUtils.jsm'); + return getLogger("Identity", "toolkit.identity.debug"); +}); + +function IdentityShim() { + this.isLoaded = false; +} + +IdentityShim.prototype = { + init: function IdentityShim_init() { + addMessageListener('identity-delegate-watch', this); + addMessageListener('identity-delegate-request', this); + addMessageListener('identity-delegate-logout', this); + sendAsyncMessage('identity-delegate-loaded'); + logger.log('init(). sent identity-delegate-complete'); + this.isLoaded = true; + }, + + uninit: function IdentityShim_uninit() { + if (this.isLoaded) { + removeMessageListener('identity-delegate-watch', this); + removeMessageListener('identity-delegate-request', this); + removeMessageListener('identity-delegate-logout', this); + sendAsyncMessage('identity-delegate-complete', null); + logger.log('uninit(). sent identity-delegate-complete'); + this.isLoaded = false; + } + }, + + receiveMessage: function IdentityShim_receiveMessage(aMessage) { + switch (aMessage.name) { + case 'identity-delegate-watch': + this.watch(aMessage.json); + break; + case 'identity-delegate-request': + this.request(aMessage.json); + break; + case 'identity-delegate-logout': + this.logout(aMessage.json); + break; + default: + logger.error("received unexpected message:", aMessage.name); + break; + } + }, + + _identityDoMethod: function IdentityShim__identityDoMethod(message) { + sendAsyncMessage('identity-service-doMethod', message); + }, + + _close: function IdentityShim__close() { + this.uninit(); + }, + + watch: function IdentityShim_watch(options) { + logger.log('doInternalWatch: isLoaded:', this.isLoaded, 'options:', options); + if (options) { + let BrowserID = content.wrappedJSObject.BrowserID; + let callback = function(aParams, aInternalParams) { + this._identityDoMethod(aParams); + if (aParams.method === 'ready') { + this._close(); + } + }.bind(this); + + BrowserID.internal.watch( + callback, + JSON.stringify(options), + function(...things) { + logger.log('internal watch returned:', things); + } + ); + } + }, + + request: function IdentityShim_request(options) { + logger.log('doInternalRequest: isLoaded:', this.isLoaded, 'options:', options); + if (options) { + var stringifiedOptions = JSON.stringify(options); + let callback = function(assertion, internalParams) { + logger.log("received assertion:", assertion); + internalParams = internalParams || {}; + if (assertion) { + logger.log("got assertion"); + this._identityDoMethod({ + method: 'login', + assertion: assertion, + _internal: options._internal, + _internalParams: internalParams}); + } + this._close(); + }.bind(this); + + logger.log('call get() with origin', options.origin, ', callback', callback, ', and options', stringifiedOptions); + content.wrappedJSObject.BrowserID.internal.get( + options.origin, + callback, + stringifiedOptions + ); + logger.log('called get()'); + } + }, + + logout: function IdentityShim_logout(options) { + logger.log('doInternalLogout: isLoaded:', this.isLoaded, 'options:', options); + if (options) { + let BrowserID = content.wrappedJSObject.BrowserID; + let callback = function() { + this._identityDoMethod({method: 'logout', _internal: options._internal}); + this._close(); + }.bind(this); + + BrowserID.internal.logout(options.origin, callback); + } + } +}; + +this.shim = null; + +addEventListener('DOMContentLoaded', function(e) { + content.addEventListener('load', function(e) { + logger.log('content loaded'); + this.shim = new IdentityShim(); + this.shim.init(); + }); +}); + +content.addEventListener('beforeunload', function(e) { + if (this.shim) { + this.shim.uninit(); + } +}); + + diff --git a/browser/base/content/browser.css b/browser/base/content/browser.css index c008da9fa24..62691f89bd0 100644 --- a/browser/base/content/browser.css +++ b/browser/base/content/browser.css @@ -267,26 +267,6 @@ panel[noactions] > richlistbox > richlistitem[type~="action"] > .ac-url-box > .a visibility: collapse; } -#urlbar[pageproxystate="invalid"] > #identity-box > #identity-icon-labels { - visibility: collapse; -} - -#urlbar[pageproxystate="invalid"] > #identity-box { - pointer-events: none; -} - -#identity-icon-labels { - max-width: 18em; -} - -#identity-icon-country-label { - direction: ltr; -} - -#identity-box.verifiedIdentity > #identity-icon-labels > #identity-icon-label { - -moz-margin-end: 0.25em !important; -} - #wrapper-search-container > #search-container > #searchbar > .searchbar-textbox > .autocomplete-textbox-container > .textbox-input-box > html|*.textbox-input { visibility: hidden; } @@ -358,16 +338,6 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m } %endif -/* Identity UI */ -#identity-popup-content-box.unknownIdentity > #identity-popup-connectedToLabel , -#identity-popup-content-box.unknownIdentity > #identity-popup-runByLabel , -#identity-popup-content-box.unknownIdentity > #identity-popup-content-host , -#identity-popup-content-box.unknownIdentity > #identity-popup-content-owner , -#identity-popup-content-box.verifiedIdentity > #identity-popup-connectedToLabel2 , -#identity-popup-content-box.verifiedDomain > #identity-popup-connectedToLabel2 { - display: none; -} - /* Full Screen UI */ #fullscr-toggler { diff --git a/browser/base/content/urlbarBindings.xml b/browser/base/content/urlbarBindings.xml index ff4e24fa921..92a5efe4d08 100644 --- a/browser/base/content/urlbarBindings.xml +++ b/browser/base/content/urlbarBindings.xml @@ -1122,254 +1122,60 @@ - - + - - - - - - - - - - - - - - - - - + + - + + - - let sitw = {}; - Components.utils.import("resource:///modules/SignInToWebsite.jsm", sitw); - sitw.SignInToWebsiteUX; - + - - document.getAnonymousElementByAttribute(this, "anonid", "newidentitydesc"); - - - - document.getAnonymousElementByAttribute(this, "anonid", "chooseidentitydesc"); - - - - document.getAnonymousElementByAttribute(this, "anonid", "identities"); - - - - document.getAnonymousElementByAttribute(this, "anonid", "email"); - - - - document.getAnonymousElementByAttribute(this, "anonid", "newemail"); - - - - document.getAnonymousElementByAttribute(this, "anonid", "chooseemail"); - - - - document.getAnonymousElementByAttribute(this, "anonid", "throbber"); - - - - this.notification.options.identity; - - - - - - return this.identity.step; - - - - - - + + + + - - - - - - - - - - - - - - - - - diff --git a/browser/base/jar.mn b/browser/base/jar.mn index e4e05c5877b..449b2827836 100644 --- a/browser/base/jar.mn +++ b/browser/base/jar.mn @@ -60,6 +60,7 @@ browser.jar: * content/browser/browser.css (content/browser.css) * content/browser/browser.js (content/browser.js) * content/browser/browser.xul (content/browser.xul) + content/browser/browser-identity.js (content/browser-identity.js) * content/browser/browser-tabPreviews.xml (content/browser-tabPreviews.xml) content/browser/content.js (content/content.js) content/browser/newtab/newTab.xul (content/newtab/newTab.xul) diff --git a/browser/modules/SignInToWebsite.jsm b/browser/modules/SignInToWebsite.jsm index b1943ef8f7d..1efb2ae3fa8 100644 --- a/browser/modules/SignInToWebsite.jsm +++ b/browser/modules/SignInToWebsite.jsm @@ -2,246 +2,444 @@ * 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/. */ -"use strict"; +'use strict'; -this.EXPORTED_SYMBOLS = ["SignInToWebsiteUX"]; +this.EXPORTED_SYMBOLS = ['SignInToWebsiteUX']; const Cc = Components.classes; const Ci = Components.interfaces; const Cu = Components.utils; -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import('resource://gre/modules/Services.jsm'); +Cu.import('resource://gre/modules/XPCOMUtils.jsm'); +Cu.import('resource://gre/modules/identity/IdentityUtils.jsm'); -XPCOMUtils.defineLazyModuleGetter(this, "IdentityService", - "resource://gre/modules/identity/Identity.jsm"); +const kIdentityScreen = 'https://picl.personatest.org/sign_in#NATIVE'; +const kIdentityFrame = 'https://picl.personatest.org/communication_iframe'; +const kIdentityShim = 'chrome://browser/content/browser-identity.js'; -XPCOMUtils.defineLazyModuleGetter(this, "Logger", - "resource://gre/modules/identity/LogUtils.jsm"); +const PANEL_MIN_HEIGHT = 440; +const PANEL_MIN_WIDTH = 300; -function log(...aMessageArgs) { - Logger.log.apply(Logger, ["SignInToWebsiteUX"].concat(aMessageArgs)); +XPCOMUtils.defineLazyModuleGetter(this, 'IdentityService', + 'resource://gre/modules/identity/MinimalIdentity.jsm'); + +XPCOMUtils.defineLazyGetter(this, "logger", function() { + Cu.import('resource://gre/modules/identity/LogUtils.jsm'); + return getLogger("Identity", "toolkit.identity.debug"); +}); + +/** + * Ripped off from the resize watcher in base/content/browser-social.js + */ + +function sizePanelToContent(iframe) { + // FIXME: bug 764787: Maybe we can use nsIDOMWindowUtils.getRootBounds() here? + let doc = iframe.contentDocument; + if (!doc || !doc.body) { + return; + } + let body = doc.body; + + // offsetHeight/Width don't include margins, so account for that. + let cs = doc.defaultView.getComputedStyle(body); + let computedHeight = parseInt(cs.marginTop) + body.offsetHeight + parseInt(cs.marginBottom); + let height = Math.max(computedHeight, PANEL_MIN_HEIGHT); + let computedWidth = parseInt(cs.marginLeft) + body.offsetWidth + parseInt(cs.marginRight); + let width = Math.max(computedWidth, PANEL_MIN_WIDTH); + + // The panel can only resize vertically; otherwise, we would have to + // compensate for leftward or rightward shifts here + iframe.style.height = height + "px"; + iframe.style.width = width + "px"; } +function ResizeWatcher(iframe) { + this._mutationObserver = null; + this._iframe = iframe; + + this.start(); +} + +ResizeWatcher.prototype = { + start: function ResizeWatcher_start() { + this.stop(); // just in case... + let doc = this._iframe.contentDocument; + + this._mutationObserver = new this._iframe.contentWindow.MutationObserver( + function(mutations) { + sizePanelToContent(this._iframe); + }.bind(this)); + + // Observe anything that causes the size to change. + let config = { + attributes: true, + characterData: true, + childList: true, + subtree: true + }; + + this._mutationObserver.observe(doc, config); + + // and since this may be setup after the load event has fired we do an + // initial resize now. + sizePanelToContent(this._iframe); + }, + + stop: function ResizeWatcher_stop() { + if (this._mutationObserver) { + try { + this._mutationObserver.disconnect(); + } catch (ex) { + // may get "TypeError: can't access dead object" which seems strange, + // but doesn't seem to indicate a real problem, so ignore it... + } + this._mutationObserver = null; + } + } +}; + +/** + * Return the chrome window and for the given outer window ID. + */ +function getUIForWindowID(aWindowId) { + let someWindow = Services.wm.getMostRecentWindow('navigator:browser'); + if (!someWindow) { + logger.error('SignInToWebsiteUX', 'no window'); + return {}; + } + + let windowUtils = someWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + let content = windowUtils.getOuterWindowWithId(aWindowId); + + if (content) { + let browser = content.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShell).chromeEventHandler; + //let browser = someWindow.gBrowser; + let chromeWin = browser.ownerDocument.defaultView; + + return { + content: content, + browser: browser, + chromeWin: chromeWin + }; + } + logger.error('SignInToWebsiteUX', 'no content'); + + return {}; +} + +function requestUI(aContext) { + logger.log('requestUI for windowId', aContext.id); + let UI = getUIForWindowID(aContext.id); + + // message is not shown in the UI but is required + let mainAction = { + label: UI.chromeWin.gNavigatorBundle.getString('identity.next.label'), + accessKey: UI.chromeWin.gNavigatorBundle.getString('identity.next.accessKey'), + callback: function() {} // required + }; + let secondaryActions = []; + let options = { + context: aContext + }; + + UI.chromeWin.PopupNotifications.show(UI.browser, + 'identity-request', aContext.id, + 'identity-notification-icon', mainAction, + [], options); +} + +function HostFrame() { + this._iframe = null; + this._resizeWatcher = null; +} + +HostFrame.prototype = { + /* + * getIframe - adds iframe to aOptions + */ + getIframe: function HostFrame_getIframe(aOptions, aCallback) { + if (this._gotIframe) { + logger.error("Can only get iframe once with HostFrame helper"); + return; + } + + this._createIframe(aOptions); + aCallback(); + }, + + cleanUp: function HostFrame_cleanUp() { + if (this._resizeWatcher) { + this._resizeWatcher.stop(); + } + }, + + /* + * create an iframe and insert it into aOptions. If showUI is + * true, attach the iframe to a xul panel in the popup notification. + * Otherwise attach to a hidden document. + */ + _createIframe: function HostFrame_createIframe(aOptions) { + let srcURI = aOptions.showUI ? kIdentityScreen : kIdentityFrame; + logger.log('showUI is', aOptions.showUI, 'so iframe src =', srcURI); + + let hiddenDoc = Services.appShell.hiddenDOMWindow.document; + this._iframe = hiddenDoc.createElementNS('http://www.w3.org/1999/xhtml', 'iframe'); + + this._iframe.setAttribute('mozbrowser', true); + this._iframe.setAttribute('mozframetype', 'content'); + this._iframe.setAttribute('type', 'content'); + this._iframe.setAttribute('remote', true); + this._iframe.setAttribute('id', 'persona-host-frame'); + this._iframe.setAttribute('src', srcURI); + + // implement a dynamic resize watcher a la Social API + this._iframe.style.height = "440px"; + this._iframe.style.width = "300px"; + + aOptions.iframe = this._iframe; + + if (aOptions.showUI) { + // synchronous, so we can call _injectShim below with no race condition + requestUI(aOptions); + this._resizeWatcher = new ResizeWatcher(this._iframe); + } else { + hiddenDoc.documentElement.appendChild(this._iframe); + } + this._injectShim(this._iframe); + }, + + _injectShim: function HostFrame_injectShim(aIframe) { + let mm = aIframe.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader.messageManager; + logger.log('loadFrameScript:', kIdentityShim); + mm.loadFrameScript(kIdentityShim, true); + } +}; + +function Pipe(aOptions, aController) { + this.options = aOptions; + this.controller = aController; + this.mm = null; + this._closed = false; + return this; +} + +Pipe.prototype = { + observe: function pipe_observe(aSubject, aTopic, aData) { + logger.log('pipe observed', aTopic); + switch (aTopic) { + case 'identity-delegate-canceled': + this._close(); + this.controller.serviceDoMethod({method: 'cancel'}, this.options.id); + break; + + default: + logger.error('pipe observed unexpected topic: ' + aTopic); + break; + } + }, + + _close: function pipe__delegateClose() { + this._closed = true; + Services.obs.removeObserver(this, 'identity-delegate-canceled'); + if (this.mm) { + this.mm.removeMessageListener('identity-service-doMethod', this._serviceDoMethod); + this.mm.removeMessageListener('identity-delegate-complete', this._delegateComplete); + this.mm.removeMessageListener('identity-delegate-loaded', this._delegateLoaded); + } + let subject = Cc['@mozilla.org/supports-string;1'].createInstance(Ci.nsISupportsString); + subject.data = this.options.id; + Services.obs.notifyObservers(subject, 'identity-delegate-ui-close', null); + + if (typeof this.options.onComplete === 'function') { + this.options.onComplete(); + } + }, + + _delegateLoaded: function pipe__delegateLoaded() { + this.mm.sendAsyncMessage(this.options.message, this.options.rpOptions); + //this.resizer = new DynamicResizeWatcher(); + //this.resizer.start( + }, + + _delegateComplete: function pipe__delegateComplete() { + this._close(); + }, + + _serviceDoMethod: function pipe__doMethod(aMethodOptions) { + let message = aMethodOptions.json; + if (typeof message === 'string') { + try { + message = JSON.parse(message); + } catch (err) { + logger.error('Bad json message: ' + message); + return; + } + } + this.controller.serviceDoMethod(message, this.options.id); + }, + + communicate: function pipe_communicate() { + if (this._closed) { + logger.error('Cannot communicate with persona frame; pipe already closed'); + return; + } + Services.obs.addObserver(this, 'identity-delegate-canceled', false); + + let frameLoader = this.options.iframe.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader; + if (frameLoader) { + this.mm = frameLoader.messageManager; + this.mm.addMessageListener('identity-service-doMethod', this._serviceDoMethod.bind(this)); + this.mm.addMessageListener('identity-delegate-loaded', this._delegateLoaded.bind(this)); + this.mm.addMessageListener('identity-delegate-complete', this._delegateComplete.bind(this)); + } else { + logger.error('FrameLoader unavailable; Frame did not get attached properly?'); + } + } +}; + this.SignInToWebsiteUX = { - init: function SignInToWebsiteUX_init() { - - /* - * bug 793906 - temporarily disabling desktop UI so we can - * focus on b2g without worrying about desktop as well - * - Services.obs.addObserver(this, "identity-request", false); - Services.obs.addObserver(this, "identity-auth", false); - Services.obs.addObserver(this, "identity-auth-complete", false); - Services.obs.addObserver(this, "identity-login-state-changed", false); - */ + this.contexts = {}; + Services.obs.addObserver(this, 'identity-controller-watch', false); + Services.obs.addObserver(this, 'identity-controller-request', false); + Services.obs.addObserver(this, 'identity-controller-logout', false); + Services.obs.addObserver(this, 'identity-controller-canceled', false); }, uninit: function SignInToWebsiteUX_uninit() { - /* - * As above: - * bug 793906 - temporarily disabling desktop UI so we can - * focus on b2g without worrying about desktop as well - * - Services.obs.removeObserver(this, "identity-request"); - Services.obs.removeObserver(this, "identity-auth"); - Services.obs.removeObserver(this, "identity-auth-complete"); - Services.obs.removeObserver(this, "identity-login-state-changed"); - */ + Services.obs.removeObserver(this, 'identity-controller-watch'); + Services.obs.removeObserver(this, 'identity-controller-request'); + Services.obs.removeObserver(this, 'identity-controller-logout'); + Services.obs.removeObserver(this, 'identity-controller-canceled'); }, observe: function SignInToWebsiteUX_observe(aSubject, aTopic, aData) { - log("observe: received", aTopic, "with", aData, "for", aSubject); - let options = null; + logger.log('controller observed:', aTopic); + // XXX need to detect page unload of any of our flows + // XXX we get strings from xul, and objects from elsewhere + let rpOptions = {}; if (aSubject) { - options = aSubject.wrappedJSObject; + if (aSubject.wrappedJSObject) { + rpOptions = aSubject.wrappedJSObject; + } else { + rpOptions = {id: aSubject.QueryInterface(Ci.nsISupportsString).data}; + } } - switch(aTopic) { - case "identity-request": - this.requestLogin(options); + if (!rpOptions.id) { + logger.error('Got a message with no RP id'); + return; + } + + let rpId = rpOptions.id; + let UI = getUIForWindowID(rpId); + + let options = { + id: rpOptions.id, + rpOptions: rpOptions + }; + + switch (aTopic) { + case 'identity-controller-watch': + this.doWatch(options); break; - case "identity-auth": - this._openAuthenticationUI(aData, options); + + case 'identity-controller-request': + this.doRequest(options); break; - case "identity-auth-complete": - this._closeAuthenticationUI(aData); + + case 'identity-controller-logout': + this.doLogout(options); break; - case "identity-login-state-changed": - let emailAddress = aData; - if (emailAddress) { - this._removeRequestUI(options); - this._showLoggedInUI(emailAddress, options); + + default: + logger.error('SignInToWebsiteUX', 'Unknown observer notification:', aTopic); + break; + } + }, + + serviceDoMethod: function SignInToWebsiteUX_doMethod(aMessage, aId) { + logger.log('serviceDoMethod received:', aMessage); + switch (aMessage.method) { + case 'ready': + IdentityService.doReady(aId); + break; + + case 'login': + if (aMessage._internalParams) { + IdentityService.doLogin(aId, aMessage.assertion, aMessage._internalParams); } else { - this._removeLoggedInUI(options); + IdentityService.doLogin(aId, aMessage.assertion); } break; + + case 'logout': + IdentityService.doLogout(aId); + break; + + case 'cancel': + IdentityService.doCancel(aId); + break; + default: - Logger.reportError("SignInToWebsiteUX", "Unknown observer notification:", aTopic); + logger.error('Unknown identity method: ' + aMessage.method); break; } }, - /** - * The website is requesting login so the user must choose an identity to use. - */ - requestLogin: function SignInToWebsiteUX_requestLogin(aOptions) { - let windowID = aOptions.rpId; - log("requestLogin", aOptions); - let [chromeWin, browserEl] = this._getUIForWindowID(windowID); - - // message is not shown in the UI but is required - let message = aOptions.origin; - let mainAction = { - label: chromeWin.gNavigatorBundle.getString("identity.next.label"), - accessKey: chromeWin.gNavigatorBundle.getString("identity.next.accessKey"), - callback: function() {}, // required - }; - let options = { - identity: { - origin: aOptions.origin, - }, - }; - let secondaryActions = []; - - // add some extra properties to the notification to store some identity-related state - for (let opt in aOptions) { - options.identity[opt] = aOptions[opt]; + cleanUp: function SignInToWebsiteUX_cleanUp(aId) { + let context = this.contexts[aId]; + if (context) { + if (context.hostFrame) { + context.hostFrame.cleanUp(); + } + if (context.iframe && context.iframe.parentNode) { + logger.log("removing iframe from parent node and deleting it"); + context.iframe.parentNode.removeChild(context.iframe); + delete context.iframe; + } + this.contexts[aId] = {}; + delete this.contexts[aId]; } - log("requestLogin: rpId: ", options.identity.rpId); - - chromeWin.PopupNotifications.show(browserEl, "identity-request", message, - "identity-notification-icon", mainAction, - [], options); }, - /** - * Get the list of possible identities to login to the given origin. - */ - getIdentitiesForSite: function SignInToWebsiteUX_getIdentitiesForSite(aOrigin) { - return IdentityService.RP.getIdentitiesForSite(aOrigin); + delegate: function SignInToWebsiteUX_delegate(aOptions) { + let hostFrame = new HostFrame(); + hostFrame.getIframe(aOptions, function() { + // iframe has been added to aOptions + + // callback for the pipe when flow is complete + aOptions.onComplete = function pipe_onComplete() { + this.cleanUp(aOptions.id); + }.bind(this); + + // store context and communicate with pipe + this.contexts[aOptions.id] = aOptions; + this.contexts[aOptions.id].hostFrame = hostFrame; + + let pipe = new Pipe(aOptions, this); + pipe.communicate(); + }.bind(this)); }, - /** - * User chose a new or existing identity from the doorhanger after a request() call - */ - selectIdentity: function SignInToWebsiteUX_selectIdentity(aRpId, aIdentity) { - log("selectIdentity: rpId: ", aRpId, " identity: ", aIdentity); - IdentityService.selectIdentity(aRpId, aIdentity); + doWatch: function SignInToWebsiteUX_doWatch(aOptions) { + aOptions.message = 'identity-delegate-watch'; + aOptions.showUI = false; + this.delegate(aOptions); }, - // Private - - /** - * Return the chrome window and for the given outer window ID. - */ - _getUIForWindowID: function(aWindowID) { - let someWindow = Services.wm.getMostRecentWindow("navigator:browser"); - if (!someWindow) { - Logger.reportError("SignInToWebsiteUX", "no window"); - return [null, null]; - } - - let windowUtils = someWindow.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils); - let content = windowUtils.getOuterWindowWithId(aWindowID); - - if (content) { - let browser = content.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShell).chromeEventHandler; - let chromeWin = browser.ownerDocument.defaultView; - return [chromeWin, browser]; - } - Logger.reportError("SignInToWebsiteUX", "no content"); - - return [null, null]; - }, - - /** - * Open UI with a content frame displaying aAuthURI so that the user can authenticate with their - * IDP. Then tell Identity.jsm the identifier for the window so that it knows that the DOM API - * calls are for this authentication flow. - */ - _openAuthenticationUI: function _openAuthenticationUI(aAuthURI, aContext) { - // Open a tab/window with aAuthURI with an identifier (aID) attached so that the DOM APIs know this is an auth. window. - let chromeWin = Services.wm.getMostRecentWindow('navigator:browser'); - let features = "chrome=false,width=640,height=480,centerscreen,location=yes,resizable=yes,scrollbars=yes,status=yes"; - log("aAuthURI: ", aAuthURI); - let authWin = Services.ww.openWindow(chromeWin, "about:blank", "", features, null); - let windowID = authWin.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).outerWindowID; - log("authWin outer id: ", windowID); - - let provId = aContext.provId; - // Tell the ID service about the id before loading the url - IdentityService.IDP.setAuthenticationFlow(windowID, provId); - - authWin.location = aAuthURI; - }, - - _closeAuthenticationUI: function _closeAuthenticationUI(aAuthId) { - log("_closeAuthenticationUI:", aAuthId); - let [chromeWin, browserEl] = this._getUIForWindowID(aAuthId); - if (chromeWin) - chromeWin.close(); - else - Logger.reportError("SignInToWebsite", "Could not close window with ID", aAuthId); - }, - - /** - * Show a doorhanger indicating the currently logged-in user. - */ - _showLoggedInUI: function _showLoggedInUI(aIdentity, aContext) { - let windowID = aContext.rpId; - log("_showLoggedInUI for ", windowID); - let [chromeWin, browserEl] = this._getUIForWindowID(windowID); - - let message = chromeWin.gNavigatorBundle.getFormattedString("identity.loggedIn.description", - [aIdentity]); - let mainAction = { - label: chromeWin.gNavigatorBundle.getString("identity.loggedIn.signOut.label"), - accessKey: chromeWin.gNavigatorBundle.getString("identity.loggedIn.signOut.accessKey"), - callback: function() { - log("sign out callback fired"); - IdentityService.RP.logout(windowID); - }, - }; - let secondaryActions = []; - let options = { - dismissed: true, - }; - let loggedInNot = chromeWin.PopupNotifications.show(browserEl, "identity-logged-in", message, - "identity-notification-icon", mainAction, - secondaryActions, options); - loggedInNot.rpId = windowID; - }, - - /** - * Remove the doorhanger indicating the currently logged-in user. - */ - _removeLoggedInUI: function _removeLoggedInUI(aContext) { - let windowID = aContext.rpId; - log("_removeLoggedInUI for ", windowID); - if (!windowID) - throw "_removeLoggedInUI: Invalid RP ID"; - let [chromeWin, browserEl] = this._getUIForWindowID(windowID); - - let loggedInNot = chromeWin.PopupNotifications.getNotification("identity-logged-in", browserEl); - if (loggedInNot) - chromeWin.PopupNotifications.remove(loggedInNot); - }, - - /** - * Remove the doorhanger indicating the currently logged-in user. - */ - _removeRequestUI: function _removeRequestUI(aContext) { - let windowID = aContext.rpId; - log("_removeRequestUI for ", windowID); - let [chromeWin, browserEl] = this._getUIForWindowID(windowID); - - let requestNot = chromeWin.PopupNotifications.getNotification("identity-request", browserEl); - if (requestNot) - chromeWin.PopupNotifications.remove(requestNot); + doRequest: function SignInToWebsiteUX_doRequest(aOptions) { + aOptions.message = 'identity-delegate-request'; + aOptions.showUI = true; + this.delegate(aOptions); }, + doLogout: function SignInToWebsiteUX_doLogout(aOptions) { + aOptions.message = 'identity-delegate-logout'; + aOptions.showUI = false; + this.delegate(aOptions); + } }; diff --git a/dom/identity/DOMIdentity.jsm b/dom/identity/DOMIdentity.jsm index 4ebd169773c..7f39ae67484 100644 --- a/dom/identity/DOMIdentity.jsm +++ b/dom/identity/DOMIdentity.jsm @@ -14,23 +14,16 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/identity/IdentityUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "IdentityService", -#ifdef MOZ_B2G_VERSION "resource://gre/modules/identity/MinimalIdentity.jsm"); -#else - "resource://gre/modules/identity/Identity.jsm"); -#endif - -XPCOMUtils.defineLazyModuleGetter(this, - "Logger", - "resource://gre/modules/identity/LogUtils.jsm"); XPCOMUtils.defineLazyServiceGetter(this, "ppmm", "@mozilla.org/parentprocessmessagemanager;1", "nsIMessageListenerManager"); -function log(...aMessageArgs) { - Logger.log.apply(Logger, ["DOMIdentity"].concat(aMessageArgs)); -} +XPCOMUtils.defineLazyGetter(this, "logger", function() { + Cu.import('resource://gre/modules/identity/LogUtils.jsm'); + return getLogger("Identity", "toolkit.identity.debug"); +}); function IDDOMMessage(aOptions) { objectCopy(aOptions, this); @@ -55,14 +48,14 @@ IDPProvisioningContext.prototype = { }, doGenKeyPairCallback: function IDPPC_doGenKeyPairCallback(aPublicKey) { - log("doGenKeyPairCallback"); + logger.log("doGenKeyPairCallback"); let message = new IDDOMMessage({id: this.id}); message.publicKey = aPublicKey; this._mm.sendAsyncMessage("Identity:IDP:CallGenKeyPairCallback", message); }, doError: function(msg) { - log("Provisioning ERROR: " + msg); + logger.warning(msg); } }; @@ -84,7 +77,7 @@ IDPAuthenticationContext.prototype = { }, doError: function IDPAC_doError(msg) { - log("Authentication ERROR: " + msg); + logger.warning(msg); } }; @@ -93,7 +86,9 @@ function RPWatchContext(aOptions, aTargetMM) { // id and origin are required if (! (this.id && this.origin)) { - throw new Error("id and origin are required for RP watch context"); + let err = "id and origin are required for RP watch context"; + logger.error(err); + throw new Error(err); } // default for no loggedInUser is undefined, not null @@ -107,7 +102,7 @@ function RPWatchContext(aOptions, aTargetMM) { RPWatchContext.prototype = { doLogin: function RPWatchContext_onlogin(aAssertion, aMaybeInternalParams) { - log("doLogin: " + this.id); + logger.log("login id: " + this.id); let message = new IDDOMMessage({id: this.id, assertion: aAssertion}); if (aMaybeInternalParams) { message._internalParams = aMaybeInternalParams; @@ -116,19 +111,19 @@ RPWatchContext.prototype = { }, doLogout: function RPWatchContext_onlogout() { - log("doLogout: " + this.id); + logger.log("logout id: " + this.id); let message = new IDDOMMessage({id: this.id}); this._mm.sendAsyncMessage("Identity:RP:Watch:OnLogout", message); }, doReady: function RPWatchContext_onready() { - log("doReady: " + this.id); + logger.log("ready id: " + this.id); let message = new IDDOMMessage({id: this.id}); this._mm.sendAsyncMessage("Identity:RP:Watch:OnReady", message); }, doCancel: function RPWatchContext_oncancel() { - log("doCancel: " + this.id); + logger.log("cancel id: " + this.id); let message = new IDDOMMessage({id: this.id}); this._mm.sendAsyncMessage("Identity:RP:Watch:OnCancel", message); }, @@ -147,6 +142,8 @@ this.DOMIdentity = { // used to send replies back to the proper window. let targetMM = aMessage.target; + logger.log("received:", aMessage.name); + switch (aMessage.name) { // RP case "Identity:RP:Watch": @@ -217,6 +214,7 @@ this.DOMIdentity = { Services.ww.registerNotification(this); Services.obs.addObserver(this, "xpcom-shutdown", false); this._subscribeListeners(); + logger.log("DOM identity service initialized"); }, _subscribeListeners: function DOMIdentity__subscribeListeners() { @@ -234,16 +232,18 @@ this.DOMIdentity = { }, _resetFrameState: function(aContext) { - log("_resetFrameState: ", aContext.id); + logger.log("_resetFrameState: ", aContext.id); if (!aContext._mm) { - throw new Error("ERROR: Trying to reset an invalid context"); + let err = "Trying to reset an invalid context"; + logger.error(err); + throw new Error(err); } let message = new IDDOMMessage({id: aContext.id}); aContext._mm.sendAsyncMessage("Identity:ResetState", message); }, _watch: function DOMIdentity__watch(message, targetMM) { - log("DOMIdentity__watch: " + message.id); + logger.log("DOMIdentity__watch: " + message.id); // Pass an object with the watch members to Identity.jsm so it can call the // callbacks. let context = new RPWatchContext(message, targetMM); diff --git a/dom/identity/nsDOMIdentity.js b/dom/identity/nsDOMIdentity.js index 1a80def39a4..c227dce79b3 100644 --- a/dom/identity/nsDOMIdentity.js +++ b/dom/identity/nsDOMIdentity.js @@ -23,12 +23,18 @@ Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/identity/IdentityUtils.jsm"); +XPCOMUtils.defineLazyGetter(this, "logger", function() { + Cu.import('resource://gre/modules/identity/LogUtils.jsm'); + return getLogger("Identity", "toolkit.identity.debug"); +}); + // This is the child process corresponding to nsIDOMIdentity XPCOMUtils.defineLazyServiceGetter(this, "cpmm", "@mozilla.org/childprocessmessagemanager;1", "nsIMessageSender"); function nsDOMIdentity(aIdentityInternal) { + logger.log("nsDOMIdentity constructor"); this._identityInternal = aIdentityInternal; } nsDOMIdentity.prototype = { @@ -65,6 +71,7 @@ nsDOMIdentity.prototype = { */ watch: function nsDOMIdentity_watch(aOptions) { + logger.log(aOptions); if (this._rpWatcher) { throw new Error("navigator.id.watch was already called"); } @@ -89,6 +96,7 @@ nsDOMIdentity.prototype = { } let message = this.DOMIdentityMessage(aOptions); + logger.log(message); // loggedInUser vs loggedInEmail // https://developer.mozilla.org/en-US/docs/DOM/navigator.id.watch @@ -98,6 +106,7 @@ nsDOMIdentity.prototype = { checkRenamed(aOptions, "loggedInEmail", "loggedInUser"); message["loggedInUser"] = aOptions["loggedInUser"]; + logger.log(message); let emailType = typeof(aOptions["loggedInUser"]); if (aOptions["loggedInUser"] && aOptions["loggedInUser"] !== "undefined") { if (emailType !== "string") { @@ -113,13 +122,14 @@ nsDOMIdentity.prototype = { // Set loggedInUser in this block that "undefined" doesn't get through. message.loggedInUser = aOptions.loggedInUser; } - this._log("loggedInUser: " + message.loggedInUser); + logger.log("loggedInUser:", message.loggedInUser); this._rpWatcher = aOptions; this._identityInternal._mm.sendAsyncMessage("Identity:RP:Watch", message); }, request: function nsDOMIdentity_request(aOptions) { + logger.log(aOptions); let util = this._window.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDOMWindowUtils); @@ -128,7 +138,7 @@ nsDOMIdentity.prototype = { // getVerifiedEmail() calls, which make use of an RP context // marked as _internal. if (this.nativeEventsRequired && !util.isHandlingUserInput && !aOptions._internal) { - this._log("request: rejecting non-native event"); + error("request: rejecting non-native event"); return; } @@ -171,6 +181,7 @@ nsDOMIdentity.prototype = { }, logout: function nsDOMIdentity_logout() { + logger.log("logout"); if (!this._rpWatcher) { throw new Error("navigator.id.logout called before navigator.id.watch"); } @@ -243,7 +254,7 @@ nsDOMIdentity.prototype = { }, getVerifiedEmail: function nsDOMIdentity_getVerifiedEmail(aCallback) { - Cu.reportError("WARNING: getVerifiedEmail has been deprecated"); + error("WARNING: getVerifiedEmail has been deprecated"); this.get(aCallback, {}); }, @@ -252,7 +263,7 @@ nsDOMIdentity.prototype = { */ beginProvisioning: function nsDOMIdentity_beginProvisioning(aCallback) { - this._log("beginProvisioning"); + logger.log("beginProvisioning"); if (this._beginProvisioningCallback) { throw new Error("navigator.id.beginProvisioning already called."); } @@ -266,7 +277,7 @@ nsDOMIdentity.prototype = { }, genKeyPair: function nsDOMIdentity_genKeyPair(aCallback) { - this._log("genKeyPair"); + logger.log("genKeyPair"); if (!this._beginProvisioningCallback) { throw new Error("navigator.id.genKeyPair called outside of provisioning"); } @@ -283,7 +294,7 @@ nsDOMIdentity.prototype = { }, registerCertificate: function nsDOMIdentity_registerCertificate(aCertificate) { - this._log("registerCertificate"); + logger.log("registerCertificate"); if (!this._genKeyPairCallback) { throw new Error("navigator.id.registerCertificate called outside of provisioning"); } @@ -298,7 +309,7 @@ nsDOMIdentity.prototype = { }, raiseProvisioningFailure: function nsDOMIdentity_raiseProvisioningFailure(aReason) { - this._log("raiseProvisioningFailure '" + aReason + "'"); + logger.log("raiseProvisioningFailure '" + aReason + "'"); if (this._provisioningEnded) { throw new Error("Provisioning already ended"); } @@ -317,7 +328,7 @@ nsDOMIdentity.prototype = { */ beginAuthentication: function nsDOMIdentity_beginAuthentication(aCallback) { - this._log("beginAuthentication"); + logger.log("beginAuthentication"); if (this._beginAuthenticationCallback) { throw new Error("navigator.id.beginAuthentication already called."); } @@ -405,7 +416,7 @@ nsDOMIdentity.prototype = { case "Identity:RP:Watch:OnLogin": // Do we have a watcher? if (!this._rpWatcher) { - this._log("WARNING: Received OnLogin message, but there is no RP watcher"); + logger.warning("Received OnLogin message, but there is no RP watcher"); return; } @@ -420,7 +431,7 @@ nsDOMIdentity.prototype = { case "Identity:RP:Watch:OnLogout": // Do we have a watcher? if (!this._rpWatcher) { - this._log("WARNING: Received OnLogout message, but there is no RP watcher"); + logger.warning("Received OnLogout message, but there is no RP watcher"); return; } @@ -431,7 +442,7 @@ nsDOMIdentity.prototype = { case "Identity:RP:Watch:OnReady": // Do we have a watcher? if (!this._rpWatcher) { - this._log("WARNING: Received OnReady message, but there is no RP watcher"); + logger.warning("Received OnReady message, but there is no RP watcher"); return; } @@ -442,7 +453,7 @@ nsDOMIdentity.prototype = { case "Identity:RP:Watch:OnCancel": // Do we have a watcher? if (!this._rpWatcher) { - this._log("WARNING: Received OnCancel message, but there is no RP watcher"); + logger.warning("Received OnCancel message, but there is no RP watcher"); return; } @@ -462,10 +473,6 @@ nsDOMIdentity.prototype = { } }, - _log: function nsDOMIdentity__log(msg) { - this._identityInternal._log(msg); - }, - _callGenKeyPairCallback: function nsDOMIdentity__callGenKeyPairCallback(message) { // create a pubkey object that works let chrome_pubkey = JSON.parse(message.publicKey); @@ -525,7 +532,7 @@ nsDOMIdentity.prototype = { }, uninit: function DOMIdentity_uninit() { - this._log("nsDOMIdentity uninit()"); + logger.log("unwatch", this._id); this._identityInternal._mm.sendAsyncMessage( "Identity:RP:Unwatch", { id: this._id } @@ -598,7 +605,7 @@ nsDOMIdentityInternal.prototype = { this._id = util.outerWindowID; this._innerWindowID = util.currentInnerWindowID; - this._log("init was called from " + aWindow.document.location); + logger.log("init was called from", aWindow.document.location); this._mm = cpmm; @@ -623,14 +630,6 @@ nsDOMIdentityInternal.prototype = { return this._identity; }, - // Private. - _log: function nsDOMIdentityInternal__log(msg) { - if (!this._debug) { - return; - } - dump("nsDOMIdentity (" + this._id + "): " + msg + "\n"); - }, - // Component setup. classID: Components.ID("{210853d9-2c97-4669-9761-b1ab9cbf57ef}"), diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index 46c10df5279..fa9599cf7f2 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -384,7 +384,7 @@ pref("toolkit.telemetry.infoURL", "http://www.mozilla.com/legal/privacy/firefox. pref("toolkit.telemetry.debugSlowSql", false); // Identity module -pref("toolkit.identity.enabled", false); +pref("dom.identity.enabled", false); pref("toolkit.identity.debug", false); // Enable deprecation warnings. diff --git a/toolkit/identity/Identity.jsm b/toolkit/identity/Identity.jsm index 47c4e539961..e6c0c8f5518 100644 --- a/toolkit/identity/Identity.jsm +++ b/toolkit/identity/Identity.jsm @@ -15,7 +15,6 @@ const Cr = Components.results; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/identity/LogUtils.jsm"); Cu.import("resource://gre/modules/identity/IdentityStore.jsm"); Cu.import("resource://gre/modules/identity/RelyingParty.jsm"); Cu.import("resource://gre/modules/identity/IdentityProvider.jsm"); @@ -24,12 +23,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "jwcrypto", "resource://gre/modules/identity/jwcrypto.jsm"); -function log(...aMessageArgs) { - Logger.log.apply(Logger, ["core"].concat(aMessageArgs)); -} -function reportError(...aMessageArgs) { - Logger.reportError.apply(Logger, ["core"].concat(aMessageArgs)); -} +XPCOMUtils.defineLazyGetter(this, "logger", function() { + Cu.import('resource://gre/modules/identity/LogUtils.jsm'); + return getLogger("Identity", "toolkit.identity.debug"); +}); function IDService() { Services.obs.addObserver(this, "quit-application-granted", false); @@ -53,7 +50,7 @@ IDService.prototype = { if (!aSubject || !aSubject.wrappedJSObject) break; let subject = aSubject.wrappedJSObject; - log("Auth complete:", aSubject.wrappedJSObject); + logger.log("Auth complete:", aSubject.wrappedJSObject); // We have authenticated in order to provision an identity. // So try again. this.selectIdentity(subject.rpId, subject.identity); @@ -73,7 +70,7 @@ IDService.prototype = { }, shutdown: function shutdown() { - log("shutdown"); + logger.log("shutdown"); Services.obs.removeObserver(this, "identity-auth-complete"); Services.obs.removeObserver(this, "quit-application-granted"); }, @@ -117,12 +114,12 @@ IDService.prototype = { * (string) the email chosen for login */ selectIdentity: function selectIdentity(aRPId, aIdentity) { - log("selectIdentity: RP id:", aRPId, "identity:", aIdentity); + logger.log("selectIdentity: RP id:", aRPId, "identity:", aIdentity); // Get the RP that was stored when watch() was invoked. let rp = this.RP._rpFlows[aRPId]; if (!rp) { - reportError("selectIdentity", "Invalid RP id: ", aRPId); + logger.warning("selectIdentity", "Invalid RP id: ", aRPId); return; } @@ -134,7 +131,7 @@ IDService.prototype = { loggedInUser: aIdentity, origin: rp.origin }; - log("selectIdentity: provId:", provId, "origin:", rp.origin); + logger.log("selectIdentity: provId:", provId, "origin:", rp.origin); // Once we have a cert, and once the user is authenticated with the // IdP, we can generate an assertion and deliver it to the doc. @@ -175,7 +172,7 @@ IDService.prototype = { if (self.IDP._provisionFlows[aProvId].didAuthentication) { self.IDP._cleanUpProvisionFlow(aProvId); self.RP._cleanUpProvisionFlow(aRPId, aProvId); - log("ERROR: selectIdentity: authentication hard fail"); + logger.error("ERROR: selectIdentity: authentication hard fail"); rp.doError("Authentication fail."); return; } @@ -222,7 +219,7 @@ IDService.prototype = { if (parsedEmail === null) { return aCallback("Could not parse email: " + aIdentity); } - log("_discoverIdentityProvider: identity:", aIdentity, "domain:", parsedEmail.domain); + logger.log("_discoverIdentityProvider: identity:", aIdentity, "domain:", parsedEmail.domain); this._fetchWellKnownFile(parsedEmail.domain, function fetchedWellKnown(err, idpParams) { // idpParams includes the pk, authorization url, and @@ -251,7 +248,7 @@ IDService.prototype = { _fetchWellKnownFile: function _fetchWellKnownFile(aDomain, aCallback, aScheme='https') { // XXX bug 769854 make tests https and remove aScheme option let url = aScheme + '://' + aDomain + "/.well-known/browserid"; - log("_fetchWellKnownFile:", url); + logger.log("_fetchWellKnownFile:", url); // this appears to be a more successful way to get at xmlhttprequest (which supposedly will close with a window let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"] @@ -264,7 +261,7 @@ IDService.prototype = { req.mozBackgroundRequest = true; req.onload = function _fetchWellKnownFile_onload() { if (req.status < 200 || req.status >= 400) { - log("_fetchWellKnownFile", url, ": server returned status:", req.status); + logger.log("_fetchWellKnownFile", url, ": server returned status:", req.status); return aCallback("Error"); } try { @@ -275,7 +272,7 @@ IDService.prototype = { idpParams.authentication && idpParams['public-key'])) { let errStr= "Invalid well-known file from: " + aDomain; - log("_fetchWellKnownFile:", errStr); + logger.log("_fetchWellKnownFile:", errStr); return aCallback(errStr); } @@ -283,18 +280,18 @@ IDService.prototype = { domain: aDomain, idpParams: idpParams, }; - log("_fetchWellKnownFile result: ", callbackObj); + logger.log("_fetchWellKnownFile result: ", callbackObj); // Yay. Valid IdP configuration for the domain. return aCallback(null, callbackObj); } catch (err) { - reportError("_fetchWellKnownFile", "Bad configuration from", aDomain, err); + logger.warning("_fetchWellKnownFile", "Bad configuration from", aDomain, err); return aCallback(err.toString()); } }; req.onerror = function _fetchWellKnownFile_onerror() { - log("_fetchWellKnownFile", "ERROR:", req.status, req.statusText); - log("ERROR: _fetchWellKnownFile:", err); + logger.log("_fetchWellKnownFile", "ERROR:", req.status, req.statusText); + logger.error("ERROR: _fetchWellKnownFile:", err); return aCallback("Error"); }; req.send(null); diff --git a/toolkit/identity/IdentityProvider.jsm b/toolkit/identity/IdentityProvider.jsm index f0fb5ed5d91..a4a8f7dc2ca 100644 --- a/toolkit/identity/IdentityProvider.jsm +++ b/toolkit/identity/IdentityProvider.jsm @@ -13,7 +13,6 @@ const Cr = Components.results; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/identity/LogUtils.jsm"); Cu.import("resource://gre/modules/identity/Sandbox.jsm"); this.EXPORTED_SYMBOLS = ["IdentityProvider"]; @@ -23,13 +22,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "jwcrypto", "resource://gre/modules/identity/jwcrypto.jsm"); -function log(...aMessageArgs) { - Logger.log.apply(Logger, ["IDP"].concat(aMessageArgs)); -} -function reportError(...aMessageArgs) { - Logger.reportError.apply(Logger, ["IDP"].concat(aMessageArgs)); -} - +XPCOMUtils.defineLazyGetter(this, "logger", function() { + Cu.import('resource://gre/modules/identity/LogUtils.jsm'); + return getLogger("Identity IDP", "toolkit.identity.debug"); +}); function IdentityProviderService() { XPCOMUtils.defineLazyModuleGetter(this, @@ -76,7 +72,7 @@ IdentityProviderService.prototype = { } let err = "No provisioning flow found with id " + aProvId; - log("ERROR:", err); + logger.warning("ERROR:", err); if (typeof aErrBack === 'function') { aErrBack(err); } @@ -122,7 +118,7 @@ IdentityProviderService.prototype = { _provisionIdentity: function _provisionIdentity(aIdentity, aIDPParams, aProvId, aCallback) { let provPath = aIDPParams.idpParams.provisioning; let url = Services.io.newURI("https://" + aIDPParams.domain, null, null).resolve(provPath); - log("_provisionIdentity: identity:", aIdentity, "url:", url); + logger.log("_provisionIdentity: identity:", aIdentity, "url:", url); // If aProvId is not null, then we already have a flow // with a sandbox. Otherwise, get a sandbox and create a @@ -130,7 +126,7 @@ IdentityProviderService.prototype = { if (aProvId) { // Re-use an existing sandbox - log("_provisionIdentity: re-using sandbox in provisioning flow with id:", aProvId); + logger.log("_provisionIdentity: re-using sandbox in provisioning flow with id:", aProvId); this._provisionFlows[aProvId].provisioningSandbox.reload(); } else { @@ -149,7 +145,7 @@ IdentityProviderService.prototype = { }, }; - log("_provisionIdentity: Created sandbox and provisioning flow with id:", provId); + logger.log("_provisionIdentity: Created sandbox and provisioning flow with id:", provId); // XXX bug 769862 - provisioning flow should timeout after N seconds }.bind(this)); @@ -167,7 +163,7 @@ IdentityProviderService.prototype = { * - doGenKeyPairCallback(pk) */ beginProvisioning: function beginProvisioning(aCaller) { - log("beginProvisioning:", aCaller.id); + logger.log("beginProvisioning:", aCaller.id); // Expect a flow for this caller already to be underway. let provFlow = this.getProvisionFlow(aCaller.id, aCaller.doError); @@ -199,7 +195,7 @@ IdentityProviderService.prototype = { * @param aReason */ raiseProvisioningFailure: function raiseProvisioningFailure(aProvId, aReason) { - reportError("Provisioning failure", aReason); + logger.warning("Provisioning failure", aReason); // look up the provisioning caller and its callback let provFlow = this.getProvisionFlow(aProvId); @@ -232,16 +228,16 @@ IdentityProviderService.prototype = { if (!provFlow.didBeginProvisioning) { let errStr = "ERROR: genKeyPair called before beginProvisioning"; - log(errStr); + logger.warning(errStr); provFlow.callback(errStr); return; } // Ok generate a keypair jwcrypto.generateKeyPair(jwcrypto.ALGORITHMS.DS160, function gkpCb(err, kp) { - log("in gkp callback"); + logger.log("in gkp callback"); if (err) { - log("ERROR: genKeyPair:", err); + logger.error("ERROR: genKeyPair:", err); provFlow.callback(err); return; } @@ -250,7 +246,7 @@ IdentityProviderService.prototype = { // Serialize the publicKey of the keypair and send it back to the // sandbox. - log("genKeyPair: generated keypair for provisioning flow with id:", aProvId); + logger.log("genKeyPair: generated keypair for provisioning flow with id:", aProvId); provFlow.caller.doGenKeyPairCallback(provFlow.kp.serializedPublicKey); }.bind(this)); }, @@ -271,18 +267,18 @@ IdentityProviderService.prototype = { * being provisioned, provided by the IdP. */ registerCertificate: function registerCertificate(aProvId, aCert) { - log("registerCertificate:", aProvId, aCert); + logger.log("registerCertificate:", aProvId, aCert); // look up provisioning caller, make sure it's valid. let provFlow = this.getProvisionFlow(aProvId); if (!provFlow.caller) { - reportError("registerCertificate", "No provision flow or caller"); + logger.warning("registerCertificate", "No provision flow or caller"); return; } if (!provFlow.kp) { let errStr = "Cannot register a certificate without a keypair"; - reportError("registerCertificate", errStr); + logger.warning("registerCertificate", errStr); provFlow.callback(errStr); return; } @@ -308,7 +304,7 @@ IdentityProviderService.prototype = { * first-positional-param error. */ _doAuthentication: function _doAuthentication(aProvId, aIDPParams) { - log("_doAuthentication: provId:", aProvId, "idpParams:", aIDPParams); + logger.log("_doAuthentication: provId:", aProvId, "idpParams:", aIDPParams); // create an authentication caller and its identifier AuthId // stash aIdentity, idpparams, and callback in it. @@ -341,7 +337,7 @@ IdentityProviderService.prototype = { * */ beginAuthentication: function beginAuthentication(aCaller) { - log("beginAuthentication: caller id:", aCaller.id); + logger.log("beginAuthentication: caller id:", aCaller.id); // Begin the authentication flow after having concluded a provisioning // flow. The aCaller that the DOM gives us will have the same ID as @@ -356,7 +352,7 @@ IdentityProviderService.prototype = { let identity = this._provisionFlows[authFlow.provId].identity; // tell the UI to start the authentication process - log("beginAuthentication: authFlow:", aCaller.id, "identity:", identity); + logger.log("beginAuthentication: authFlow:", aCaller.id, "identity:", identity); return authFlow.caller.doBeginAuthenticationCallback(identity); }, @@ -368,12 +364,12 @@ IdentityProviderService.prototype = { * */ completeAuthentication: function completeAuthentication(aAuthId) { - log("completeAuthentication:", aAuthId); + logger.log("completeAuthentication:", aAuthId); // look up the AuthId caller, and get its callback. let authFlow = this._authenticationFlows[aAuthId]; if (!authFlow) { - reportError("completeAuthentication", "No auth flow with id", aAuthId); + logger.warning("completeAuthentication", "No auth flow with id", aAuthId); return; } let provId = authFlow.provId; @@ -399,12 +395,12 @@ IdentityProviderService.prototype = { * */ cancelAuthentication: function cancelAuthentication(aAuthId) { - log("cancelAuthentication:", aAuthId); + logger.log("cancelAuthentication:", aAuthId); // look up the AuthId caller, and get its callback. let authFlow = this._authenticationFlows[aAuthId]; if (!authFlow) { - reportError("cancelAuthentication", "No auth flow with id:", aAuthId); + logger.warning("cancelAuthentication", "No auth flow with id:", aAuthId); return; } let provId = authFlow.provId; @@ -419,7 +415,7 @@ IdentityProviderService.prototype = { // invoke callback with ERROR. let errStr = "Authentication canceled by IDP"; - log("ERROR: cancelAuthentication:", errStr); + logger.log("ERROR: cancelAuthentication:", errStr); provFlow.callback(errStr); }, @@ -430,7 +426,7 @@ IdentityProviderService.prototype = { // this is the transition point between the two flows, // provision and authenticate. We tell the auth flow which // provisioning flow it is started from. - log("setAuthenticationFlow: authId:", aAuthId, "provId:", aProvId); + logger.log("setAuthenticationFlow: authId:", aAuthId, "provId:", aProvId); this._authenticationFlows[aAuthId] = { provId: aProvId }; this._provisionFlows[aProvId].authId = aAuthId; }, @@ -440,7 +436,7 @@ IdentityProviderService.prototype = { * process. */ _createProvisioningSandbox: function _createProvisioningSandbox(aURL, aCallback) { - log("_createProvisioningSandbox:", aURL); + logger.log("_createProvisioningSandbox:", aURL); if (!this._sandboxConfigured) { // Configure message manager listening on the hidden window @@ -456,7 +452,7 @@ IdentityProviderService.prototype = { * Load the authentication UI to start the authentication process. */ _beginAuthenticationFlow: function _beginAuthenticationFlow(aProvId, aURL) { - log("_beginAuthenticationFlow:", aProvId, aURL); + logger.log("_beginAuthenticationFlow:", aProvId, aURL); let propBag = {provId: aProvId}; Services.obs.notifyObservers({wrappedJSObject:propBag}, "identity-auth", aURL); @@ -467,14 +463,14 @@ IdentityProviderService.prototype = { * that may be attached to it. */ _cleanUpProvisionFlow: function _cleanUpProvisionFlow(aProvId) { - log('_cleanUpProvisionFlow:', aProvId); + logger.log('_cleanUpProvisionFlow:', aProvId); let prov = this._provisionFlows[aProvId]; // Clean up the sandbox, if there is one. if (prov.provisioningSandbox) { let sandbox = this._provisionFlows[aProvId]['provisioningSandbox']; if (sandbox.free) { - log('_cleanUpProvisionFlow: freeing sandbox'); + logger.log('_cleanUpProvisionFlow: freeing sandbox'); sandbox.free(); } delete this._provisionFlows[aProvId]['provisioningSandbox']; diff --git a/toolkit/identity/IdentityUtils.jsm b/toolkit/identity/IdentityUtils.jsm index f9fc8b28546..234b41bca84 100644 --- a/toolkit/identity/IdentityUtils.jsm +++ b/toolkit/identity/IdentityUtils.jsm @@ -23,12 +23,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "uuidgen", "@mozilla.org/uuid-generator;1", "nsIUUIDGenerator"); -XPCOMUtils.defineLazyModuleGetter(this, "Logger", - "resource://gre/modules/identity/LogUtils.jsm"); - -function log(...aMessageArgs) { - Logger.log.apply(Logger, ["Identity"].concat(aMessageArgs)); -} +XPCOMUtils.defineLazyGetter(this, "logger", function() { + Cu.import('resource://gre/modules/identity/LogUtils.jsm'); + return getLogger("Identity", "toolkit.identity.debug"); +}); function defined(item) { return typeof item !== 'undefined'; @@ -36,7 +34,7 @@ function defined(item) { var checkDeprecated = this.checkDeprecated = function checkDeprecated(aOptions, aField) { if (defined(aOptions[aField])) { - log("WARNING: field is deprecated:", aField); + logger.log("WARNING: field is deprecated:", aField); return true; } return false; @@ -46,7 +44,7 @@ this.checkRenamed = function checkRenamed(aOptions, aOldName, aNewName) { if (defined(aOptions[aOldName]) && defined(aOptions[aNewName])) { let err = "You cannot provide both " + aOldName + " and " + aNewName; - Logger.reportError(err); + logger.error(err); throw new Error(err); } @@ -64,7 +62,7 @@ this.getRandomId = function getRandomId() { * copy source object into target, excluding private properties * (those whose names begin with an underscore) */ -this.objectCopy = function objectCopy(source, target){ +this.objectCopy = function objectCopy(source, target) { let desc; Object.getOwnPropertyNames(source).forEach(function(name) { if (name[0] !== '_') { diff --git a/toolkit/identity/LogUtils.jsm b/toolkit/identity/LogUtils.jsm index 61dba9d3ba9..a30090cff79 100644 --- a/toolkit/identity/LogUtils.jsm +++ b/toolkit/identity/LogUtils.jsm @@ -6,34 +6,45 @@ "use strict"; -this.EXPORTED_SYMBOLS = ["Logger"]; -const PREF_DEBUG = "toolkit.identity.debug"; +this.EXPORTED_SYMBOLS = ["Logger", "getLogger"]; const Cu = Components.utils; const Ci = Components.interfaces; -const Cc = Components.classes; -const Cr = Components.results; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); -function IdentityLogger() { - Services.prefs.addObserver(PREF_DEBUG, this, false); - this._debug = Services.prefs.getBoolPref(PREF_DEBUG); - return this; +function Logger(aIdentifier, aEnablingPref) { + this._identifier = aIdentifier; + this._enablingPref = aEnablingPref; + + // Enabled by default if a pref for toggling the logger is not given + this._enabled = !this._enablingPref; + + this.init(); } -IdentityLogger.prototype = { +Logger.prototype = { QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]), + init: function Logger_init() { + if (this._enablingPref) { + Services.prefs.addObserver(this._enablingPref, this, false); + this._enabled = Services.prefs.getBoolPref(this._enablingPref); + } + }, + observe: function observe(aSubject, aTopic, aData) { - switch(aTopic) { + switch (aTopic) { case "nsPref:changed": - this._debug = Services.prefs.getBoolPref(PREF_DEBUG); + this._enabled = Services.prefs.getBoolPref(this._enablingPref); + dump("LogUtils " + + (this._enabled ? "enabled" : "disabled") + + " for " + this._identifier + "\n"); break; case "quit-application-granted": - Services.prefs.removeObserver(PREF_DEBUG, this); + Services.prefs.removeObserver(this._enablingPref, this); break; default: @@ -42,28 +53,64 @@ IdentityLogger.prototype = { } }, - _generateLogMessage: function _generateLogMessage(aPrefix, args) { - // create a string representation of a list of arbitrary things + _generatePrefix: function _generatePrefix() { + let caller = Components.stack.caller.caller; + let parts = ['[' + this._identifier + ']']; + + // filename could be like path/to/foo.js or Scratchpad/1 + if (caller.filename) { + let path = caller.filename.split('/'); + if (path[path.length - 1].match(/\./)) { + parts.push(path[path.length - 1]) + } else { + parts.push(caller.filename); + } + } + + // Might not be called from a function; might be top-level + if (caller.name) { + parts.push(caller.name + '()'); + } + + parts.push('line ' + caller.lineNumber + ': '); + + return parts.join(' '); + }, + + _generateLogMessage: function _generateLogMessage(severity, argList) { let strings = []; - - // XXX bug 770418 - args look like flattened array, not list of strings - - args.forEach(function(arg) { - if (typeof arg === 'string') { - strings.push(arg); - } else if (typeof arg === 'undefined') { - strings.push('undefined'); - } else if (arg === null) { + argList.forEach(function(arg) { + if (arg === null) { strings.push('null'); } else { - try { - strings.push(JSON.stringify(arg, null, 2)); - } catch(err) { - strings.push("<>"); + switch (typeof arg) { + case 'string': + strings.push(arg); + break; + case 'undefined': + strings.push('undefined'); + break; + case 'function': + strings.push('<>'); + break; + case 'object': + try { + strings.push(JSON.stringify(arg, null, 2)); + } catch (err) { + strings.push('<>'); + } + break; + default: + try { + strings.push(arg.toString()); + } catch (err) { + strings.push('<>'); + } + break; } } }); - return 'Identity ' + aPrefix + ': ' + strings.join(' '); + return strings.join(' '); }, /** @@ -71,33 +118,61 @@ IdentityLogger.prototype = { * * Enable with about:config pref toolkit.identity.debug */ - log: function log(aPrefix, ...args) { - if (!this._debug) { + log: function log(...argList) { + if (!this._enabled) { return; } - let output = this._generateLogMessage(aPrefix, args); - dump(output + "\n"); + let output = this._generatePrefix() + this._generateLogMessage('info', argList); - // Additionally, make the output visible in the Error Console + // print to the shell console and the browser error console + dump(output + "\n"); Services.console.logStringMessage(output); }, + warning: function Logger_warning(...argList) { + if (!this._enabled) { + return; + } + + let output = this._generatePrefix() + this._generateLogMessage('warning', argList); + }, + /** - * reportError() - report an error through component utils as well as + * error() - report an error through component utils as well as * our log function */ - reportError: function reportError(aPrefix, ...aArgs) { - let prefix = aPrefix + ' ERROR'; + error: function Logger_error(...argList) { + if (!this._enabled) { + return; + } // Report the error in the browser - let output = this._generateLogMessage(aPrefix, aArgs); + let output = this._generatePrefix() + this._generateLogMessage('error', argList); Cu.reportError(output); + + // print to the console dump("ERROR: " + output + "\n"); + dump(" traceback follows:\n"); for (let frame = Components.stack.caller; frame; frame = frame.caller) { dump(frame + "\n"); } } - }; -this.Logger = new IdentityLogger(); +/** + * let logger = getLogger('my component', 'toolkit.foo.debug'); + * logger.log("I would like", 42, "pies", {'and-some': 'object'}); + */ + +let _loggers = {}; + +this.getLogger = function(aIdentifier, aEnablingPref) { + let key = aIdentifier; + if (aEnablingPref) { + key = key + '-' + aEnablingPref; + } + if (!_loggers[key]) { + _loggers[key] = new Logger(aIdentifier, aEnablingPref); + } + return _loggers[key]; +} diff --git a/toolkit/identity/MinimalIdentity.jsm b/toolkit/identity/MinimalIdentity.jsm index 7af57b645af..f78bd66c5a3 100644 --- a/toolkit/identity/MinimalIdentity.jsm +++ b/toolkit/identity/MinimalIdentity.jsm @@ -19,24 +19,15 @@ this.EXPORTED_SYMBOLS = ["IdentityService"]; const Cu = Components.utils; const Ci = Components.interfaces; -const Cc = Components.classes; -const Cr = Components.results; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/identity/LogUtils.jsm"); Cu.import("resource://gre/modules/identity/IdentityUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, - "jwcrypto", - "resource://gre/modules/identity/jwcrypto.jsm"); - -function log(...aMessageArgs) { - Logger.log.apply(Logger, ["minimal core"].concat(aMessageArgs)); -} -function reportError(...aMessageArgs) { - Logger.reportError.apply(Logger, ["core"].concat(aMessageArgs)); -} +XPCOMUtils.defineLazyGetter(this, "logger", function() { + Cu.import('resource://gre/modules/identity/LogUtils.jsm'); + return getLogger("Identity", "toolkit.identity.debug"); +}); function makeMessageObject(aRpCaller) { let options = {}; @@ -64,7 +55,7 @@ function makeMessageObject(aRpCaller) { if ((typeof options.id === 'undefined') || (typeof options.origin === 'undefined')) { let err = "id and origin required in relying-party message: " + JSON.stringify(options); - reportError(err); + logger.error(err); throw new Error(err); } @@ -73,7 +64,6 @@ function makeMessageObject(aRpCaller) { function IDService() { Services.obs.addObserver(this, "quit-application-granted", false); - // Services.obs.addObserver(this, "identity-auth-complete", false); // simplify, it's one object this.RP = this; @@ -88,29 +78,14 @@ function IDService() { IDService.prototype = { QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]), - observe: function observe(aSubject, aTopic, aData) { + observe: function IDService_observe(aSubject, aTopic, aData) { switch (aTopic) { case "quit-application-granted": Services.obs.removeObserver(this, "quit-application-granted"); - // Services.obs.removeObserver(this, "identity-auth-complete"); break; } }, - /** - * Parse an email into username and domain if it is valid, else return null - */ - parseEmail: function parseEmail(email) { - var match = email.match(/^([^@]+)@([^@^/]+.[a-z]+)$/); - if (match) { - return { - username: match[1], - domain: match[2] - }; - } - return null; - }, - /** * Register a listener for a given windowID as a result of a call to * navigator.id.watch(). @@ -130,12 +105,12 @@ IDService.prototype = { * - doCancel() * */ - watch: function watch(aRpCaller) { + watch: function IDService_watch(aRpCaller) { // store the caller structure and notify the UI observers this._rpFlows[aRpCaller.id] = aRpCaller; let options = makeMessageObject(aRpCaller); - log("sending identity-controller-watch:", options); + logger.log("sending identity-controller-watch:", options); Services.obs.notifyObservers({wrappedJSObject: options},"identity-controller-watch", null); }, @@ -143,14 +118,14 @@ IDService.prototype = { * The RP has gone away; remove handles to the hidden iframe. * It's probable that the frame will already have been cleaned up. */ - unwatch: function unwatch(aRpId, aTargetMM) { + unwatch: function IDService_unwatch(aRpId, aTargetMM) { let rp = this._rpFlows[aRpId]; let options = makeMessageObject({ id: aRpId, origin: rp.origin, messageManager: aTargetMM }); - log("sending identity-controller-unwatch for id", options.id, options.origin); + logger.log("sending identity-controller-unwatch for id", options.id, options.origin); Services.obs.notifyObservers({wrappedJSObject: options}, "identity-controller-unwatch", null); }, @@ -164,7 +139,7 @@ IDService.prototype = { * @param aOptions * (Object) options including privacyPolicy, termsOfService */ - request: function request(aRPId, aOptions) { + request: function IDService_request(aRPId, aOptions) { let rp = this._rpFlows[aRPId]; // Notify UX to display identity picker. @@ -182,19 +157,19 @@ IDService.prototype = { * (integer) the id of the doc object obtained in .watch() * */ - logout: function logout(aRpCallerId) { + logout: function IDService_logout(aRpCallerId) { let rp = this._rpFlows[aRpCallerId]; let options = makeMessageObject(rp); Services.obs.notifyObservers({wrappedJSObject: options}, "identity-controller-logout", null); }, - childProcessShutdown: function childProcessShutdown(messageManager) { + childProcessShutdown: function IDService_childProcessShutdown(messageManager) { let options = makeMessageObject({messageManager: messageManager, id: null, origin: null}); Services.obs.notifyObservers({wrappedJSObject: options}, "identity-child-process-shutdown", null); Object.keys(this._rpFlows).forEach(function(key) { if (this._rpFlows[key]._mm === messageManager) { - log("child process shutdown for rp", key, "- deleting flow"); + logger.log("child process shutdown for rp", key, "- deleting flow"); delete this._rpFlows[key]; } }, this); @@ -206,7 +181,7 @@ IDService.prototype = { * following functions (doLogin, doLogout, or doReady) */ - doLogin: function doLogin(aRpCallerId, aAssertion, aInternalParams) { + doLogin: function IDService_doLogin(aRpCallerId, aAssertion, aInternalParams) { let rp = this._rpFlows[aRpCallerId]; if (!rp) { dump("WARNING: doLogin found no rp to go with callerId " + aRpCallerId + "\n"); @@ -216,7 +191,7 @@ IDService.prototype = { rp.doLogin(aAssertion, aInternalParams); }, - doLogout: function doLogout(aRpCallerId) { + doLogout: function IDService_doLogout(aRpCallerId) { let rp = this._rpFlows[aRpCallerId]; if (!rp) { dump("WARNING: doLogout found no rp to go with callerId " + aRpCallerId + "\n"); @@ -226,7 +201,7 @@ IDService.prototype = { rp.doLogout(); }, - doReady: function doReady(aRpCallerId) { + doReady: function IDService_doReady(aRpCallerId) { let rp = this._rpFlows[aRpCallerId]; if (!rp) { dump("WARNING: doReady found no rp to go with callerId " + aRpCallerId + "\n"); @@ -236,7 +211,7 @@ IDService.prototype = { rp.doReady(); }, - doCancel: function doCancel(aRpCallerId) { + doCancel: function IDService_doCancel(aRpCallerId) { let rp = this._rpFlows[aRpCallerId]; if (!rp) { dump("WARNING: doCancel found no rp to go with callerId " + aRpCallerId + "\n"); @@ -244,202 +219,7 @@ IDService.prototype = { } rp.doCancel(); - }, - - - /* - * XXX Bug 804229: Implement Identity Provider Functions - * - * Stubs for Identity Provider functions follow - */ - - /** - * the provisioning iframe sandbox has called navigator.id.beginProvisioning() - * - * @param aCaller - * (object) the iframe sandbox caller with all callbacks and - * other information. Callbacks include: - * - doBeginProvisioningCallback(id, duration_s) - * - doGenKeyPairCallback(pk) - */ - beginProvisioning: function beginProvisioning(aCaller) { - }, - - /** - * the provisioning iframe sandbox has called - * navigator.id.raiseProvisioningFailure() - * - * @param aProvId - * (int) the identifier of the provisioning flow tied to that sandbox - * @param aReason - */ - raiseProvisioningFailure: function raiseProvisioningFailure(aProvId, aReason) { - reportError("Provisioning failure", aReason); - }, - - /** - * When navigator.id.genKeyPair is called from provisioning iframe sandbox. - * Generates a keypair for the current user being provisioned. - * - * @param aProvId - * (int) the identifier of the provisioning caller tied to that sandbox - * - * It is an error to call genKeypair without receiving the callback for - * the beginProvisioning() call first. - */ - genKeyPair: function genKeyPair(aProvId) { - }, - - /** - * When navigator.id.registerCertificate is called from provisioning iframe - * sandbox. - * - * Sets the certificate for the user for which a certificate was requested - * via a preceding call to beginProvisioning (and genKeypair). - * - * @param aProvId - * (integer) the identifier of the provisioning caller tied to that - * sandbox - * - * @param aCert - * (String) A JWT representing the signed certificate for the user - * being provisioned, provided by the IdP. - */ - registerCertificate: function registerCertificate(aProvId, aCert) { - }, - - /** - * The authentication frame has called navigator.id.beginAuthentication - * - * IMPORTANT: the aCaller is *always* non-null, even if this is called from - * a regular content page. We have to make sure, on every DOM call, that - * aCaller is an expected authentication-flow identifier. If not, we throw - * an error or something. - * - * @param aCaller - * (object) the authentication caller - * - */ - beginAuthentication: function beginAuthentication(aCaller) { - }, - - /** - * The auth frame has called navigator.id.completeAuthentication - * - * @param aAuthId - * (int) the identifier of the authentication caller tied to that sandbox - * - */ - completeAuthentication: function completeAuthentication(aAuthId) { - }, - - /** - * The auth frame has called navigator.id.cancelAuthentication - * - * @param aAuthId - * (int) the identifier of the authentication caller - * - */ - cancelAuthentication: function cancelAuthentication(aAuthId) { - }, - - // methods for chrome and add-ons - - /** - * Discover the IdP for an identity - * - * @param aIdentity - * (string) the email we're logging in with - * - * @param aCallback - * (function) callback to invoke on completion - * with first-positional parameter the error. - */ - _discoverIdentityProvider: function _discoverIdentityProvider(aIdentity, aCallback) { - // XXX bug 767610 - validate email address call - // When that is available, we can remove this custom parser - var parsedEmail = this.parseEmail(aIdentity); - if (parsedEmail === null) { - return aCallback("Could not parse email: " + aIdentity); - } - log("_discoverIdentityProvider: identity:", aIdentity, "domain:", parsedEmail.domain); - - this._fetchWellKnownFile(parsedEmail.domain, function fetchedWellKnown(err, idpParams) { - // idpParams includes the pk, authorization url, and - // provisioning url. - - // XXX bug 769861 follow any authority delegations - // if no well-known at any point in the delegation - // fall back to browserid.org as IdP - return aCallback(err, idpParams); - }); - }, - - /** - * Fetch the well-known file from the domain. - * - * @param aDomain - * - * @param aScheme - * (string) (optional) Protocol to use. Default is https. - * This is necessary because we are unable to test - * https. - * - * @param aCallback - * - */ - _fetchWellKnownFile: function _fetchWellKnownFile(aDomain, aCallback, aScheme='https') { - // XXX bug 769854 make tests https and remove aScheme option - let url = aScheme + '://' + aDomain + "/.well-known/browserid"; - log("_fetchWellKnownFile:", url); - - // this appears to be a more successful way to get at xmlhttprequest (which supposedly will close with a window - let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"] - .createInstance(Ci.nsIXMLHttpRequest); - - // XXX bug 769865 gracefully handle being off-line - // XXX bug 769866 decide on how to handle redirects - req.open("GET", url, true); - req.responseType = "json"; - req.mozBackgroundRequest = true; - req.onload = function _fetchWellKnownFile_onload() { - if (req.status < 200 || req.status >= 400) { - log("_fetchWellKnownFile", url, ": server returned status:", req.status); - return aCallback("Error"); - } - try { - let idpParams = req.response; - - // Verify that the IdP returned a valid configuration - if (! (idpParams.provisioning && - idpParams.authentication && - idpParams['public-key'])) { - let errStr= "Invalid well-known file from: " + aDomain; - log("_fetchWellKnownFile:", errStr); - return aCallback(errStr); - } - - let callbackObj = { - domain: aDomain, - idpParams: idpParams, - }; - log("_fetchWellKnownFile result: ", callbackObj); - // Yay. Valid IdP configuration for the domain. - return aCallback(null, callbackObj); - - } catch (err) { - reportError("_fetchWellKnownFile", "Bad configuration from", aDomain, err); - return aCallback(err.toString()); - } - }; - req.onerror = function _fetchWellKnownFile_onerror() { - log("_fetchWellKnownFile", "ERROR:", req.status, req.statusText); - log("ERROR: _fetchWellKnownFile:", err); - return aCallback("Error"); - }; - req.send(null); - }, - + } }; this.IdentityService = new IDService(); diff --git a/toolkit/identity/RelyingParty.jsm b/toolkit/identity/RelyingParty.jsm index 2a26daca105..a2cde17aba4 100644 --- a/toolkit/identity/RelyingParty.jsm +++ b/toolkit/identity/RelyingParty.jsm @@ -13,7 +13,6 @@ const Cr = Components.results; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/identity/LogUtils.jsm"); Cu.import("resource://gre/modules/identity/IdentityUtils.jsm"); Cu.import("resource://gre/modules/identity/IdentityStore.jsm"); @@ -23,12 +22,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "jwcrypto", "resource://gre/modules/identity/jwcrypto.jsm"); -function log(...aMessageArgs) { - Logger.log.apply(Logger, ["RP"].concat(aMessageArgs)); -} -function reportError(...aMessageArgs) { - Logger.reportError.apply(Logger, ["RP"].concat(aMessageArgs)); -} +XPCOMUtils.defineLazyGetter(this, "logger", function() { + Cu.import('resource://gre/modules/identity/LogUtils.jsm'); + return getLogger("Identity RP", "toolkit.identity.debug"); +}); function IdentityRelyingParty() { // The store is a singleton shared among Identity, RelyingParty, and @@ -87,7 +84,7 @@ IdentityRelyingParty.prototype = { let origin = aRpCaller.origin; let state = this._store.getLoginState(origin) || { isLoggedIn: false, email: null }; - log("watch: rpId:", aRpCaller.id, + logger.log("watch: rpId:", aRpCaller.id, "origin:", origin, "loggedInUser:", aRpCaller.loggedInUser, "loggedIn:", state.isLoggedIn, @@ -139,7 +136,7 @@ IdentityRelyingParty.prototype = { * Note that this calls _getAssertion */ _doLogin: function _doLogin(aRpCaller, aOptions, aAssertion) { - log("_doLogin: rpId:", aRpCaller.id, "origin:", aOptions.origin); + logger.log("_doLogin: rpId:", aRpCaller.id, "origin:", aOptions.origin); let loginWithAssertion = function loginWithAssertion(assertion) { this._store.setLoginState(aOptions.origin, true, aOptions.loggedInUser); @@ -153,7 +150,7 @@ IdentityRelyingParty.prototype = { } else { this._getAssertion(aOptions, function gotAssertion(err, assertion) { if (err) { - reportError("_doLogin:", "Failed to get assertion on login attempt:", err); + logger.warning("_doLogin:", "Failed to get assertion on login attempt:", err); this._doLogout(aRpCaller); } else { loginWithAssertion(assertion); @@ -167,7 +164,7 @@ IdentityRelyingParty.prototype = { * on logout. */ _doLogout: function _doLogout(aRpCaller, aOptions) { - log("_doLogout: rpId:", aRpCaller.id, "origin:", aOptions.origin); + logger.log("_doLogout: rpId:", aRpCaller.id, "origin:", aOptions.origin); let state = this._store.getLoginState(aOptions.origin) || {}; @@ -191,7 +188,7 @@ IdentityRelyingParty.prototype = { * (string) The email of the user whose login state has changed */ _notifyLoginStateChanged: function _notifyLoginStateChanged(aRpCallerId, aIdentity) { - log("_notifyLoginStateChanged: rpId:", aRpCallerId, "identity:", aIdentity); + logger.log("_notifyLoginStateChanged: rpId:", aRpCallerId, "identity:", aIdentity); let options = {rpId: aRpCallerId}; Services.obs.notifyObservers({wrappedJSObject: options}, @@ -210,7 +207,7 @@ IdentityRelyingParty.prototype = { * (Object) options including privacyPolicy, termsOfService */ request: function request(aRPId, aOptions) { - log("request: rpId:", aRPId); + logger.log("request: rpId:", aRPId); let rp = this._rpFlows[aRPId]; // Notify UX to display identity picker. @@ -238,14 +235,14 @@ IdentityRelyingParty.prototype = { * */ logout: function logout(aRpCallerId) { - log("logout: RP caller id:", aRpCallerId); + logger.log("logout: RP caller id:", aRpCallerId); let rp = this._rpFlows[aRpCallerId]; if (rp && rp.origin) { let origin = rp.origin; - log("logout: origin:", origin); + logger.log("logout: origin:", origin); this._doLogout(rp, {origin: origin}); } else { - log("logout: no RP found with id:", aRpCallerId); + logger.log("logout: no RP found with id:", aRpCallerId); } // We don't delete this._rpFlows[aRpCallerId], because // the user might log back in again. @@ -254,7 +251,7 @@ IdentityRelyingParty.prototype = { getDefaultEmailForOrigin: function getDefaultEmailForOrigin(aOrigin) { let identities = this.getIdentitiesForSite(aOrigin); let result = identities.lastUsed || null; - log("getDefaultEmailForOrigin:", aOrigin, "->", result); + logger.log("getDefaultEmailForOrigin:", aOrigin, "->", result); return result; }, @@ -293,7 +290,7 @@ IdentityRelyingParty.prototype = { _getAssertion: function _getAssertion(aOptions, aCallback) { let audience = aOptions.origin; let email = aOptions.loggedInUser || this.getDefaultEmailForOrigin(audience); - log("_getAssertion: audience:", audience, "email:", email); + logger.log("_getAssertion: audience:", audience, "email:", email); if (!audience) { throw "audience required for _getAssertion"; } @@ -307,9 +304,9 @@ IdentityRelyingParty.prototype = { if (cert) { this._generateAssertion(audience, email, function generatedAssertion(err, assertion) { if (err) { - log("ERROR: _getAssertion:", err); + logger.warning("ERROR: _getAssertion:", err); } - log("_getAssertion: generated assertion:", assertion); + logger.log("_getAssertion: generated assertion:", assertion); return aCallback(err, assertion); }); } @@ -331,12 +328,12 @@ IdentityRelyingParty.prototype = { * with first-positional parameter the error. */ _generateAssertion: function _generateAssertion(aAudience, aIdentity, aCallback) { - log("_generateAssertion: audience:", aAudience, "identity:", aIdentity); + logger.log("_generateAssertion: audience:", aAudience, "identity:", aIdentity); let id = this._store.fetchIdentity(aIdentity); if (! (id && id.cert)) { let errStr = "Cannot generate an assertion without a certificate"; - log("ERROR: _generateAssertion:", errStr); + logger.log("ERROR: _generateAssertion:", errStr); aCallback(errStr); return; } @@ -345,7 +342,7 @@ IdentityRelyingParty.prototype = { if (!kp) { let errStr = "Cannot generate an assertion without a keypair"; - log("ERROR: _generateAssertion:", errStr); + logger.log("ERROR: _generateAssertion:", errStr); aCallback(errStr); return; } @@ -361,7 +358,7 @@ IdentityRelyingParty.prototype = { if (rp) { delete rp['provId']; } else { - log("Error: Couldn't delete provision flow ", aProvId, " for RP ", aRPId); + logger.log("Error: Couldn't delete provision flow ", aProvId, " for RP ", aRPId); } }, diff --git a/toolkit/identity/Sandbox.jsm b/toolkit/identity/Sandbox.jsm index 4fe2d89c8ed..8d7f26152e2 100644 --- a/toolkit/identity/Sandbox.jsm +++ b/toolkit/identity/Sandbox.jsm @@ -13,9 +13,10 @@ const XHTML_NS = "http://www.w3.org/1999/xhtml"; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, - "Logger", - "resource://gre/modules/identity/LogUtils.jsm"); +XPCOMUtils.defineLazyGetter(this, "logger", function() { + Cu.import('resource://gre/modules/identity/LogUtils.jsm'); + return getLogger("Identity", "toolkit.identity.debug"); +}); /** * An object that represents a sandbox in an iframe loaded with aURL. The @@ -34,7 +35,7 @@ XPCOMUtils.defineLazyModuleGetter(this, this.Sandbox = function Sandbox(aURL, aCallback) { // Normalize the URL so the comparison in _makeSandboxContentLoaded works this._url = Services.io.newURI(aURL, null, null).spec; - this._log("Creating sandbox for:", this._url); + logger.log("Creating sandbox for:", this._url); this._createFrame(); this._createSandbox(aCallback); }; @@ -54,9 +55,9 @@ this.Sandbox.prototype = { * id and URL). */ reload: function Sandbox_reload(aCallback) { - this._log("reload:", this.id, ":", this._url); + logger.log("reload:", this.id, ":", this._url); this._createSandbox(function createdSandbox(aSandbox) { - this._log("reloaded sandbox id:", aSandbox.id); + logger.log("reloaded sandbox id:", aSandbox.id); aCallback(aSandbox); }.bind(this)); }, @@ -65,7 +66,7 @@ this.Sandbox.prototype = { * Frees the sandbox and releases the iframe created to host it. */ free: function Sandbox_free() { - this._log("free:", this.id); + logger.log("free:", this.id); this._container.removeChild(this._frame); this._frame = null; this._container = null; @@ -115,7 +116,7 @@ this.Sandbox.prototype = { _createSandbox: function Sandbox__createSandbox(aCallback) { let self = this; function _makeSandboxContentLoaded(event) { - self._log("_makeSandboxContentLoaded:", self.id, + logger.log("_makeSandboxContentLoaded:", self.id, event.target.location.toString()); if (event.target != self._frame.contentDocument) { return; @@ -144,10 +145,5 @@ this.Sandbox.prototype = { null // headers ); - }, - - _log: function Sandbox__log(...aMessageArgs) { - Logger.log.apply(Logger, ["sandbox"].concat(aMessageArgs)); - }, - + } }; diff --git a/toolkit/identity/jwcrypto.jsm b/toolkit/identity/jwcrypto.jsm index e20bc1672db..1fb28c6aada 100644 --- a/toolkit/identity/jwcrypto.jsm +++ b/toolkit/identity/jwcrypto.jsm @@ -14,7 +14,11 @@ const Cr = Components.results; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/identity/LogUtils.jsm"); + +XPCOMUtils.defineLazyGetter(this, "logger", function() { + Cu.import('resource://gre/modules/identity/LogUtils.jsm'); + return getLogger("Identity test", "toolkit.identity.debug"); +}); XPCOMUtils.defineLazyServiceGetter(this, "IdentityCryptoService", @@ -25,12 +29,8 @@ this.EXPORTED_SYMBOLS = ["jwcrypto"]; const ALGORITHMS = { RS256: "RS256", DS160: "DS160" }; -function log(...aMessageArgs) { - Logger.log.apply(Logger, ["jwcrypto"].concat(aMessageArgs)); -} - function generateKeyPair(aAlgorithmName, aCallback) { - log("Generate key pair; alg =", aAlgorithmName); + logger.log("Generate key pair; alg =", aAlgorithmName); IdentityCryptoService.generateKeyPair(aAlgorithmName, function(rv, aKeyPair) { if (!Components.isSuccessCode(rv)) { @@ -74,10 +74,10 @@ function generateKeyPair(aAlgorithmName, aCallback) { function sign(aPayload, aKeypair, aCallback) { aKeypair._kp.sign(aPayload, function(rv, signature) { if (!Components.isSuccessCode(rv)) { - log("ERROR: signer.sign failed"); + logger.warning("ERROR: signer.sign failed"); return aCallback("Sign failed"); } - log("signer.sign: success"); + logger.log("signer.sign: success"); return aCallback(null, signature); }); } @@ -93,7 +93,7 @@ jwcryptoClass.prototype = { }, generateKeyPair: function(aAlgorithmName, aCallback) { - log("generating"); + logger.log("generating"); generateKeyPair(aAlgorithmName, aCallback); }, @@ -113,7 +113,7 @@ jwcryptoClass.prototype = { var payloadBytes = IdentityCryptoService.base64UrlEncode( JSON.stringify(payload)); - log("payload bytes", payload, payloadBytes); + logger.log("payload bytes", payload, payloadBytes); sign(headerBytes + "." + payloadBytes, aKeyPair, function(err, signature) { if (err) return aCallback(err); diff --git a/toolkit/identity/tests/unit/head_identity.js b/toolkit/identity/tests/unit/head_identity.js index c226a85ddc8..45f97498e3d 100644 --- a/toolkit/identity/tests/unit/head_identity.js +++ b/toolkit/identity/tests/unit/head_identity.js @@ -25,10 +25,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "IdentityStore", "resource://gre/modules/identity/IdentityStore.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, - "Logger", - "resource://gre/modules/identity/LogUtils.jsm"); - XPCOMUtils.defineLazyServiceGetter(this, "uuidGenerator", "@mozilla.org/uuid-generator;1", @@ -75,10 +71,13 @@ registrar.registerFactory(Components.ID("{fbfae60b-64a4-44ef-a911-08ceb70b9f31}" XULAppInfoFactory); // The following are utility functions for Identity testing +// +XPCOMUtils.defineLazyGetter(this, "logger", function() { + Cu.import('resource://gre/modules/identity/LogUtils.jsm'); + return getLogger("Identity test", "toolkit.identity.debug"); +}); -function log(...aMessageArgs) { - Logger.log.apply(Logger, ["test"].concat(aMessageArgs)); -} +var log = logger.log; function get_idstore() { return IdentityStore; diff --git a/toolkit/identity/tests/unit/test_crypto_service.js b/toolkit/identity/tests/unit/test_crypto_service.js index dc5a49b7168..8b26da5a6c4 100644 --- a/toolkit/identity/tests/unit/test_crypto_service.js +++ b/toolkit/identity/tests/unit/test_crypto_service.js @@ -5,7 +5,11 @@ Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import('resource://gre/modules/identity/LogUtils.jsm'); + +XPCOMUtils.defineLazyGetter(this, "logger", function() { + Cu.import('resource://gre/modules/identity/LogUtils.jsm'); + return getLogger("Identity test", "toolkit.identity.debug"); +}); const idService = Cc["@mozilla.org/identity/crypto-service;1"] .getService(Ci.nsIIdentityCryptoService); @@ -20,7 +24,7 @@ function do_check_eq_or_slightly_less(x, y) { function test_dsa() { idService.generateKeyPair(ALG_DSA, function (rv, keyPair) { - log("DSA generateKeyPair finished ", rv); + logger.log("DSA generateKeyPair finished ", rv); do_check_true(Components.isSuccessCode(rv)); do_check_eq(typeof keyPair.sign, "function"); do_check_eq(keyPair.keyType, ALG_DSA); @@ -30,9 +34,9 @@ function test_dsa() { do_check_eq_or_slightly_less(keyPair.hexDSAPublicValue.length, 1024 / 8 * 2); // XXX: test that RSA parameters throw the correct error - log("about to sign with DSA key"); + logger.log("about to sign with DSA key"); keyPair.sign("foo", function (rv, signature) { - log("DSA sign finished ", rv, signature); + logger.log("DSA sign finished ", rv, signature); do_check_true(Components.isSuccessCode(rv)); do_check_true(signature.length > 1); // TODO: verify the signature with the public key @@ -43,7 +47,7 @@ function test_dsa() { function test_rsa() { idService.generateKeyPair(ALG_RSA, function (rv, keyPair) { - log("RSA generateKeyPair finished ", rv); + logger.log("RSA generateKeyPair finished ", rv); do_check_true(Components.isSuccessCode(rv)); do_check_eq(typeof keyPair.sign, "function"); do_check_eq(keyPair.keyType, ALG_RSA); @@ -51,9 +55,9 @@ function test_rsa() { 2048 / 8); do_check_true(keyPair.hexRSAPublicKeyExponent.length > 1); - log("about to sign with RSA key"); + logger.log("about to sign with RSA key"); keyPair.sign("foo", function (rv, signature) { - log("RSA sign finished ", rv, signature); + logger.log("RSA sign finished ", rv, signature); do_check_true(Components.isSuccessCode(rv)); do_check_true(signature.length > 1); run_next_test(); diff --git a/toolkit/identity/tests/unit/test_jwcrypto.js b/toolkit/identity/tests/unit/test_jwcrypto.js index 309ef266808..2d8a257721a 100644 --- a/toolkit/identity/tests/unit/test_jwcrypto.js +++ b/toolkit/identity/tests/unit/test_jwcrypto.js @@ -3,8 +3,6 @@ "use strict" -Cu.import('resource://gre/modules/identity/LogUtils.jsm'); - XPCOMUtils.defineLazyModuleGetter(this, "IDService", "resource://gre/modules/identity/Identity.jsm", "IdentityService"); @@ -12,6 +10,11 @@ XPCOMUtils.defineLazyModuleGetter(this, "IDService", XPCOMUtils.defineLazyModuleGetter(this, "jwcrypto", "resource://gre/modules/identity/jwcrypto.jsm"); +XPCOMUtils.defineLazyGetter(this, "logger", function() { + Cu.import('resource://gre/modules/identity/LogUtils.jsm'); + return getLogger("Identity test", "toolkit.identity.debug"); +}); + const RP_ORIGIN = "http://123done.org"; const INTERNAL_ORIGIN = "browserid://"; @@ -47,7 +50,7 @@ function test_get_assertion() { do_check_null(err); // more checks on assertion - log("assertion", assertion); + logger.log("assertion", assertion); do_test_finished(); run_next_test(); @@ -59,7 +62,7 @@ function test_rsa() { do_test_pending(); function checkRSA(err, kpo) { do_check_neq(kpo, undefined); - log(kpo.serializedPublicKey); + logger.log(kpo.serializedPublicKey); let pk = JSON.parse(kpo.serializedPublicKey); do_check_eq(pk.algorithm, "RS"); /* TODO @@ -89,7 +92,7 @@ function test_dsa() { do_test_pending(); function checkDSA(err, kpo) { do_check_neq(kpo, undefined); - log(kpo.serializedPublicKey); + logger.log(kpo.serializedPublicKey); let pk = JSON.parse(kpo.serializedPublicKey); do_check_eq(pk.algorithm, "DS"); /* TODO diff --git a/toolkit/identity/tests/unit/test_log_utils.js b/toolkit/identity/tests/unit/test_log_utils.js index 6c40cdadc33..aa247baf7ae 100644 --- a/toolkit/identity/tests/unit/test_log_utils.js +++ b/toolkit/identity/tests/unit/test_log_utils.js @@ -3,7 +3,11 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import('resource://gre/modules/Services.jsm'); -Cu.import('resource://gre/modules/identity/LogUtils.jsm'); + +XPCOMUtils.defineLazyGetter(this, "logger", function() { + Cu.import('resource://gre/modules/identity/LogUtils.jsm'); + return getLogger("Identity test", "toolkit.identity.debug"); +}); function toggle_debug() { do_test_pending(); @@ -17,7 +21,7 @@ function toggle_debug() { observe: function observe(aSubject, aTopic, aData) { if (aTopic === "nsPref:changed") { // race condition? - do_check_eq(Logger._debug, true); + do_check_eq(logger._enabled, true); do_test_finished(); run_next_test(); } @@ -34,41 +38,36 @@ function toggle_debug() { // test that things don't break -function logAlias(...args) { - Logger.log.apply(Logger, ["log alias"].concat(args)); -} -function reportErrorAlias(...args) { - Logger.reportError.apply(Logger, ["report error alias"].concat(args)); -} - function test_log() { - Logger.log("log test", "I like pie"); + logger.log("log test", "I like pie"); do_test_finished(); run_next_test(); } -function test_reportError() { - Logger.reportError("log test", "We are out of pies!!!"); +function test_warning() { + logger.warning("similar log test", "We are still out of pies!!!"); do_test_finished(); run_next_test(); } -function test_wrappers() { - logAlias("I like potatoes"); +function test_error() { + logger.error("My head a splode"); do_test_finished(); - reportErrorAlias("Too much red bull"); + run_next_test(); } + let TESTS = [ // XXX fix me // toggle_debug, test_log, - test_reportError, - test_wrappers + test_warning, + test_error ]; TESTS.forEach(add_test); function run_test() { run_next_test(); -} \ No newline at end of file +} + diff --git a/toolkit/identity/tests/unit/test_minimalidentity.js b/toolkit/identity/tests/unit/test_minimalidentity.js index 576cbaf8e3c..e60937b8bb4 100644 --- a/toolkit/identity/tests/unit/test_minimalidentity.js +++ b/toolkit/identity/tests/unit/test_minimalidentity.js @@ -4,12 +4,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "MinimalIDService", "resource://gre/modules/identity/MinimalIdentity.jsm", "IdentityService"); -Cu.import("resource://gre/modules/identity/LogUtils.jsm"); - -function log(...aMessageArgs) { - Logger.log.apply(Logger, ["test_minimalidentity"].concat(aMessageArgs)); -} - function test_overall() { do_check_neq(MinimalIDService, null); run_next_test();