зеркало из https://github.com/mozilla/gecko-dev.git
Bug 753239 - Implement a DOM component for navigator.id. r=jst
--HG-- extra : rebase_source : 4cd2b33f46c6c884dc9a3ff4820203275a6c5ae9
This commit is contained in:
Родитель
da71fbd278
Коммит
1912e8f515
|
@ -474,6 +474,9 @@
|
|||
@BINPATH@/components/Webapps.manifest
|
||||
@BINPATH@/components/AppsService.js
|
||||
@BINPATH@/components/AppsService.manifest
|
||||
@BINPATH@/components/nsDOMIdentity.js
|
||||
@BINPATH@/components/nsIDService.js
|
||||
@BINPATH@/components/Identity.manifest
|
||||
|
||||
@BINPATH@/components/ContactManager.js
|
||||
@BINPATH@/components/ContactManager.manifest
|
||||
|
|
|
@ -67,6 +67,7 @@ DIRS += \
|
|||
indexedDB \
|
||||
system \
|
||||
ipc \
|
||||
identity \
|
||||
workers \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
@ -0,0 +1,266 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
// This is the parent process corresponding to nsDOMIdentity.
|
||||
let EXPORTED_SYMBOLS = ["DOMIdentity"];
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "IdentityService",
|
||||
"resource://gre/modules/identity/Identity.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this,
|
||||
"Logger",
|
||||
"resource://gre/modules/identity/LogUtils.jsm");
|
||||
|
||||
function log(...aMessageArgs) {
|
||||
Logger.log.apply(Logger, ["DOMIdentity"].concat(aMessageArgs));
|
||||
}
|
||||
|
||||
function IDDOMMessage(aID) {
|
||||
this.id = aID;
|
||||
}
|
||||
|
||||
function IDPProvisioningContext(aID, aOrigin, aTargetMM) {
|
||||
this._id = aID;
|
||||
this._origin = aOrigin;
|
||||
this._mm = aTargetMM;
|
||||
}
|
||||
|
||||
IDPProvisioningContext.prototype = {
|
||||
get id() this._id,
|
||||
get origin() this._origin,
|
||||
|
||||
doBeginProvisioningCallback: function IDPPC_doBeginProvCB(aID, aCertDuration) {
|
||||
let message = new IDDOMMessage(this.id);
|
||||
message.identity = aID;
|
||||
message.certDuration = aCertDuration;
|
||||
this._mm.sendAsyncMessage("Identity:IDP:CallBeginProvisioningCallback",
|
||||
message);
|
||||
},
|
||||
|
||||
doGenKeyPairCallback: function IDPPC_doGenKeyPairCallback(aPublicKey) {
|
||||
log("doGenKeyPairCallback");
|
||||
let message = new IDDOMMessage(this.id);
|
||||
message.publicKey = aPublicKey;
|
||||
this._mm.sendAsyncMessage("Identity:IDP:CallGenKeyPairCallback", message);
|
||||
},
|
||||
|
||||
doError: function(msg) {
|
||||
log("Provisioning ERROR: " + msg);
|
||||
},
|
||||
};
|
||||
|
||||
function IDPAuthenticationContext(aID, aOrigin, aTargetMM) {
|
||||
this._id = aID;
|
||||
this._origin = aOrigin;
|
||||
this._mm = aTargetMM;
|
||||
}
|
||||
|
||||
IDPAuthenticationContext.prototype = {
|
||||
get id() this._id,
|
||||
get origin() this._origin,
|
||||
|
||||
doBeginAuthenticationCallback: function IDPAC_doBeginAuthCB(aIdentity) {
|
||||
let message = new IDDOMMessage(this.id);
|
||||
message.identity = aIdentity;
|
||||
this._mm.sendAsyncMessage("Identity:IDP:CallBeginAuthenticationCallback",
|
||||
message);
|
||||
},
|
||||
|
||||
doError: function IDPAC_doError(msg) {
|
||||
log("Authentication ERROR: " + msg);
|
||||
},
|
||||
};
|
||||
|
||||
function RPWatchContext(aID, aOrigin, aLoggedInEmail, aTargetMM) {
|
||||
this._id = aID;
|
||||
this._origin = aOrigin;
|
||||
this._loggedInEmail = aLoggedInEmail;
|
||||
this._mm = aTargetMM;
|
||||
}
|
||||
|
||||
RPWatchContext.prototype = {
|
||||
get id() this._id,
|
||||
get origin() this._origin,
|
||||
get loggedInEmail() this._loggedInEmail,
|
||||
|
||||
doLogin: function RPWatchContext_onlogin(aAssertion) {
|
||||
log("doLogin: " + this.id);
|
||||
let message = new IDDOMMessage(this.id);
|
||||
message.assertion = aAssertion;
|
||||
this._mm.sendAsyncMessage("Identity:RP:Watch:OnLogin", message);
|
||||
},
|
||||
|
||||
doLogout: function RPWatchContext_onlogout() {
|
||||
log("doLogout :" + this.id);
|
||||
let message = new IDDOMMessage(this.id);
|
||||
this._mm.sendAsyncMessage("Identity:RP:Watch:OnLogout", message);
|
||||
},
|
||||
|
||||
doReady: function RPWatchContext_onready() {
|
||||
log("doReady: " + this.id);
|
||||
let message = new IDDOMMessage(this.id);
|
||||
this._mm.sendAsyncMessage("Identity:RP:Watch:OnReady", message);
|
||||
},
|
||||
|
||||
doError: function RPWatchContext_onerror(aMessage) {
|
||||
log("doError: " + aMessage);
|
||||
}
|
||||
};
|
||||
|
||||
let DOMIdentity = {
|
||||
// nsIFrameMessageListener
|
||||
receiveMessage: function DOMIdentity_receiveMessage(aMessage) {
|
||||
let msg = aMessage.json;
|
||||
|
||||
// Target is the frame message manager that called us and is
|
||||
// used to send replies back to the proper window.
|
||||
let targetMM = aMessage.target
|
||||
.QueryInterface(Ci.nsIFrameLoaderOwner)
|
||||
.frameLoader.messageManager;
|
||||
|
||||
switch (aMessage.name) {
|
||||
// RP
|
||||
case "Identity:RP:Watch":
|
||||
this._watch(msg, targetMM);
|
||||
break;
|
||||
case "Identity:RP:Request":
|
||||
this._request(msg);
|
||||
break;
|
||||
case "Identity:RP:Logout":
|
||||
this._logout(msg);
|
||||
break;
|
||||
// IDP
|
||||
case "Identity:IDP:BeginProvisioning":
|
||||
this._beginProvisioning(msg, targetMM);
|
||||
break;
|
||||
case "Identity:IDP:GenKeyPair":
|
||||
this._genKeyPair(msg);
|
||||
break;
|
||||
case "Identity:IDP:RegisterCertificate":
|
||||
this._registerCertificate(msg);
|
||||
break;
|
||||
case "Identity:IDP:ProvisioningFailure":
|
||||
this._provisioningFailure(msg);
|
||||
break;
|
||||
case "Identity:IDP:BeginAuthentication":
|
||||
this._beginAuthentication(msg, targetMM);
|
||||
break;
|
||||
case "Identity:IDP:CompleteAuthentication":
|
||||
this._completeAuthentication(msg);
|
||||
break;
|
||||
case "Identity:IDP:AuthenticationFailure":
|
||||
this._authenticationFailure(msg);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
// nsIObserver
|
||||
observe: function DOMIdentity_observe(aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case "domwindowopened":
|
||||
case "domwindowclosed":
|
||||
let win = aSubject.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindow);
|
||||
this._configureMessages(win, aTopic == "domwindowopened");
|
||||
break;
|
||||
|
||||
case "xpcom-shutdown":
|
||||
Services.ww.unregisterNotification(this);
|
||||
Services.obs.removeObserver(this, "xpcom-shutdown");
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
messages: ["Identity:RP:Watch", "Identity:RP:Request", "Identity:RP:Logout",
|
||||
"Identity:IDP:BeginProvisioning", "Identity:IDP:ProvisioningFailure",
|
||||
"Identity:IDP:RegisterCertificate", "Identity:IDP:GenKeyPair",
|
||||
"Identity:IDP:BeginAuthentication",
|
||||
"Identity:IDP:CompleteAuthentication",
|
||||
"Identity:IDP:AuthenticationFailure"],
|
||||
|
||||
// Private.
|
||||
_init: function DOMIdentity__init() {
|
||||
Services.ww.registerNotification(this);
|
||||
Services.obs.addObserver(this, "xpcom-shutdown", false);
|
||||
},
|
||||
|
||||
_configureMessages: function DOMIdentity__configureMessages(aWindow, aRegister) {
|
||||
if (!aWindow.messageManager)
|
||||
return;
|
||||
|
||||
let func = aWindow.messageManager[aRegister ? "addMessageListener"
|
||||
: "removeMessageListener"];
|
||||
|
||||
for (let message of this.messages) {
|
||||
func(message, this);
|
||||
}
|
||||
},
|
||||
|
||||
_resetFrameState: function(aContext) {
|
||||
log("_resetFrameState: ", aContext.id);
|
||||
if (!aContext._mm) {
|
||||
throw new Error("ERROR: Trying to reset an invalid context");
|
||||
}
|
||||
let message = new IDDOMMessage(aContext.id);
|
||||
aContext._mm.sendAsyncMessage("Identity:ResetState", message);
|
||||
},
|
||||
|
||||
_watch: function DOMIdentity__watch(message, targetMM) {
|
||||
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.id, message.origin,
|
||||
message.loggedInEmail, targetMM);
|
||||
IdentityService.RP.watch(context);
|
||||
},
|
||||
|
||||
_request: function DOMIdentity__request(message) {
|
||||
IdentityService.RP.request(message.id, message);
|
||||
},
|
||||
|
||||
_logout: function DOMIdentity__logout(message) {
|
||||
IdentityService.RP.logout(message.id, message.origin);
|
||||
},
|
||||
|
||||
_beginProvisioning: function DOMIdentity__beginProvisioning(message, targetMM) {
|
||||
let context = new IDPProvisioningContext(message.id, message.origin,
|
||||
targetMM);
|
||||
IdentityService.IDP.beginProvisioning(context);
|
||||
},
|
||||
|
||||
_genKeyPair: function DOMIdentity__genKeyPair(message) {
|
||||
IdentityService.IDP.genKeyPair(message.id);
|
||||
},
|
||||
|
||||
_registerCertificate: function DOMIdentity__registerCertificate(message) {
|
||||
IdentityService.IDP.registerCertificate(message.id, message.cert);
|
||||
},
|
||||
|
||||
_provisioningFailure: function DOMIdentity__provisioningFailure(message) {
|
||||
IdentityService.IDP.raiseProvisioningFailure(message.id, message.reason);
|
||||
},
|
||||
|
||||
_beginAuthentication: function DOMIdentity__beginAuthentication(message, targetMM) {
|
||||
let context = new IDPAuthenticationContext(message.id, message.origin,
|
||||
targetMM);
|
||||
IdentityService.IDP.beginAuthentication(context);
|
||||
},
|
||||
|
||||
_completeAuthentication: function DOMIdentity__completeAuthentication(message) {
|
||||
IdentityService.IDP.completeAuthentication(message.id);
|
||||
},
|
||||
|
||||
_authenticationFailure: function DOMIdentity__authenticationFailure(message) {
|
||||
IdentityService.IDP.cancelAuthentication(message.id);
|
||||
},
|
||||
};
|
||||
|
||||
// Object is initialized by nsIDService.js
|
|
@ -0,0 +1,9 @@
|
|||
# nsDOMIdentity.js
|
||||
component {8bcac6a3-56a4-43a4-a44c-cdf42763002f} nsDOMIdentity.js
|
||||
contract @mozilla.org/dom/identity;1 {8bcac6a3-56a4-43a4-a44c-cdf42763002f}
|
||||
category JavaScript-navigator-property id @mozilla.org/dom/identity;1
|
||||
|
||||
# nsIDService.js (initialization on startup)
|
||||
component {baa581e5-8e72-406c-8c9f-dcd4b23a6f82} nsIDService.js
|
||||
contract @mozilla.org/dom/identity/service;1 {baa581e5-8e72-406c-8c9f-dcd4b23a6f82}
|
||||
category app-startup IDService @mozilla.org/dom/identity/service;1
|
|
@ -0,0 +1,28 @@
|
|||
# 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/.
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
relativesrcdir = dom/identity
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
EXTRA_COMPONENTS = \
|
||||
nsDOMIdentity.js \
|
||||
nsIDService.js \
|
||||
Identity.manifest \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_JS_MODULES = \
|
||||
DOMIdentity.jsm \
|
||||
$(NULL)
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
DIRS += tests
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
|
@ -0,0 +1,530 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
const PREF_DEBUG = "toolkit.identity.debug";
|
||||
const PREF_ENABLED = "dom.identity.enabled";
|
||||
|
||||
// Maximum length of a string that will go through IPC
|
||||
const MAX_STRING_LENGTH = 2048;
|
||||
// Maximum number of times navigator.id.request can be called for a document
|
||||
const MAX_RP_CALLS = 100;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
// This is the child process corresponding to nsIDOMIdentity.
|
||||
|
||||
|
||||
function nsDOMIdentity(aIdentityInternal) {
|
||||
this._identityInternal = aIdentityInternal;
|
||||
}
|
||||
nsDOMIdentity.prototype = {
|
||||
__exposedProps__: {
|
||||
// Relying Party (RP)
|
||||
watch: 'r',
|
||||
request: 'r',
|
||||
logout: 'r',
|
||||
|
||||
// Provisioning
|
||||
beginProvisioning: 'r',
|
||||
genKeyPair: 'r',
|
||||
registerCertificate: 'r',
|
||||
raiseProvisioningFailure: 'r',
|
||||
|
||||
// Authentication
|
||||
beginAuthentication: 'r',
|
||||
completeAuthentication: 'r',
|
||||
raiseAuthenticationFailure: 'r',
|
||||
},
|
||||
|
||||
// nsIDOMIdentity
|
||||
/**
|
||||
* Relying Party (RP) APIs
|
||||
*/
|
||||
|
||||
watch: function nsDOMIdentity_watch(aOptions) {
|
||||
this._log("watch");
|
||||
if (this._rpWatcher) {
|
||||
throw new Error("navigator.id.watch was already called");
|
||||
}
|
||||
|
||||
if (!aOptions || typeof(aOptions) !== "object") {
|
||||
throw new Error("options argument to watch is required");
|
||||
}
|
||||
|
||||
// Check for required callbacks
|
||||
let requiredCallbacks = ["onlogin", "onlogout"];
|
||||
for (let cbName of requiredCallbacks) {
|
||||
if ((!(cbName in aOptions))
|
||||
|| typeof(aOptions[cbName]) !== "function") {
|
||||
throw new Error(cbName + " callback is required.");
|
||||
}
|
||||
}
|
||||
|
||||
// Optional callback "onready"
|
||||
if (aOptions["onready"]
|
||||
&& typeof(aOptions['onready']) !== "function") {
|
||||
throw new Error("onready must be a function");
|
||||
}
|
||||
|
||||
let message = this.DOMIdentityMessage();
|
||||
|
||||
// loggedInEmail
|
||||
message.loggedInEmail = null;
|
||||
let emailType = typeof(aOptions["loggedInEmail"]);
|
||||
if (aOptions["loggedInEmail"] && aOptions["loggedInEmail"] !== "undefined") {
|
||||
if (emailType !== "string") {
|
||||
throw new Error("loggedInEmail must be a String or null");
|
||||
}
|
||||
|
||||
// TODO: Bug 767610 - check email format.
|
||||
// See nsHTMLInputElement::IsValidEmailAddress
|
||||
if (aOptions["loggedInEmail"].indexOf("@") == -1
|
||||
|| aOptions["loggedInEmail"].length > MAX_STRING_LENGTH) {
|
||||
throw new Error("loggedInEmail is not valid");
|
||||
}
|
||||
// Set loggedInEmail in this block that "undefined" doesn't get through.
|
||||
message.loggedInEmail = aOptions.loggedInEmail;
|
||||
}
|
||||
this._log("loggedInEmail: " + message.loggedInEmail);
|
||||
|
||||
this._rpWatcher = aOptions;
|
||||
this._identityInternal._mm.sendAsyncMessage("Identity:RP:Watch", message);
|
||||
},
|
||||
|
||||
request: function nsDOMIdentity_request(aOptions) {
|
||||
// TODO: Bug 769569 - "must be invoked from within a click handler"
|
||||
|
||||
// Has the caller called watch() before this?
|
||||
if (!this._rpWatcher) {
|
||||
throw new Error("navigator.id.request called before navigator.id.watch");
|
||||
}
|
||||
if (this._rpCalls > MAX_RP_CALLS) {
|
||||
throw new Error("navigator.id.request called too many times");
|
||||
}
|
||||
|
||||
let message = this.DOMIdentityMessage();
|
||||
|
||||
if (aOptions) {
|
||||
// Optional string properties
|
||||
let optionalStringProps = ["privacyPolicy", "termsOfService"];
|
||||
for (let propName of optionalStringProps) {
|
||||
if (!aOptions[propName] || aOptions[propName] === "undefined")
|
||||
continue;
|
||||
if (typeof(aOptions[propName]) !== "string") {
|
||||
throw new Error(propName + " must be a string representing a URL.");
|
||||
}
|
||||
if (aOptions[propName].length > MAX_STRING_LENGTH) {
|
||||
throw new Error(propName + " is invalid.");
|
||||
}
|
||||
message[propName] = aOptions[propName];
|
||||
}
|
||||
|
||||
if (aOptions["oncancel"]
|
||||
&& typeof(aOptions["oncancel"]) !== "function") {
|
||||
throw new Error("oncancel is not a function");
|
||||
} else {
|
||||
// Store optional cancel callback for later.
|
||||
this._onCancelRequestCallback = aOptions.oncancel;
|
||||
}
|
||||
}
|
||||
|
||||
this._rpCalls++;
|
||||
this._identityInternal._mm.sendAsyncMessage("Identity:RP:Request", message);
|
||||
},
|
||||
|
||||
logout: function nsDOMIdentity_logout() {
|
||||
if (!this._rpWatcher) {
|
||||
throw new Error("navigator.id.logout called before navigator.id.watch");
|
||||
}
|
||||
if (this._rpCalls > MAX_RP_CALLS) {
|
||||
throw new Error("navigator.id.logout called too many times");
|
||||
}
|
||||
|
||||
this._rpCalls++;
|
||||
let message = this.DOMIdentityMessage();
|
||||
this._identityInternal._mm.sendAsyncMessage("Identity:RP:Logout", message);
|
||||
},
|
||||
|
||||
/**
|
||||
* Identity Provider (IDP) Provisioning APIs
|
||||
*/
|
||||
|
||||
beginProvisioning: function nsDOMIdentity_beginProvisioning(aCallback) {
|
||||
this._log("beginProvisioning");
|
||||
if (this._beginProvisioningCallback) {
|
||||
throw new Error("navigator.id.beginProvisioning already called.");
|
||||
}
|
||||
if (!aCallback || typeof(aCallback) !== "function") {
|
||||
throw new Error("beginProvisioning callback is required.");
|
||||
}
|
||||
|
||||
this._beginProvisioningCallback = aCallback;
|
||||
this._identityInternal._mm.sendAsyncMessage("Identity:IDP:BeginProvisioning",
|
||||
this.DOMIdentityMessage());
|
||||
},
|
||||
|
||||
genKeyPair: function nsDOMIdentity_genKeyPair(aCallback) {
|
||||
this._log("genKeyPair");
|
||||
if (!this._beginProvisioningCallback) {
|
||||
throw new Error("navigator.id.genKeyPair called outside of provisioning");
|
||||
}
|
||||
if (this._genKeyPairCallback) {
|
||||
throw new Error("navigator.id.genKeyPair already called.");
|
||||
}
|
||||
if (!aCallback || typeof(aCallback) !== "function") {
|
||||
throw new Error("genKeyPair callback is required.");
|
||||
}
|
||||
|
||||
this._genKeyPairCallback = aCallback;
|
||||
this._identityInternal._mm.sendAsyncMessage("Identity:IDP:GenKeyPair",
|
||||
this.DOMIdentityMessage());
|
||||
},
|
||||
|
||||
registerCertificate: function nsDOMIdentity_registerCertificate(aCertificate) {
|
||||
this._log("registerCertificate");
|
||||
if (!this._genKeyPairCallback) {
|
||||
throw new Error("navigator.id.registerCertificate called outside of provisioning");
|
||||
}
|
||||
if (this._provisioningEnded) {
|
||||
throw new Error("Provisioning already ended");
|
||||
}
|
||||
this._provisioningEnded = true;
|
||||
|
||||
let message = this.DOMIdentityMessage();
|
||||
message.cert = aCertificate;
|
||||
this._identityInternal._mm.sendAsyncMessage("Identity:IDP:RegisterCertificate", message);
|
||||
},
|
||||
|
||||
raiseProvisioningFailure: function nsDOMIdentity_raiseProvisioningFailure(aReason) {
|
||||
this._log("raiseProvisioningFailure '" + aReason + "'");
|
||||
if (this._provisioningEnded) {
|
||||
throw new Error("Provisioning already ended");
|
||||
}
|
||||
if (!aReason || typeof(aReason) != "string") {
|
||||
throw new Error("raiseProvisioningFailure reason is required");
|
||||
}
|
||||
this._provisioningEnded = true;
|
||||
|
||||
let message = this.DOMIdentityMessage();
|
||||
message.reason = aReason;
|
||||
this._identityInternal._mm.sendAsyncMessage("Identity:IDP:ProvisioningFailure", message);
|
||||
},
|
||||
|
||||
/**
|
||||
* Identity Provider (IDP) Authentication APIs
|
||||
*/
|
||||
|
||||
beginAuthentication: function nsDOMIdentity_beginAuthentication(aCallback) {
|
||||
this._log("beginAuthentication");
|
||||
if (this._beginAuthenticationCallback) {
|
||||
throw new Error("navigator.id.beginAuthentication already called.");
|
||||
}
|
||||
if (typeof(aCallback) !== "function") {
|
||||
throw new Error("beginAuthentication callback is required.");
|
||||
}
|
||||
if (!aCallback || typeof(aCallback) !== "function") {
|
||||
throw new Error("beginAuthentication callback is required.");
|
||||
}
|
||||
|
||||
this._beginAuthenticationCallback = aCallback;
|
||||
this._identityInternal._mm.sendAsyncMessage("Identity:IDP:BeginAuthentication",
|
||||
this.DOMIdentityMessage());
|
||||
},
|
||||
|
||||
completeAuthentication: function nsDOMIdentity_completeAuthentication() {
|
||||
if (this._authenticationEnded) {
|
||||
throw new Error("Authentication already ended");
|
||||
}
|
||||
if (!this._beginAuthenticationCallback) {
|
||||
throw new Error("navigator.id.completeAuthentication called outside of authentication");
|
||||
}
|
||||
this._authenticationEnded = true;
|
||||
|
||||
this._identityInternal._mm.sendAsyncMessage("Identity:IDP:CompleteAuthentication",
|
||||
this.DOMIdentityMessage());
|
||||
},
|
||||
|
||||
raiseAuthenticationFailure: function nsDOMIdentity_raiseAuthenticationFailure(aReason) {
|
||||
if (this._authenticationEnded) {
|
||||
throw new Error("Authentication already ended");
|
||||
}
|
||||
if (!aReason || typeof(aReason) != "string") {
|
||||
throw new Error("raiseProvisioningFailure reason is required");
|
||||
}
|
||||
|
||||
let message = this.DOMIdentityMessage();
|
||||
message.reason = aReason;
|
||||
this._identityInternal._mm.sendAsyncMessage("Identity:IDP:AuthenticationFailure", message);
|
||||
},
|
||||
|
||||
// Private.
|
||||
_init: function nsDOMIdentity__init(aWindow) {
|
||||
|
||||
this._initializeState();
|
||||
|
||||
// Store window and origin URI.
|
||||
this._window = aWindow;
|
||||
this._origin = aWindow.document.nodePrincipal.origin;
|
||||
|
||||
// Setup identifiers for current window.
|
||||
let util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
this._id = util.outerWindowID;
|
||||
},
|
||||
|
||||
/**
|
||||
* Called during init and shutdown.
|
||||
*/
|
||||
_initializeState: function nsDOMIdentity__initializeState() {
|
||||
// Some state to prevent abuse
|
||||
// Limit the number of calls to .request
|
||||
this._rpCalls = 0;
|
||||
this._provisioningEnded = false;
|
||||
this._authenticationEnded = false;
|
||||
|
||||
this._rpWatcher = null;
|
||||
this._onCancelRequestCallback = null;
|
||||
this._beginProvisioningCallback = null;
|
||||
this._genKeyPairCallback = null;
|
||||
this._beginAuthenticationCallback = null;
|
||||
},
|
||||
|
||||
_receiveMessage: function nsDOMIdentity_receiveMessage(aMessage) {
|
||||
let msg = aMessage.json;
|
||||
this._log("receiveMessage: " + aMessage.name);
|
||||
|
||||
switch (aMessage.name) {
|
||||
case "Identity:ResetState":
|
||||
if (!this._identityInternal._debug) {
|
||||
return;
|
||||
}
|
||||
this._initializeState();
|
||||
Services.obs.notifyObservers(null, "identity-DOM-state-reset", this._id);
|
||||
break;
|
||||
case "Identity:RP:Watch:OnLogin":
|
||||
// Do we have a watcher?
|
||||
if (!this._rpWatcher) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._rpWatcher.onlogin) {
|
||||
this._rpWatcher.onlogin(msg.assertion);
|
||||
}
|
||||
break;
|
||||
case "Identity:RP:Watch:OnLogout":
|
||||
// Do we have a watcher?
|
||||
if (!this._rpWatcher) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._rpWatcher.onlogout) {
|
||||
this._rpWatcher.onlogout();
|
||||
}
|
||||
break;
|
||||
case "Identity:RP:Watch:OnReady":
|
||||
// Do we have a watcher?
|
||||
if (!this._rpWatcher) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._rpWatcher.onready) {
|
||||
this._rpWatcher.onready();
|
||||
}
|
||||
break;
|
||||
case "Identity:RP:Request:OnCancel":
|
||||
// Do we have a watcher?
|
||||
if (!this._rpWatcher) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._onCancelRequestCallback) {
|
||||
this._onCancelRequestCallback();
|
||||
}
|
||||
break;
|
||||
case "Identity:IDP:CallBeginProvisioningCallback":
|
||||
this._callBeginProvisioningCallback(msg);
|
||||
break;
|
||||
case "Identity:IDP:CallGenKeyPairCallback":
|
||||
this._callGenKeyPairCallback(msg);
|
||||
break;
|
||||
case "Identity:IDP:CallBeginAuthenticationCallback":
|
||||
this._callBeginAuthenticationCallback(msg);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_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);
|
||||
|
||||
// bunch of stuff to create a proper object in window context
|
||||
function genPropDesc(value) {
|
||||
return {
|
||||
enumerable: true, configurable: true, writable: true, value: value
|
||||
};
|
||||
}
|
||||
|
||||
let propList = {};
|
||||
for (let k in chrome_pubkey) {
|
||||
propList[k] = genPropDesc(chrome_pubkey[k]);
|
||||
}
|
||||
|
||||
let pubkey = Cu.createObjectIn(this._window);
|
||||
Object.defineProperties(pubkey, propList);
|
||||
Cu.makeObjectPropsNormal(pubkey);
|
||||
|
||||
// do the callback
|
||||
this._genKeyPairCallback(pubkey);
|
||||
},
|
||||
|
||||
_callBeginProvisioningCallback:
|
||||
function nsDOMIdentity__callBeginProvisioningCallback(message) {
|
||||
let identity = message.identity;
|
||||
let certValidityDuration = message.certDuration;
|
||||
this._beginProvisioningCallback(identity,
|
||||
certValidityDuration);
|
||||
},
|
||||
|
||||
_callBeginAuthenticationCallback:
|
||||
function nsDOMIdentity__callBeginAuthenticationCallback(message) {
|
||||
let identity = message.identity;
|
||||
this._beginAuthenticationCallback(identity);
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper to create messages to send using a message manager
|
||||
*/
|
||||
DOMIdentityMessage: function DOMIdentityMessage() {
|
||||
return {
|
||||
id: this._id,
|
||||
origin: this._origin,
|
||||
};
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal functions that shouldn't be exposed to content.
|
||||
*/
|
||||
function nsDOMIdentityInternal() {
|
||||
}
|
||||
nsDOMIdentityInternal.prototype = {
|
||||
|
||||
// nsIFrameMessageListener
|
||||
receiveMessage: function nsDOMIdentityInternal_receiveMessage(aMessage) {
|
||||
let msg = aMessage.json;
|
||||
// Is this message intended for this window?
|
||||
if (msg.id != this._id) {
|
||||
return;
|
||||
}
|
||||
this._identity._receiveMessage(aMessage);
|
||||
},
|
||||
|
||||
// nsIObserver
|
||||
observe: function nsDOMIdentityInternal_observe(aSubject, aTopic, aData) {
|
||||
let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
|
||||
if (wId != this._innerWindowID) {
|
||||
return;
|
||||
}
|
||||
|
||||
Services.obs.removeObserver(this, "inner-window-destroyed");
|
||||
this._identity._initializeState();
|
||||
this._identity = null;
|
||||
|
||||
// TODO: Also send message to DOMIdentity notifiying window is no longer valid
|
||||
// ie. in the case that the user closes the auth. window and we need to know.
|
||||
|
||||
try {
|
||||
for (let msgName of this._messages) {
|
||||
this._mm.removeMessageListener(msgName, this);
|
||||
}
|
||||
} catch (ex) {
|
||||
// Avoid errors when removing more than once.
|
||||
}
|
||||
|
||||
this._mm = null;
|
||||
},
|
||||
|
||||
// nsIDOMGlobalPropertyInitializer
|
||||
init: function nsDOMIdentityInternal_init(aWindow) {
|
||||
if (Services.prefs.getPrefType(PREF_ENABLED) != Ci.nsIPrefBranch.PREF_BOOL
|
||||
|| !Services.prefs.getBoolPref(PREF_ENABLED)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
this._debug =
|
||||
Services.prefs.getPrefType(PREF_DEBUG) == Ci.nsIPrefBranch.PREF_BOOL
|
||||
&& Services.prefs.getBoolPref(PREF_DEBUG);
|
||||
|
||||
this._identity = new nsDOMIdentity(this);
|
||||
|
||||
this._identity._init(aWindow);
|
||||
|
||||
let util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
this._id = util.outerWindowID;
|
||||
this._innerWindowID = util.currentInnerWindowID;
|
||||
|
||||
this._log("init was called from " + aWindow.document.location);
|
||||
|
||||
this._mm = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIContentFrameMessageManager);
|
||||
|
||||
// Setup listeners for messages from parent process.
|
||||
this._messages = [
|
||||
"Identity:ResetState",
|
||||
"Identity:RP:Watch:OnLogin",
|
||||
"Identity:RP:Watch:OnLogout",
|
||||
"Identity:RP:Watch:OnReady",
|
||||
"Identity:RP:Request:OnCancel",
|
||||
"Identity:IDP:CallBeginProvisioningCallback",
|
||||
"Identity:IDP:CallGenKeyPairCallback",
|
||||
"Identity:IDP:CallBeginAuthenticationCallback",
|
||||
];
|
||||
this._messages.forEach((function(msgName) {
|
||||
this._mm.addMessageListener(msgName, this);
|
||||
}).bind(this));
|
||||
|
||||
// Setup observers so we can remove message listeners.
|
||||
Services.obs.addObserver(this, "inner-window-destroyed", false);
|
||||
|
||||
return this._identity;
|
||||
},
|
||||
|
||||
// Private.
|
||||
_log: function nsDOMIdentityInternal__log(msg) {
|
||||
if (!this._debug) {
|
||||
return;
|
||||
}
|
||||
dump("nsDOMIdentity (" + this._id + "): " + msg + "\n");
|
||||
},
|
||||
|
||||
// Component setup.
|
||||
classID: Components.ID("{8bcac6a3-56a4-43a4-a44c-cdf42763002f}"),
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI(
|
||||
[Ci.nsIDOMGlobalPropertyInitializer, Ci.nsIFrameMessageListener]
|
||||
),
|
||||
|
||||
classInfo: XPCOMUtils.generateCI({
|
||||
classID: Components.ID("{8bcac6a3-56a4-43a4-a44c-cdf42763002f}"),
|
||||
contractID: "@mozilla.org/dom/identity;1",
|
||||
interfaces: [],
|
||||
classDescription: "Identity DOM Implementation"
|
||||
})
|
||||
|
||||
};
|
||||
|
||||
const NSGetFactory = XPCOMUtils.generateNSGetFactory([nsDOMIdentityInternal]);
|
|
@ -0,0 +1,34 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function IDService() {
|
||||
this.wrappedJSObject = this;
|
||||
}
|
||||
IDService.prototype = {
|
||||
classID: Components.ID("{baa581e5-8e72-406c-8c9f-dcd4b23a6f82}"),
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
|
||||
observe: function observe(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case "app-startup":
|
||||
Services.obs.addObserver(this, "final-ui-startup", true);
|
||||
break;
|
||||
case "final-ui-startup":
|
||||
// Startup DOMIdentity.jsm
|
||||
Cu.import("resource://gre/modules/DOMIdentity.jsm");
|
||||
DOMIdentity._init();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const NSGetFactory = XPCOMUtils.generateNSGetFactory([IDService]);
|
|
@ -0,0 +1,28 @@
|
|||
# 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/.
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
relativesrcdir = dom/identity/tests
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
_TEST_FILES = \
|
||||
head_identity.js \
|
||||
test_identity_idp_auth_basics.html \
|
||||
test_identity_idp_prov_basics.html \
|
||||
test_identity_rp_basics.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = SpecialPowers.wrap(Components).utils;
|
||||
|
||||
SpecialPowers.setBoolPref("toolkit.identity.debug", true);
|
||||
SpecialPowers.setBoolPref("dom.identity.enabled", true);
|
||||
|
||||
const Services = Cu.import("resource://gre/modules/Services.jsm").Services;
|
||||
const DOMIdentity = Cu.import("resource://gre/modules/DOMIdentity.jsm")
|
||||
.DOMIdentity;
|
||||
|
||||
let util = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
let outerWinId = util.outerWindowID;
|
||||
|
||||
const identity = navigator.id || navigator.mozId;
|
||||
|
||||
let index = 0;
|
||||
|
||||
// mimicking callback funtionality for ease of testing
|
||||
// this observer auto-removes itself after the observe function
|
||||
// is called, so this is meant to observe only ONE event.
|
||||
function makeObserver(aObserveTopic, aObserveFunc) {
|
||||
function observe(aSubject, aTopic, aData) {
|
||||
if (aTopic == aObserveTopic) {
|
||||
aObserveFunc(aSubject, aTopic, aData);
|
||||
Services.obs.removeObserver(this, aObserveTopic);
|
||||
}
|
||||
}
|
||||
|
||||
Services.obs.addObserver(observe, aObserveTopic, false);
|
||||
}
|
||||
|
||||
function expectException(aFunc, msg, aErrorType="Error") {
|
||||
info("Expecting an exception: " + msg);
|
||||
msg = msg || "";
|
||||
let caughtEx = null;
|
||||
try {
|
||||
aFunc();
|
||||
} catch (ex) {
|
||||
let exProto = Object.getPrototypeOf(ex);
|
||||
// Don't count NS_* exceptions since they shouldn't be exposed to content
|
||||
if (exProto.toString() == aErrorType
|
||||
&& ex.toString().indexOf("NS_ERROR_FAILURE") == -1) {
|
||||
caughtEx = ex;
|
||||
} else {
|
||||
ok(false, ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
isnot(caughtEx, null, "Check for thrown exception.");
|
||||
}
|
||||
|
||||
function next() {
|
||||
if (!identity) {
|
||||
todo(false, "DOM API is not available. Skipping tests.");
|
||||
finish_tests();
|
||||
return;
|
||||
}
|
||||
if (index >= steps.length) {
|
||||
ok(false, "Shouldn't get here!");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
let fn = steps[index];
|
||||
info("Begin test " + index + " '" + steps[index].name + "'!");
|
||||
fn();
|
||||
} catch(ex) {
|
||||
ok(false, "Caught exception", ex);
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
|
||||
function finish_tests() {
|
||||
info("all done");
|
||||
SpecialPowers.clearUserPref("toolkit.identity.debug");
|
||||
SpecialPowers.clearUserPref("dom.identity.enabled");
|
||||
SimpleTest.finish();
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for navigator.id identity provider (IDP) authentication basics</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript;version=1.8" src="head_identity.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank">navigator.id identity provider (IDP) authentication basics</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript;version=1.8">
|
||||
|
||||
"use strict"
|
||||
|
||||
let steps = [
|
||||
// completeAuthentication tests
|
||||
function completeAuthenticationExists() {
|
||||
is(typeof(identity.completeAuthentication), "function",
|
||||
"Check completeAuthentication is a function");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
function completeAuthenticationOutsideFlow() {
|
||||
expectException(function() {
|
||||
identity.completeAuthentication();
|
||||
}, "Check completeAuthentication outside of an auth. flow");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
|
||||
// raiseAuthenticationFailure tests
|
||||
function raiseAuthenticationFailureExists() {
|
||||
is(typeof(identity.raiseAuthenticationFailure), "function",
|
||||
"Check raiseAuthenticationFailure is a function");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
function raiseAuthenticationFailureNoArgs() {
|
||||
expectException(function() {
|
||||
identity.raiseAuthenticationFailure();
|
||||
}, "raiseAuthenticationFailure with no arguments");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
|
||||
// beginAuthentication tests
|
||||
function beginAuthenticationExists() {
|
||||
is(typeof(identity.beginAuthentication), "function",
|
||||
"Check beginAuthentication is a function");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
function beginAuthenticationNoArgs() {
|
||||
expectException(function() {
|
||||
identity.beginAuthentication();
|
||||
}, "beginAuthentication with no arguments");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
function beginAuthenticationInvalidArg() {
|
||||
expectException(function() {
|
||||
identity.beginAuthentication(999);
|
||||
}, "beginAuthentication with a non-function argument");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
function beginAuthenticationArgs() {
|
||||
function beginAuthenticationCb() {
|
||||
throw "beginAuthentication callback shouldn't have been called outside of an "
|
||||
+ "auth flow";
|
||||
}
|
||||
is(identity.beginAuthentication(beginAuthenticationCb), undefined,
|
||||
"Check minimum beginAuthentication arguments");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
|
||||
finish_tests,
|
||||
];
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(next);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,160 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for navigator.id identity provider (IDP) provisioning basics</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript;version=1.8" src="head_identity.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank">navigator.id identity provider (IDP) provisioning basics</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript;version=1.8">
|
||||
|
||||
"use strict"
|
||||
|
||||
let IDP = Cu.import("resource://gre/modules/identity/IdentityProvider.jsm").IdentityProvider;
|
||||
|
||||
function setupProv() {
|
||||
info("setupProv");
|
||||
// Add a provisioning flow so the DOM calls succeed
|
||||
IDP._provisionFlows[outerWinId] = {
|
||||
sandbox: {},
|
||||
callback: function doCallback(aErr) {
|
||||
info("provisioning callback: " + aErr);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function resetAndNext() {
|
||||
info("resetAndNext");
|
||||
// reset DOM state for the next test
|
||||
// Give the flow some time to cross the IPC boundary
|
||||
setTimeout(function() {
|
||||
let provContext = IDP._provisionFlows[outerWinId];
|
||||
if (!provContext) {
|
||||
SimpleTest.executeSoon(next);
|
||||
return;
|
||||
}
|
||||
makeObserver("identity-DOM-state-reset", function() {
|
||||
info("reset done");
|
||||
SimpleTest.executeSoon(next);
|
||||
});
|
||||
DOMIdentity._resetFrameState(provContext.caller);
|
||||
}, 700);
|
||||
}
|
||||
|
||||
let steps = [
|
||||
// genKeyPair tests
|
||||
function genKeyPairExists() {
|
||||
is(typeof(identity.genKeyPair), "function",
|
||||
"Check genKeyPair is a function");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
function genKeyPairOutsideProv() {
|
||||
expectException(function(){
|
||||
identity.genKeyPair(function(){});
|
||||
}, "Check genKeyPair outside of a prov. flow");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
function genKeyPairNoArgs() {
|
||||
setupProv();
|
||||
identity.beginProvisioning(function() {
|
||||
expectException(function() {
|
||||
identity.genKeyPair();
|
||||
}, "genKeyPair with no arguments");
|
||||
SimpleTest.executeSoon(resetAndNext);
|
||||
});
|
||||
},
|
||||
function genKeyPairInvalidArg() {
|
||||
setupProv();
|
||||
identity.beginProvisioning(function() {
|
||||
expectException(function() {
|
||||
identity.genKeyPair(999);
|
||||
}, "Check genKeyPair with non-function object argument");
|
||||
SimpleTest.executeSoon(resetAndNext);
|
||||
});
|
||||
},
|
||||
|
||||
// registerCertificate tests
|
||||
function registerCertificateExists() {
|
||||
is(typeof(identity.registerCertificate), "function",
|
||||
"Check registerCertificate is a function");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
function registerCertificateNoArgs() {
|
||||
setupProv();
|
||||
identity.beginProvisioning(function() {
|
||||
expectException(function() {
|
||||
identity.registerCertificate();
|
||||
}, "Check registerCertificate with no arguments");
|
||||
});
|
||||
SimpleTest.executeSoon(resetAndNext);
|
||||
},
|
||||
function registerCertificateOutsideProv() {
|
||||
expectException(function(){
|
||||
identity.registerCertificate("foo");
|
||||
}, "Check registerCertificate outside of a prov. flow");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
|
||||
// raiseProvisioningFailure tests
|
||||
function raiseProvisioningFailureExists() {
|
||||
is(typeof(identity.raiseProvisioningFailure), "function",
|
||||
"Check raiseProvisioningFailure is a function");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
function raiseProvisioningFailureNoArgs() {
|
||||
expectException(function() {
|
||||
identity.raiseProvisioningFailure();
|
||||
}, "raiseProvisioningFailure with no arguments");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
function raiseProvisioningFailureWithReason() {
|
||||
identity.raiseProvisioningFailure("my test reason");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
|
||||
// beginProvisioning tests
|
||||
function beginProvisioningExists() {
|
||||
is(typeof(identity.beginProvisioning), "function",
|
||||
"Check beginProvisioning is a function");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
function beginProvisioningNoArgs() {
|
||||
expectException(function() {
|
||||
identity.beginProvisioning();
|
||||
}, "beginProvisioning with no arguments");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
function beginProvisioningInvalidArg() {
|
||||
expectException(function() {
|
||||
identity.beginProvisioning(999);
|
||||
}, "beginProvisioning with a non-function argument");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
function beginProvisioningArgs() {
|
||||
function beginProvisioningCb() {
|
||||
SimpleTest.executeSoon(resetAndNext);
|
||||
}
|
||||
is(identity.beginProvisioning(beginProvisioningCb), undefined,
|
||||
"Check minimum beginProvisioning arguments");
|
||||
},
|
||||
|
||||
finish_tests,
|
||||
];
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(next);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,172 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for navigator.id relying party (RP) basics</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript;version=1.8" src="head_identity.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank">navigator.id RP basics</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript;version=1.8">
|
||||
|
||||
"use strict";
|
||||
|
||||
const RP = Cu.import("resource://gre/modules/identity/RelyingParty.jsm").RelyingParty;
|
||||
|
||||
function resetAndNext() {
|
||||
// reset DOM state for the next test
|
||||
makeObserver("identity-DOM-state-reset", function() {
|
||||
SimpleTest.executeSoon(next);
|
||||
});
|
||||
// Give the flow some time to cross the IPC boundary
|
||||
setTimeout(function() {
|
||||
let rpContext = RP._rpFlows[outerWinId];
|
||||
if (!rpContext) {
|
||||
SimpleTest.executeSoon(next);
|
||||
return;
|
||||
}
|
||||
DOMIdentity._resetFrameState(rpContext);
|
||||
}, 700);
|
||||
}
|
||||
|
||||
let steps = [
|
||||
function nonExistentProp() {
|
||||
is(identity.foobarbaz, undefined, "Check that foobarbaz does not exist");
|
||||
expectException(function() {
|
||||
identity.foobarbaz()
|
||||
}, "Check for exception calling non-existent method", "TypeError");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
|
||||
// test request before watch throws an exception
|
||||
function requestBeforeWatch() {
|
||||
expectException(function() {
|
||||
identity.request();
|
||||
});
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
|
||||
// watch tests
|
||||
function watchExists() {
|
||||
is(typeof(identity.watch), "function", "Check watch is a function");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
function watchNoArgs() {
|
||||
expectException(function() {
|
||||
identity.watch();
|
||||
}, "watch with no arguments");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
function watchEmptyObj() {
|
||||
expectException(function() {
|
||||
identity.watch({});
|
||||
}, "watch with empty object argument");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
function watchOnLoginBool() {
|
||||
expectException(function() {
|
||||
identity.watch({onlogin: true});
|
||||
}, "watch with invalid onlogin member");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
function watchOnLoginLogoutBool() {
|
||||
expectException(function() {
|
||||
identity.watch({onlogin: true, onlogout: false});
|
||||
}, "watch with invalid onlogin and onlogout members");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
function watchMinimumArgs() {
|
||||
function onLoginLogoutCb() {
|
||||
throw "onlogin/onlogout callback shouldn't have been called";
|
||||
}
|
||||
is(identity.watch({onlogin: onLoginLogoutCb, onlogout: onLoginLogoutCb}),
|
||||
undefined, "Check minimum watch argument members");
|
||||
resetAndNext();
|
||||
},
|
||||
function watchOnReadyType() {
|
||||
function onLoginLogoutCb() {
|
||||
throw "onlogin/onlogout callback shouldn't have been called";
|
||||
}
|
||||
let options = {
|
||||
onlogin: onLoginLogoutCb,
|
||||
onlogout: onLoginLogoutCb,
|
||||
onready: 999,
|
||||
}
|
||||
expectException(function() {
|
||||
identity.watch(options)
|
||||
}, "Check onready type");
|
||||
resetAndNext();
|
||||
},
|
||||
function watchLoggedInEmailType() {
|
||||
function onLoginLogoutCb() {
|
||||
throw "onlogin/onlogout callback shouldn't have been called";
|
||||
}
|
||||
let options = {
|
||||
onlogin: onLoginLogoutCb,
|
||||
onlogout: onLoginLogoutCb,
|
||||
loggedInEmail: {},
|
||||
}
|
||||
expectException(function() {
|
||||
identity.watch(options)
|
||||
}, "Check loggedInEmail type");
|
||||
resetAndNext();
|
||||
},
|
||||
function watchOnReadyCalled() {
|
||||
let onLogoutCalled = false;
|
||||
let options = {
|
||||
loggedInEmail: "loggedOut@user.com",
|
||||
onlogin: function onLoginCb(assertion) {
|
||||
throw "onlogin/onlogout callback shouldn't have been called";
|
||||
},
|
||||
onlogout: function onLogoutCb() {
|
||||
is(arguments.length, 0, "Check onlogout argument length");
|
||||
onLogoutCalled = true;
|
||||
},
|
||||
onready: function onReady() {
|
||||
is(arguments.length, 0, "Check onready argument length");
|
||||
ok(onLogoutCalled, "onlogout callback should be called before onready");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
}
|
||||
is(identity.watch(options), undefined, "Check onready is called");
|
||||
},
|
||||
|
||||
// request tests
|
||||
function requestExists() {
|
||||
is(typeof(identity.request), "function", "Check request is a function");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
function requestNoArgs() {
|
||||
is(identity.request(), undefined, "Check request with no arguments");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
function requestEmptyObj() {
|
||||
is(identity.request({}), undefined, "Check request with empty object argument");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
|
||||
// logout tests
|
||||
function logoutExists() {
|
||||
is(typeof(identity.logout), "function", "Check logout is a function");
|
||||
SimpleTest.executeSoon(next);
|
||||
},
|
||||
|
||||
finish_tests,
|
||||
];
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(next);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -42,6 +42,7 @@ function IdentityProviderService() {
|
|||
|
||||
IdentityProviderService.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]),
|
||||
_sandboxConfigured: false,
|
||||
|
||||
observe: function observe(aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
|
@ -83,6 +84,14 @@ IdentityProviderService.prototype = {
|
|||
|
||||
shutdown: function RP_shutdown() {
|
||||
this.reset();
|
||||
|
||||
if (this._sandboxConfigured) {
|
||||
// Tear down message manager listening on the hidden window
|
||||
Cu.import("resource://gre/modules/DOMIdentity.jsm");
|
||||
DOMIdentity._configureMessages(Services.appShell.hiddenDOMWindow, false);
|
||||
this._sandboxConfigured = false;
|
||||
}
|
||||
|
||||
Services.obs.removeObserver(this, "quit-application-granted");
|
||||
},
|
||||
|
||||
|
@ -432,6 +441,14 @@ IdentityProviderService.prototype = {
|
|||
*/
|
||||
_createProvisioningSandbox: function _createProvisioningSandbox(aURL, aCallback) {
|
||||
log("_createProvisioningSandbox:", aURL);
|
||||
|
||||
if (!this._sandboxConfigured) {
|
||||
// Configure message manager listening on the hidden window
|
||||
Cu.import("resource://gre/modules/DOMIdentity.jsm");
|
||||
DOMIdentity._configureMessages(Services.appShell.hiddenDOMWindow, true);
|
||||
this._sandboxConfigured = true;
|
||||
}
|
||||
|
||||
new Sandbox(aURL, aCallback);
|
||||
},
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче