mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 845546 - Port b2g identity implementation to desktop. r=benadida
This commit is contained in:
parent
ecad0ec815
commit
a81b79511e
149
browser/base/content/browser-identity.js
Normal file
149
browser/base/content/browser-identity.js
Normal file
@ -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();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -1122,254 +1122,60 @@
|
||||
</implementation>
|
||||
</binding>
|
||||
|
||||
<binding id="identity-request-notification" extends="chrome://global/content/bindings/notification.xml#popup-notification">
|
||||
<content align="start">
|
||||
<binding
|
||||
id="identity-request-notification"
|
||||
extends="chrome://global/content/bindings/notification.xml#popup-notification">
|
||||
|
||||
<xul:image class="popup-notification-icon"
|
||||
xbl:inherits="popupid,src=icon"/>
|
||||
|
||||
<xul:vbox flex="1">
|
||||
<xul:vbox anonid="identity-deck">
|
||||
<xul:vbox flex="1" pack="center"> <!-- 1: add an email -->
|
||||
<html:input type="email" anonid="email" required="required" size="30"/>
|
||||
<xul:description anonid="newidentitydesc"/>
|
||||
<xul:spacer flex="1"/>
|
||||
<xul:label class="text-link custom-link small-margin" anonid="chooseemail" hidden="true"/>
|
||||
</xul:vbox>
|
||||
<xul:vbox flex="1" hidden="true"> <!-- 2: choose an email -->
|
||||
<xul:description anonid="chooseidentitydesc"/>
|
||||
<xul:radiogroup anonid="identities">
|
||||
</xul:radiogroup>
|
||||
<xul:label class="text-link custom-link" anonid="newemail"/>
|
||||
</xul:vbox>
|
||||
</xul:vbox>
|
||||
<xul:hbox class="popup-notification-button-container"
|
||||
pack="end" align="center">
|
||||
<xul:label anonid="tos" class="text-link" hidden="true"/>
|
||||
<xul:label anonid="privacypolicy" class="text-link" hidden="true"/>
|
||||
<xul:spacer flex="1"/>
|
||||
<xul:image anonid="throbber" src="chrome://browser/skin/tabbrowser/loading.png"
|
||||
style="visibility:hidden" width="16" height="16"/>
|
||||
<xul:button anonid="button"
|
||||
type="menu-button"
|
||||
class="popup-notification-menubutton"
|
||||
xbl:inherits="oncommand=buttoncommand,label=buttonlabel,accesskey=buttonaccesskey">
|
||||
<xul:menupopup anonid="menupopup"
|
||||
xbl:inherits="oncommand=menucommand">
|
||||
<children/>
|
||||
<xul:menuitem class="menuitem-iconic popup-notification-closeitem"
|
||||
label="&closeNotificationItem.label;"
|
||||
xbl:inherits="oncommand=closeitemcommand"/>
|
||||
</xul:menupopup>
|
||||
</xul:button>
|
||||
</xul:hbox>
|
||||
</xul:vbox>
|
||||
<xul:vbox pack="start">
|
||||
<xul:toolbarbutton anonid="closebutton"
|
||||
class="messageCloseButton popup-notification-closebutton tabbable"
|
||||
xbl:inherits="oncommand=closebuttoncommand"
|
||||
tooltiptext="&closeNotification.tooltip;"/>
|
||||
</xul:vbox>
|
||||
<content>
|
||||
<panel id="persona-container" anonid="persona-container" flex="1" />
|
||||
</content>
|
||||
<implementation>
|
||||
|
||||
<implementation implements="nsIObserver, nsIDOMEventListener">
|
||||
<constructor><![CDATA[
|
||||
// this.notification.options.identity is used to pass identity-specific info to the binding
|
||||
let origin = this.identity.origin
|
||||
dump(" ** in identity xul constructor\n");
|
||||
this.complete = false;
|
||||
|
||||
// Populate text
|
||||
this.emailField.placeholder = gNavigatorBundle.
|
||||
getString("identity.newIdentity.email.placeholder");
|
||||
this.newIdentityDesc.textContent = gNavigatorBundle.getFormattedString(
|
||||
"identity.newIdentity.description", [origin]);
|
||||
this.chooseIdentityDesc.textContent = gNavigatorBundle.getFormattedString(
|
||||
"identity.chooseIdentity.description", [origin]);
|
||||
// Mark outgoing messages with the id of the caller
|
||||
this.messageSubject = Components.classes["@mozilla.org/supports-string;1"]
|
||||
.createInstance(Components.interfaces.nsISupportsString);
|
||||
this.messageSubject.data = this.notification.options.context.id;
|
||||
|
||||
// Show optional terms of service and privacy policy links
|
||||
this._populateLink(this.identity.termsOfService, "tos", "identity.termsOfService");
|
||||
this._populateLink(this.identity.privacyPolicy, "privacypolicy", "identity.privacyPolicy");
|
||||
// adopt the iframe and display it in the panel
|
||||
// XXX this does not work in FF3.6 or older
|
||||
let personaIframe = this.notification.options.context.iframe;
|
||||
let node = document.adoptNode(personaIframe);
|
||||
let panel = document.getAnonymousElementByAttribute(this, "anonid", "persona-container");
|
||||
panel.appendChild(node);
|
||||
|
||||
// Populate the list of identities to choose from. The origin is used to provide
|
||||
// better suggestions.
|
||||
let identities = this.SignInToWebsiteUX.getIdentitiesForSite(origin);
|
||||
// The dimensions of the panel are modified dynamically by
|
||||
// SignInToWebsite.jsm.
|
||||
|
||||
this._populateIdentityList(identities);
|
||||
dump(" ** Persona host iframe attached to xul panel\n");
|
||||
|
||||
if (typeof this.step == "undefined") {
|
||||
// First opening of this notification
|
||||
// Show the add email pane (0) if there are no existing identities otherwise show the list
|
||||
this.step = "result" in identities && identities.result.length ? 1 : 0;
|
||||
} else {
|
||||
// Already opened so restore previous state
|
||||
if (this.identity.typedEmail) {
|
||||
this.emailField.value = this.identity.typedEmail;
|
||||
}
|
||||
if (this.identity.selected) {
|
||||
// If the user already chose an identity then update the UI to reflect that
|
||||
this.onIdentitySelected();
|
||||
}
|
||||
// Update the view for the step
|
||||
this.step = this.step;
|
||||
}
|
||||
// Listen to messages from SignInToWebsite.jsm
|
||||
Services.obs.addObserver(this, "identity-delegate-ui-close", false);
|
||||
|
||||
// Fire notification with the chosen identity when main button is clicked
|
||||
this.button.addEventListener("command", this._onButtonCommand.bind(this), true);
|
||||
|
||||
// Do the same if enter is pressed in the email field
|
||||
this.emailField.addEventListener("keypress", function emailFieldKeypress(aEvent) {
|
||||
if (aEvent.keyCode != aEvent.DOM_VK_RETURN)
|
||||
return;
|
||||
this._onButtonCommand(aEvent);
|
||||
}.bind(this));
|
||||
|
||||
this.addEmailLink.value = gNavigatorBundle.getString("identity.newIdentity.label");
|
||||
this.addEmailLink.accessKey = gNavigatorBundle.getString("identity.newIdentity.accessKey");
|
||||
this.addEmailLink.addEventListener("click", function addEmailClick(evt) {
|
||||
this.step = 0;
|
||||
}.bind(this));
|
||||
|
||||
this.chooseEmailLink.value = gNavigatorBundle.getString("identity.chooseIdentity.label");
|
||||
this.chooseEmailLink.hidden = !("result" in identities && identities.result.length);
|
||||
this.chooseEmailLink.addEventListener("click", function chooseEmailClick(evt) {
|
||||
this.step = 1;
|
||||
}.bind(this));
|
||||
|
||||
this.emailField.addEventListener("blur", function onEmailBlur() {
|
||||
this.identity.typedEmail = this.emailField.value;
|
||||
}.bind(this));
|
||||
// message back to SignInToWebsite that we've started
|
||||
// and the flow with the given id can go ahead
|
||||
// XXX we might not need this
|
||||
Services.obs.notifyObservers(this.messageSubject, "identity-delegate-ui-open", null);
|
||||
]]></constructor>
|
||||
|
||||
<field name="SignInToWebsiteUX" readonly="true">
|
||||
let sitw = {};
|
||||
Components.utils.import("resource:///modules/SignInToWebsite.jsm", sitw);
|
||||
sitw.SignInToWebsiteUX;
|
||||
</field>
|
||||
<destructor><![CDATA[
|
||||
if (!this.complete) {
|
||||
Services.obs.notifyObservers(this.messageSubject, "identity-delegate-canceled", null);
|
||||
}
|
||||
Services.obs.removeObserver(this, "identity-delegate-ui-close", false);
|
||||
]]></destructor>
|
||||
|
||||
<field name="newIdentityDesc" readonly="true">
|
||||
document.getAnonymousElementByAttribute(this, "anonid", "newidentitydesc");
|
||||
</field>
|
||||
|
||||
<field name="chooseIdentityDesc" readonly="true">
|
||||
document.getAnonymousElementByAttribute(this, "anonid", "chooseidentitydesc");
|
||||
</field>
|
||||
|
||||
<field name="identityList" readonly="true">
|
||||
document.getAnonymousElementByAttribute(this, "anonid", "identities");
|
||||
</field>
|
||||
|
||||
<field name="emailField" readonly="true">
|
||||
document.getAnonymousElementByAttribute(this, "anonid", "email");
|
||||
</field>
|
||||
|
||||
<field name="addEmailLink" readonly="true">
|
||||
document.getAnonymousElementByAttribute(this, "anonid", "newemail");
|
||||
</field>
|
||||
|
||||
<field name="chooseEmailLink" readonly="true">
|
||||
document.getAnonymousElementByAttribute(this, "anonid", "chooseemail");
|
||||
</field>
|
||||
|
||||
<field name="throbber" readonly="true">
|
||||
document.getAnonymousElementByAttribute(this, "anonid", "throbber");
|
||||
</field>
|
||||
|
||||
<field name="identity" readonly="true">
|
||||
this.notification.options.identity;
|
||||
</field>
|
||||
|
||||
<!-- persist the state on the identity object so we can re-create the
|
||||
notification state upon re-opening -->
|
||||
<property name="step">
|
||||
<getter>
|
||||
return this.identity.step;
|
||||
</getter>
|
||||
<setter><![CDATA[
|
||||
let deck = document.getAnonymousElementByAttribute(this, "anonid", "identity-deck");
|
||||
for (let i = 0; i < deck.children.length; i++) {
|
||||
deck.children[i].hidden = (val != i);
|
||||
}
|
||||
this.identity.step = val;
|
||||
switch (val) {
|
||||
case 0:
|
||||
this.emailField.focus();
|
||||
break;
|
||||
}]]>
|
||||
</setter>
|
||||
</property>
|
||||
|
||||
<method name="onIdentitySelected">
|
||||
<method name="observe">
|
||||
<parameter name="aSubject"/>
|
||||
<parameter name="aTopic"/>
|
||||
<parameter name="aData"/>
|
||||
<body><![CDATA[
|
||||
this.throbber.style.visibility = "visible";
|
||||
this.button.disabled = true;
|
||||
this.emailField.value = this.identity.selected
|
||||
this.emailField.disabled = true;
|
||||
this.identityList.disabled = true;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_populateLink">
|
||||
<parameter name="aURL"/>
|
||||
<parameter name="aLinkId"/>
|
||||
<parameter name="aStringId"/>
|
||||
<body><![CDATA[
|
||||
if (aURL) {
|
||||
// Show optional link to aURL
|
||||
let link = document.getAnonymousElementByAttribute(this, "anonid", aLinkId);
|
||||
link.value = gNavigatorBundle.getString(aStringId);
|
||||
link.href = aURL;
|
||||
link.hidden = false;
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_populateIdentityList">
|
||||
<parameter name="aIdentities"/>
|
||||
<body><![CDATA[
|
||||
let foundLastUsed = false;
|
||||
let lastUsed = this.identity.selected || aIdentities.lastUsed;
|
||||
for (let id in aIdentities.result) {
|
||||
let label = aIdentities.result[id];
|
||||
let opt = this.identityList.appendItem(label);
|
||||
if (label == lastUsed) {
|
||||
this.identityList.selectedItem = opt;
|
||||
foundLastUsed = true;
|
||||
}
|
||||
}
|
||||
if (!foundLastUsed) {
|
||||
this.identityList.selectedIndex = -1;
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_onButtonCommand">
|
||||
<parameter name="aEvent"/>
|
||||
<body><![CDATA[
|
||||
if (aEvent.target != aEvent.currentTarget)
|
||||
return;
|
||||
let chosenId;
|
||||
switch (this.step) {
|
||||
case 0:
|
||||
aEvent.stopPropagation();
|
||||
if (!this.emailField.validity.valid) {
|
||||
this.emailField.focus();
|
||||
return;
|
||||
}
|
||||
chosenId = this.emailField.value;
|
||||
break;
|
||||
case 1:
|
||||
aEvent.stopPropagation();
|
||||
let selectedItem = this.identityList.selectedItem
|
||||
chosenId = selectedItem ? selectedItem.label : null;
|
||||
if (!chosenId)
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unknown case");
|
||||
return;
|
||||
}
|
||||
// Actually select the identity
|
||||
this.SignInToWebsiteUX.selectIdentity(this.identity.rpId, chosenId);
|
||||
this.identity.selected = chosenId;
|
||||
this.onIdentitySelected();
|
||||
// The only message we observe is identity-delegate-ui-close
|
||||
this.complete = true;
|
||||
this.notification.remove();
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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 <browser> 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 <browser> 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);
|
||||
}
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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}"),
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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'];
|
||||
|
@ -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] !== '_') {
|
||||
|
@ -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("<<something>>");
|
||||
switch (typeof arg) {
|
||||
case 'string':
|
||||
strings.push(arg);
|
||||
break;
|
||||
case 'undefined':
|
||||
strings.push('undefined');
|
||||
break;
|
||||
case 'function':
|
||||
strings.push('<<function>>');
|
||||
break;
|
||||
case 'object':
|
||||
try {
|
||||
strings.push(JSON.stringify(arg, null, 2));
|
||||
} catch (err) {
|
||||
strings.push('<<object>>');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
try {
|
||||
strings.push(arg.toString());
|
||||
} catch (err) {
|
||||
strings.push('<<something>>');
|
||||
}
|
||||
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];
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -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));
|
||||
},
|
||||
|
||||
}
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user