Skip to content

Instantly share code, notes, and snippets.

@jaredhirsch
Created February 27, 2013 20:19
Show Gist options
  • Save jaredhirsch/5051319 to your computer and use it in GitHub Desktop.
Save jaredhirsch/5051319 to your computer and use it in GitHub Desktop.
diff --cc bin/keysigner
index db7e49a,1f668ba..0000000
--- a/bin/keysigner
+++ b/bin/keysigner
@@@ -22,7 -23,7 +23,11 @@@ heartbeat = require('../lib/heartbeat')
shutdown = require('../lib/shutdown'),
computecluster = require('compute-cluster'),
urlparse = require('urlparse'),
++<<<<<<< HEAD
+toobusy = require('../lib/busy_middleware.js');
++=======
+ certKey = require('../lib/wsapi/cert_key.js');
++>>>>>>> b2g
logger.info("keysigner starting up");
diff --cc bin/verifier
index 1c108fd,3718a74..0000000
--- a/bin/verifier
+++ b/bin/verifier
@@@ -19,7 -20,7 +20,11 @@@ logger = require('../lib/logging').logg
config = require('../lib/configuration'),
shutdown = require('../lib/shutdown'),
statsd = require('../lib/statsd'),
++<<<<<<< HEAD
+toobusy = require('../lib/busy_middleware.js');
++=======
+ booleanQuery = require('../lib/boolean-query');
++>>>>>>> b2g
logger.info("verifier server starting up");
diff --cc lib/db/mysql.js
index 19997d5,5b5ebf0..0000000
--- a/lib/db/mysql.js
+++ b/lib/db/mysql.js
@@@ -486,9 -489,15 +491,21 @@@ exports.completePasswordReset = functio
function(err) {
if (err) return cb(err);
++<<<<<<< HEAD
+ // update the password!
+ exports.updatePassword(uid, password || o.passwd, true, function(err) {
+ cb(err, o.email, uid);
++=======
+
+ // mark this address as verified
+ addEmailToUser(uid, o.email, 'secondary', function(err){
+ if (err) return cb(err);
+
+ // update the password!
+ exports.updatePassword(uid, o.passwd, true, function(err) {
+ cb(err, o.email, uid);
+ });
++>>>>>>> b2g
});
});
});
diff --cc lib/static/views.js
index cccc015,d30b2d2..0000000
--- a/lib/static/views.js
+++ b/lib/static/views.js
@@@ -54,23 -53,22 +54,32 @@@ function renderCachableView(req, res, t
options.enable_development_menu = config.get('enable_development_menu');
- // The real version number is not ready until sometime after initial load,
- // until it is ready a fake randomly generated string is used. Go get
- // the real SHA whenever it is actually needed so that the randomly
- // generated SHA is not returned to the user.
- options.commit = version();
+ // Get the SHA associated with this code.
+ version(function(commit) {
+ options.commit = commit;
- res.local('util', util);
- res.render(template, options);
+ res.local('util', util);
+ res.render(template, options);
+ });
+}
+
+
+function isProductionEnvironment() {
+ return [
+ 'https://login.persona.org',
+ 'https://login.anosrep.org'
+ ].indexOf(config.get('public_url')) !== -1;
}
++<<<<<<< HEAD
++=======
+ const X_FRAME_ALLOWED = [
+ '/communication_iframe',
+ '/relay',
+ '/tos',
+ '/privacy'
+ ];
++>>>>>>> b2g
exports.setup = function(app) {
diff --cc lib/wsapi.js
index 8a5ccc9,ff2c522..0000000
--- a/lib/wsapi.js
+++ b/lib/wsapi.js
@@@ -300,6 -285,9 +303,12 @@@ exports.setup = function(options, app)
secure: overSSL
}
});
++<<<<<<< HEAD
++=======
+
+ app.use(booleanQuery);
+
++>>>>>>> b2g
app.use(function(req, resp, next) {
var purl = url.parse(req.url);
diff --cc lib/wsapi/stage_user.js
index 68fb0e1,2cdac2b..0000000
--- a/lib/wsapi/stage_user.js
+++ b/lib/wsapi/stage_user.js
@@@ -58,30 -64,50 +64,74 @@@ exports.process = function(req, res)
}
try {
++<<<<<<< HEAD
+ // upon success, stage_user returns a secret (that'll get baked into a url
+ // and given to the user), on failure it throws
+ db.stageUser(req.params.email, hash, function(err, secret) {
+ if (err) {
+ cef_logger.alert("DB_FAILURE", "Cannot stage user; dbwriter failure", req, {msg: err});
+ return wsapi.databaseDown(res, err);
+ }
+
+ // store the email being registered in the session data
+ if (!req.session) req.session = {};
+
+ // store the secret we're sending via email in the users session, as checking
+ // that it still exists in the database is the surest way to determine the
+ // status of the email verification.
+ req.session.pendingCreation = secret;
+
+ res.json({ success: true });
+
+ // let's now kick out a verification email!
+ email.sendNewUserEmail(req.params.email, req.params.site, secret, langContext);
+ });
++=======
+ if (allowUnverified) {
+ // if its ok to be unverified, then create the user right now,
+ // and stage their email instead.
+ db.createUnverifiedUser(req.params.email, hash, function(err, uid, secret) {
+ if (err) {
+ cef_logger.alert("DB_FAILURE", "Cannot create unverified user; dbwriter failure", req, {msg: err});
+ return wsapi.databaseDown(res, err);
+ }
+
+ if (!req.session) req.session = {};
+ req.session.pendingAddition = secret;
+
+ res.json({ success: true, unverified: true });
+
+ email.sendConfirmationEmail(req.params.email, req.params.site, secret, langContext);
+ });
+ } else {
+ // the typical flow
+
+ // upon success, stage_user returns a secret (that'll get baked into a url
+ // and given to the user), on failure it throws
+ db.stageUser(req.params.email, hash, function(err, secret) {
+ if (err) {
+ cef_logger.alert("DB_FAILURE", "Cannot stage user; dbwriter failure", req, {msg: err});
+ return wsapi.databaseDown(res, err);
+ }
+
+ // store the email being registered in the session data
+ if (!req.session) req.session = {};
+
+ // store the secret we're sending via email in the users session, as checking
+ // that it still exists in the database is the surest way to determine the
+ // status of the email verification.
+ req.session.pendingCreation = secret;
+
+ res.json({ success: true });
+
+ // let's now kick out a verification email!
+ email.sendNewUserEmail(req.params.email, req.params.site, secret, langContext);
+ });
+ }
++>>>>>>> b2g
} catch(e) {
// we should differentiate tween' 400 and 500 here.
- httputils.badRequest(res, e.toString());
+ httputils.badRequest(res, String(e));
}
});
});
diff --cc resources/static/common/js/network.js
index e3fb896,05a304a..0000000
--- a/resources/static/common/js/network.js
+++ b/resources/static/common/js/network.js
@@@ -758,47 -765,13 +767,57 @@@ BrowserID.Network = (function()
},
/**
++<<<<<<< HEAD
+ * Request that an account transitions from a primary to a secondary. Used
+ * whenever a user has only primary addresses and one of the addresses
+ * belongs to an IdP which converts to a secondary.
+ * @method requestTransitionToSecondary
+ * @param {string} email
+ * @param {string} password
+ * @param {string} origin - site user is trying to sign in to.
+ * @param {function} [onComplete] - Callback to call when complete.
+ * @param {function} [onFailure] - Called on XHR failure.
+ */
+ requestTransitionToSecondary: function(email, password, origin, onComplete, onFailure) {
+ var postData = {
+ email: email,
+ pass: password,
+ site : origin
+ };
+ stageAddressForVerification(postData, "/wsapi/stage_transition", onComplete, onFailure);
+ },
+
+ /**
+ * Complete transition to secondary
+ * @method completeTransitionToSecondary
+ * @param {string} token - token to register for.
+ * @param {string} password
+ * @param {function} [onComplete] - Called when complete.
+ * @param {function} [onFailure] - Called on XHR failure.
+ */
+ completeTransitionToSecondary: completeAddressVerification.curry("/wsapi/complete_transition"),
+
+ /**
+ * Check the registration status of a transition to secondary
+ * @method checkTransitionToSecondary
+ * @param {function} [onsuccess] - called when complete.
+ * @param {function} [onfailure] - called on xhr failure.
+ */
+ checkTransitionToSecondary: function(email, onComplete, onFailure) {
+ get({
+ url: "/wsapi/transition_status?email=" + encodeURIComponent(email),
+ success: handleAddressVerifyCheckResponse.curry(onComplete),
+ error: onFailure
+ });
++=======
+ * Set whether the network should pass allowUnverified=true in
+ * its requests.
+ * @method setAllowUnverified
+ * @param {boolean} [allow] - True or false, to allow.
+ */
+ setAllowUnverified: function(allow) {
+ allow_unverified = allow;
++>>>>>>> b2g
}
};
diff --cc resources/static/common/js/user.js
index d077bf8,dd30480..0000000
--- a/resources/static/common/js/user.js
+++ b/resources/static/common/js/user.js
@@@ -640,11 -689,11 +692,16 @@@ BrowserID.User = (function()
* info.reason {string} - if status false, reason of failure.
* @param {function} [onFailure] - Called on XHR failure.
*/
++<<<<<<< HEAD
+ requestPasswordReset: function(email, onComplete, onFailure) {
+ User.addressInfo(email, function(info) {
++=======
+ requestPasswordReset: function(email, password, onComplete, onFailure) {
+ User.addressInfo(email, 'default', function(info) {
++>>>>>>> b2g
// user is not known. Can't request a password reset.
if (info.state === "unknown") {
- complete(onComplete, { success: false, reason: "invalid_user" });
+ complete(onComplete, { success: false, reason: "invalid_email" });
}
// user is trying to reset the password of a primary address.
else if (info.type === "primary") {
@@@ -1158,78 -1197,82 +1246,143 @@@
* @param {function} [onComplete] - Called with assertion, null otw.
* @param {function} [onFailure] - Called on error.
*/
++<<<<<<< HEAD
+ getAssertion: function(email, audience, onComplete, onFailure) {
+ function complete(status) {
+ onComplete && onComplete(status);
+ }
+
+ var storedID = storage.getEmail(email),
+ assertion,
+ self=this;
+
+ function createAssertion(idInfo) {
+ // we use the current time from the browserid servers
+ // to avoid issues with clock drift on user's machine.
+ // (issue #329)
+ network.serverTime(function(serverTime) {
+ var sk = jwcrypto.loadSecretKeyFromObject(idInfo.priv);
+
+ // assertions are valid for 2 minutes
+ var expirationMS = serverTime.getTime() + (2 * 60 * 1000);
+ var expirationDate = new Date(expirationMS);
+
+ // yield to the render thread, important on IE8 so we don't
+ // raise "script has become unresponsive" errors.
+ setTimeout(function() {
+ jwcrypto.assertion.sign(
+ {}, {audience: audience, expiresAt: expirationDate},
+ sk,
+ function(err, signedAssertion) {
+ assertion = jwcrypto.cert.bundle([idInfo.cert], signedAssertion);
+ storage.site.set(audience, "email", email);
+ complete(assertion);
+ });
+ }, 0);
+ }, onFailure);
+ }
+
+ if (storedID) {
+ prepareDeps();
+ if (storedID.priv) {
+ // parse the secret key
+ // yield to the render thread!
+ setTimeout(function() {
+ createAssertion(storedID);
+ }, 0);
+ }
+ else {
+ // first we have to get the address info, then attempt
+ // a provision, then if the user is provisioned, go and get an
+ // assertion.
+ User.addressInfo(email, function(info) {
+ if (info.type === "primary") {
+ User.provisionPrimaryUser(email, info, function(status) {
+ if (status === "primary.verified") {
+ User.getAssertion(email, audience, onComplete, onFailure);
+ }
+ else {
+ complete(null);
+ }
++=======
+ getAssertion: function(email, audience, forceIssuer, onComplete, onFailure) {
+ // we use the current time from the browserid servers
+ // to avoid issues with clock drift on user's machine.
+ // (issue #329)
+ function complete(status) {
+ onComplete && onComplete(status);
+ }
+
+ var storedID,
+ assertion,
+ self=this;
+
+ if ('default' === forceIssuer)
+ storedID = storage.getEmail(email);
+ else
+ storedID = storage.getForceIssuerEmail(email, forceIssuer);
+
+ function createAssertion(idInfo) {
+ network.serverTime(function(serverTime) {
+ var sk = jwcrypto.loadSecretKeyFromObject(idInfo.priv);
+
+ setTimeout(function() {
+ // assertions are valid for 2 minutes
+ var expirationMS = serverTime.getTime() + (2 * 60 * 1000);
+ var expirationDate = new Date(expirationMS);
+
+ jwcrypto.assertion.sign(
+ {}, {audience: audience, expiresAt: expirationDate},
+ sk,
+ function(err, signedAssertion) {
+ assertion = jwcrypto.cert.bundle([idInfo.cert], signedAssertion);
+ storage.site.set(audience, "email", email);
+ complete(assertion);
+ });
+ }, 0);
+ }, onFailure);
+ }
+
+ if (storedID) {
+ prepareDeps();
+ if (storedID.priv) {
+ // parse the secret key
+ // yield to the render thread!
+ setTimeout(function() {
+ createAssertion(storedID);
+ }, 0);
+ }
+ else {
+ // TODO what will the type of forceIssuer email addresses be?
+ if (storedID.type === "primary" && 'default' === User.forceIssuer) {
+ // first we have to get the address info, then attempt
+ // a provision, then if the user is provisioned, go and get an
+ // assertion.
+ User.addressInfo(email, User.forceIssuer, function(info) {
+ User.provisionPrimaryUser(email, info, function(status) {
+ if (status === "primary.verified") {
+ User.getAssertion(email, audience, User.forceIssuer, onComplete, onFailure);
+ }
+ else {
+ complete(null);
+ }
+ }, onFailure);
++>>>>>>> b2g
}, onFailure);
}
else {
// we have no key for this identity, go generate the key,
// sync it and then get the assertion recursively.
User.syncEmailKeypair(email, function(status) {
- User.getAssertion(email, audience, onComplete, onFailure);
+ User.getAssertion(email, audience, forceIssuer, onComplete, onFailure);
}, onFailure);
}
- }
- }
- else {
- complete(null);
+ }, onFailure);
}
+ }
+ else {
+ complete(null);
+ }
},
/**
diff --cc resources/static/dialog/css/style.css
index 4019739,96df97e..0000000
--- a/resources/static/dialog/css/style.css
+++ b/resources/static/dialog/css/style.css
@@@ -76,9 -76,9 +76,13 @@@ h3
.home {
- width: 161px;
+ width: 211px;
height: 40px;
++<<<<<<< HEAD
+ background: url("data:image/png;base64,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") 0 0 no-repeat; /* source: /dialog/i/persona-logo-transparent.png */
++=======
+ background: url("/dialog/i/firefox-accounts-logo.png") 0 0 no-repeat;
++>>>>>>> b2g
text-indent: -9999px;
display: inline-block;
*display: block;
diff --cc resources/static/dialog/js/misc/state.js
index fce0a92,3dc3d1c..0000000
--- a/resources/static/dialog/js/misc/state.js
+++ b/resources/static/dialog/js/misc/state.js
@@@ -199,43 -204,56 +205,77 @@@ BrowserID.State = (function()
complete(info.complete);
});
+ // B2G forceIssuer on primary
+ handleState("new_fxaccount", function(msg, info) {
+ self.newFxAccountEmail = info.email;
+
+ startAction(false, "doSetPassword", info);
+ complete(info.complete);
+ });
+
handleState("password_set", function(msg, info) {
++<<<<<<< HEAD
+ /* A password can be set for one of three reasons -
+ * 1) This is a new user
+ * 2) A user is adding the first secondary address to an account that
+ * consists only of primary addresses
+ * 3) A primary address was downgraded to a secondary and the user
+ * has no password in the DB.
+ *
+ * #1 is taken care of by newUserEmail, #2 by addEmailEmail,
+ * and #3 by transitionNoPassword
+ */
+ info = _.extend({ email: self.newUserEmail || self.addEmailEmail ||
+ self.transitionNoPassword }, info);
+
++=======
+ /* A password can be set for several reasons
+ * 1) This is a new user
+ * 2) A user is adding the first secondary address to an account that
+ * consists only of primary addresses
+ * 3) an existing user has forgotten their password and wants to reset it.
+ * 4) A primary address was downgraded to a secondary and the user
+ * has no password in the DB.
+ * 5) RP is using forceIssuer and we have a primary email address with
+ * no password for the user
+ * #1 is taken care of by newUserEmail, #2 by addEmailEmail, #3 by resetPasswordEmail,
+ * #4 by transitionNoPassword and #5 by fxAccountEmail
+ */
+ info = _.extend({ email: self.newUserEmail || self.addEmailEmail ||
+ self.resetPasswordEmail || self.transitionNoPassword ||
+ self.newFxAccountEmail}, info);
++>>>>>>> b2g
if(self.newUserEmail) {
startAction(false, "doStageUser", info);
}
else if(self.addEmailEmail) {
startAction(false, "doStageEmail", info);
}
- else if(self.resetPasswordEmail) {
- startAction(false, "doStageResetPassword", info);
- }
else if (self.transitionNoPassword) {
- startAction(false, "doStageResetPassword", info);
+ redirectToState("stage_transition_to_secondary", info);
}
+ else if(self.newFxAccountEmail) {
+ startAction(false, "doStageUser", info);
+ // TODO startAction(false, "doStageResetPassword", info); ???
+ }
});
handleState("user_staged", handleEmailStaged.curry("doConfirmUser"));
+ handleState("unverified_created", function(msg, info) {
+ startAction(false, "doAuthenticateWithUnverifiedEmail", info);
+ });
+
handleState("user_confirmed", handleEmailConfirmed);
+ handleState("stage_transition_to_secondary", function(msg, info) {
+ startAction(false, "doStageTransitionToSecondary", info);
+ });
+
+ handleState("transition_to_secondary_staged", handleEmailStaged.curry("doConfirmTransitionToSecondary"));
+
+ handleState("transition_to_secondary_confirmed", handleEmailConfirmed);
+
handleState("upgraded_primary_user", function (msg, info) {
user.usedAddressAsPrimary(info.email, function () {
info.state = 'known';
@@@ -371,9 -415,10 +437,9 @@@
startAction("doAuthenticate", info);
}
else if ("transition_no_password" === info.state) {
- self.transitionNoPassword = info.email;
- startAction("doSetPassword", _.extend({transition_no_password: true}, info));
+ redirectToState("transition_no_password", info);
}
- else if (info.state === 'unverified') {
+ else if (info.state === 'unverified' && !self.allowUnverified) {
// user selected an unverified secondary email, kick them over to the
// verify screen.
redirectToState("stage_reverify_email", info);
diff --cc resources/static/dialog/js/modules/actions.js
index 5e9d7fa,fe8b586..0000000
--- a/resources/static/dialog/js/modules/actions.js
+++ b/resources/static/dialog/js/modules/actions.js
@@@ -95,8 -95,19 +95,22 @@@ BrowserID.Modules.Actions = (function(
startService("required_email", info);
},
++<<<<<<< HEAD
++=======
+ doAuthenticateWithUnverifiedEmail: function(info) {
+ var self = this;
+ dialogHelpers.authenticateUser.call(this, info.email, info.password, function() {
+ self.publish("authenticated", info);
+ });
+ },
+
+ doResetPassword: function(info) {
+ startService("set_password", _.extend(info, { password_reset: true }), "reset_password");
+ },
+
++>>>>>>> b2g
doStageResetPassword: function(info) {
- dialogHelpers.resetPassword.call(this, info.email, info.password, info.ready);
+ dialogHelpers.resetPassword.call(this, info.email, info.ready);
},
doConfirmResetPassword: function(info) {
diff --cc resources/static/dialog/js/modules/authenticate.js
index 393009c,0595110..0000000
--- a/resources/static/dialog/js/modules/authenticate.js
+++ b/resources/static/dialog/js/modules/authenticate.js
@@@ -38,8 -39,11 +39,16 @@@ BrowserID.Modules.Authenticate = (funct
}
function hasPassword(info) {
++<<<<<<< HEAD
+ return (info && info.email && info.type === "secondary" &&
+ (info.state === "known" || info.state === "transition_to_secondary" ));
++=======
+ /*jshint validthis:true*/
+ return (info && info.email && info.type === "secondary" &&
+ (info.state === "known" ||
+ info.state === "transition_to_secondary" ||
+ info.state === "unverified" && this.allowUnverified));
++>>>>>>> b2g
}
function initialState(info) {
@@@ -118,7 -127,19 +132,23 @@@
}
}
++<<<<<<< HEAD
+ function authenticate(done) {
++=======
+ function createFxAccount(callback, forceIssuer) {
+ /*jshint validthis: true*/
+ var self=this,
+ email = getEmail();
+
+ if (email) {
+ self.close("new_fxaccount", { email: email, fxaccount: true }, { email: email });
+ } else {
+ complete(callback);
+ }
+ }
+
+ function authenticate() {
++>>>>>>> b2g
/*jshint validthis: true*/
var email = getEmail(),
pass = helpers.getAndValidatePassword(PASSWORD_SELECTOR),
diff --cc resources/static/dialog/js/modules/set_password.js
index 6260bac,e8f12bd..0000000
--- a/resources/static/dialog/js/modules/set_password.js
+++ b/resources/static/dialog/js/modules/set_password.js
@@@ -39,7 -39,9 +39,13 @@@ BrowserID.Modules.SetPassword = (functi
password_reset: !!options.password_reset,
transition_no_password: !!options.transition_no_password,
domain: helpers.getDomainFromEmail(options.email),
++<<<<<<< HEAD
+ cancelable: options.cancelable !== false
++=======
+ fxaccount: !!options.fxaccount,
+ cancelable: options.cancelable !== false,
+ personaTOSPP: options.personaTOSPP
++>>>>>>> b2g
});
if (options.siteTOSPP) {
diff --cc resources/static/dialog/views/set_password.ejs
index c3ae67c,377a87d..0000000
--- a/resources/static/dialog/views/set_password.ejs
+++ b/resources/static/dialog/views/set_password.ejs
@@@ -10,13 -10,15 +10,20 @@@
<ul class="inputs">
<li>
<% if (!password_reset) { %>
++<<<<<<< HEAD
+ <% if (transition_no_password) { %>
+ <%- format(gettext("%(idp)s no longer allows you to log into Persona with your %(idp)s password. Please create a new password to use with your Persona account."), {
++=======
+ <% if (fxaccount) { %>
+ <%= gettext("Your email address is new to us. Please create a password to use with FirefoxOS.") %>
+ <% } else if (transition_no_password) { %>
+ <%- format(gettext("%(idp) no longer allows you to log into Persona with your %(idp) password. Please create a new password to use with your Persona account."), {
++>>>>>>> b2g
idp: "<strong>" + escape(domain) + "</strong>"
}) %>
- <% } else { %>
- <%= gettext("Your email address is new to us. Please create a password to use with Persona.") %>
<% } %>
+ <% } else { %>
+ <%= gettext("Your email address is new to us. Please create a password to use with Persona.") %>
<% } %>
</li>
diff --cc resources/static/include_js/_jschannel.js
index ff80e71,bb99304..0000000
--- a/resources/static/include_js/_jschannel.js
+++ b/resources/static/include_js/_jschannel.js
@@@ -613,3 -625,695 +613,698 @@@
};
})();
++<<<<<<< HEAD:resources/static/include_js/_jschannel.js
++=======
+ // local embedded copy of winchan: http://github.com/lloyd/winchan
+ // BEGIN WINCHAN
+
+ ;WinChan = (function() {
+ var RELAY_FRAME_NAME = "__winchan_relay_frame";
+ var CLOSE_CMD = "die";
+
+ // a portable addListener implementation
+ function addListener(w, event, cb) {
+ if(w.attachEvent) w.attachEvent('on' + event, cb);
+ else if (w.addEventListener) w.addEventListener(event, cb, false);
+ }
+
+ // a portable removeListener implementation
+ function removeListener(w, event, cb) {
+ if(w.detachEvent) w.detachEvent('on' + event, cb);
+ else if (w.removeEventListener) w.removeEventListener(event, cb, false);
+ }
+
+ // checking for IE8 or above
+ function isInternetExplorer() {
+ var rv = -1; // Return value assumes failure.
+ if (navigator.appName === 'Microsoft Internet Explorer') {
+ var ua = navigator.userAgent;
+ var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
+ if (re.exec(ua) != null)
+ rv = parseFloat(RegExp.$1);
+ }
+ return rv >= 8;
+ }
+
+ // checking Mobile Firefox (Fennec)
+ function isFennec() {
+ try {
+ // We must check for both XUL and Java versions of Fennec. Both have
+ // distinct UA strings.
+ var userAgent = navigator.userAgent;
+ return (userAgent.indexOf('Fennec/') != -1) || // XUL
+ (userAgent.indexOf('Firefox/') != -1 && userAgent.indexOf('Android') != -1); // Java
+ } catch(e) {};
+ return false;
+ }
+
+ // feature checking to see if this platform is supported at all
+ function isSupported() {
+ return (window.JSON && window.JSON.stringify &&
+ window.JSON.parse && window.postMessage);
+ }
+
+ // given a URL, extract the origin
+ function extractOrigin(url) {
+ if (!/^https?:\/\//.test(url)) url = window.location.href;
+ var m = /^(https?:\/\/[\-_a-zA-Z\.0-9:]+)/.exec(url);
+ if (m) return m[1];
+ return url;
+ }
+
+ // find the relay iframe in the opener
+ function findRelay() {
+ var loc = window.location;
+ var frames = window.opener.frames;
+ var origin = loc.protocol + '//' + loc.host;
+ for (var i = frames.length - 1; i >= 0; i--) {
+ try {
+ if (frames[i].location.href.indexOf(origin) === 0 &&
+ frames[i].name === RELAY_FRAME_NAME)
+ {
+ return frames[i];
+ }
+ } catch(e) { }
+ }
+ return;
+ }
+
+ var isIE = isInternetExplorer();
+
+ if (isSupported()) {
+ /* General flow:
+ * 0. user clicks
+ * (IE SPECIFIC) 1. caller adds relay iframe (served from trusted domain) to DOM
+ * 2. caller opens window (with content from trusted domain)
+ * 3. window on opening adds a listener to 'message'
+ * (IE SPECIFIC) 4. window on opening finds iframe
+ * 5. window checks if iframe is "loaded" - has a 'doPost' function yet
+ * (IE SPECIFIC5) 5a. if iframe.doPost exists, window uses it to send ready event to caller
+ * (IE SPECIFIC5) 5b. if iframe.doPost doesn't exist, window waits for frame ready
+ * (IE SPECIFIC5) 5bi. once ready, window calls iframe.doPost to send ready event
+ * 6. caller upon reciept of 'ready', sends args
+ */
+ return {
+ open: function(opts, cb) {
+ if (!cb) throw "missing required callback argument";
+
+ // test required options
+ var err;
+ if (!opts.url) err = "missing required 'url' parameter";
+ if (!opts.relay_url) err = "missing required 'relay_url' parameter";
+ if (err) setTimeout(function() { cb(err); }, 0);
+
+ // supply default options
+ if (!opts.window_name) opts.window_name = null;
+ if (!opts.window_features || isFennec()) opts.window_features = undefined;
+
+ // opts.params may be undefined
+
+ var iframe;
+
+ // sanity check, are url and relay_url the same origin?
+ var origin = extractOrigin(opts.url);
+ if (origin !== extractOrigin(opts.relay_url)) {
+ return setTimeout(function() {
+ cb('invalid arguments: origin of url and relay_url must match');
+ }, 0);
+ }
+
+ var messageTarget;
+
+ if (isIE) {
+ // first we need to add a "relay" iframe to the document that's served
+ // from the target domain. We can postmessage into a iframe, but not a
+ // window
+ iframe = document.createElement("iframe");
+ // iframe.setAttribute('name', framename);
+ iframe.setAttribute('src', opts.relay_url);
+ iframe.style.display = "none";
+ iframe.setAttribute('name', RELAY_FRAME_NAME);
+ document.body.appendChild(iframe);
+ messageTarget = iframe.contentWindow;
+ }
+
+ var w = window.open(opts.url, opts.window_name, opts.window_features);
+
+ if (!messageTarget) messageTarget = w;
+
+ var req = JSON.stringify({a: 'request', d: opts.params});
+
+ // cleanup on unload
+ function cleanup() {
+ if (iframe) document.body.removeChild(iframe);
+ iframe = undefined;
+ if (w) {
+ try {
+ w.close();
+ } catch (securityViolation) {
+ // This happens in Opera 12 sometimes
+ // see https://github.com/mozilla/browserid/issues/1844
+ messageTarget.postMessage(CLOSE_CMD, origin);
+ }
+ }
+ w = messageTarget = undefined;
+ }
+
+ addListener(window, 'unload', cleanup);
+
+ function onMessage(e) {
+ try {
+ var d = JSON.parse(e.data);
+ if (d.a === 'ready') messageTarget.postMessage(req, origin);
+ else if (d.a === 'error') {
+ if (cb) {
+ cb(d.d);
+ cb = null;
+ }
+ } else if (d.a === 'response') {
+ removeListener(window, 'message', onMessage);
+ removeListener(window, 'unload', cleanup);
+ cleanup();
+ if (cb) {
+ cb(null, d.d);
+ cb = null;
+ }
+ }
+ } catch(err) { }
+ }
+
+ addListener(window, 'message', onMessage);
+
+ return {
+ close: cleanup,
+ focus: function() {
+ if (w) {
+ try {
+ w.focus();
+ } catch (e) {
+ // IE7 blows up here, do nothing
+ }
+ }
+ }
+ };
+ }
+ };
+ } else {
+ return {
+ open: function(url, winopts, arg, cb) {
+ setTimeout(function() { cb("unsupported browser"); }, 0);
+ }
+ };
+ }
+ })();
+
+
+
+ // END WINCHAN
+
+ var BrowserSupport = (function() {
+ var win = window,
+ nav = navigator,
+ reason;
+
+ // For unit testing
+ function setTestEnv(newNav, newWindow) {
+ nav = newNav;
+ win = newWindow;
+ }
+
+ function getInternetExplorerVersion() {
+ var rv = -1; // Return value assumes failure.
+ if (nav.appName == 'Microsoft Internet Explorer') {
+ var ua = nav.userAgent;
+ var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
+ if (re.exec(ua) != null)
+ rv = parseFloat(RegExp.$1);
+ }
+
+ return rv;
+ }
+
+ function checkIE() {
+ var ieVersion = getInternetExplorerVersion(),
+ ieNosupport = ieVersion > -1 && ieVersion < 8;
+
+ if(ieNosupport) {
+ return "BAD_IE_VERSION";
+ }
+ }
+
+ function explicitNosupport() {
+ return checkIE();
+ }
+
+ function checkLocalStorage() {
+ // Firefox/Fennec/Chrome blow up when trying to access or
+ // write to localStorage. We must do two explicit checks, first
+ // whether the browser has localStorage. Second, we must check
+ // whether the localStorage can be written to. Firefox (at v11)
+ // throws an exception when querying win['localStorage']
+ // when cookies are disabled. Chrome (v17) excepts when trying to
+ // write to localStorage when cookies are disabled. If an
+ // exception is thrown, then localStorage is disabled. If no
+ // exception is thrown, hasLocalStorage will be true if the
+ // browser supports localStorage and it can be written to.
+ try {
+ var hasLocalStorage = 'localStorage' in win
+ // Firefox will except here if cookies are disabled.
+ && win['localStorage'] !== null;
+
+ if(hasLocalStorage) {
+ // browser has localStorage, check if it can be written to. If
+ // cookies are disabled, some browsers (Chrome) will except here.
+ win['localStorage'].setItem("test", "true");
+ win['localStorage'].removeItem("test");
+ }
+ else {
+ // Browser does not have local storage.
+ return "LOCALSTORAGE_NOT_SUPPORTED";
+ }
+ } catch(e) {
+ return "LOCALSTORAGE_DISABLED";
+ }
+ }
+
+ function checkPostMessage() {
+ if(!win.postMessage) {
+ return "POSTMESSAGE_NOT_SUPPORTED";
+ }
+ }
+
+ function checkJSON() {
+ if(!(window.JSON && window.JSON.stringify && window.JSON.parse)) {
+ return "JSON_NOT_SUPPORTED";
+ }
+ }
+
+ function isSupported() {
+ reason = explicitNosupport() || checkLocalStorage() || checkPostMessage() || checkJSON();
+
+ return !reason;
+ }
+
+
+ function getNoSupportReason() {
+ return reason;
+ }
+
+ return {
+ /**
+ * Set the test environment.
+ * @method setTestEnv
+ */
+ setTestEnv: setTestEnv,
+ /**
+ * Check whether the current browser is supported
+ * @method isSupported
+ * @returns {boolean}
+ */
+ isSupported: isSupported,
+ /**
+ * Called after isSupported, if isSupported returns false. Gets the reason
+ * why browser is not supported.
+ * @method getNoSupportReason
+ * @returns {string}
+ */
+ getNoSupportReason: getNoSupportReason
+ };
+ }());
+
+ if (!navigator.id) {
+ // Is there a native implementation on this platform?
+ // If so, hook navigator.id onto it.
+ if (navigator.mozId) {
+ navigator.id = navigator.mozId;
+ } else {
+ navigator.id = {};
+ }
+ }
+
+ if (!navigator.id.request || navigator.id._shimmed) {
+ var ipServer = "https://login.persona.org";
+ var userAgent = navigator.userAgent;
+ // We must check for both XUL and Java versions of Fennec. Both have
+ // distinct UA strings.
+ var isFennec = (userAgent.indexOf('Fennec/') != -1) || // XUL
+ (userAgent.indexOf('Firefox/') != -1 && userAgent.indexOf('Android') != -1); // Java
+
+ var windowOpenOpts =
+ (isFennec ? undefined :
+ "menubar=0,location=1,resizable=1,scrollbars=1,status=0,dialog=1,minimizable=1,width=700,height=375");
+
+ var w;
+
+ // table of registered observers
+ var observers = {
+ login: null,
+ logout: null,
+ ready: null
+ };
+
+ var loggedInUser;
+
+ var compatMode = undefined;
+ function checkCompat(requiredMode) {
+ if (requiredMode === true) {
+ // this deprecation warning should be re-enabled when the .watch and .request APIs become final.
+ // try { console.log("this site uses deprecated APIs (see documentation for navigator.id.request())"); } catch(e) { }
+ }
+
+ if (compatMode === undefined) compatMode = requiredMode;
+ else if (compatMode != requiredMode) {
+ throw new Error("you cannot combine the navigator.id.watch() API with navigator.id.getVerifiedEmail() or navigator.id.get()" +
+ "this site should instead use navigator.id.request() and navigator.id.watch()");
+ }
+ }
+
+ var commChan,
+ waitingForDOM = false,
+ browserSupported = BrowserSupport.isSupported();
+
+ function domReady(callback) {
+ if (document.addEventListener) {
+ document.addEventListener('DOMContentLoaded', function contentLoaded() {
+ document.removeEventListener('DOMContentLoaded', contentLoaded);
+ callback();
+ }, false);
+ } else if (document.attachEvent && document.readyState) {
+ document.attachEvent('onreadystatechange', function ready() {
+ var state = document.readyState;
+ // 'interactive' is the same as DOMContentLoaded,
+ // but not all browsers use it, sadly.
+ if (state === 'loaded' || state === 'complete' || state === 'interactive') {
+ document.detachEvent('onreadystatechange', ready);
+ callback();
+ }
+ });
+ }
+ }
+
+
+ // this is for calls that are non-interactive
+ function _open_hidden_iframe() {
+ // If this is an unsupported browser, do not even attempt to add the
+ // IFRAME as doing so will cause an exception to be thrown in IE6 and IE7
+ // from within the communication_iframe.
+ if(!browserSupported) return;
+ var doc = window.document;
+
+ // can't attach iframe and make commChan without the body
+ if (!doc.body) {
+ if (!waitingForDOM) {
+ domReady(_open_hidden_iframe);
+ waitingForDOM = true;
+ }
+ return;
+ }
+
+ try {
+ if (!commChan) {
+ var iframe = doc.createElement("iframe");
+ iframe.style.display = "none";
+ doc.body.appendChild(iframe);
+ iframe.src = ipServer + "/communication_iframe";
+ commChan = Channel.build({
+ window: iframe.contentWindow,
+ origin: ipServer,
+ scope: "mozid_ni",
+ onReady: function() {
+ // once the channel is set up, we'll fire a loaded message. this is the
+ // cutoff point where we'll say if 'setLoggedInUser' was not called before
+ // this point, then it wont be called (XXX: optimize and improve me)
+ commChan.call({
+ method: 'loaded',
+ success: function(){
+ // NOTE: Do not modify without reading GH-2017
+ if (observers.ready) observers.ready();
+ }, error: function() {
+ }
+ });
+ }
+ });
+
+ commChan.bind('logout', function(trans, params) {
+ if (observers.logout) observers.logout();
+ });
+
+ commChan.bind('login', function(trans, params) {
+ if (observers.login) observers.login(params);
+ });
+
+ if (defined(loggedInUser)) {
+ commChan.notify({
+ method: 'loggedInUser',
+ params: loggedInUser
+ });
+ }
+ }
+ } catch(e) {
+ // channel building failed! let's ignore the error and allow higher
+ // level code to handle user messaging.
+ commChan = undefined;
+ }
+ }
+
+ function defined(item) {
+ return typeof item !== "undefined";
+ }
+
+ function warn(message) {
+ try {
+ console.warn(message);
+ } catch(e) {
+ /* ignore error */
+ }
+ }
+
+ function checkDeprecated(options, field) {
+ if(defined(options[field])) {
+ warn(field + " has been deprecated");
+ return true;
+ }
+ }
+
+ function checkRenamed(options, oldName, newName) {
+ if (defined(options[oldName]) &&
+ defined(options[newName])) {
+ throw new Error("you cannot supply *both* " + oldName + " and " + newName);
+ }
+ else if(checkDeprecated(options, oldName)) {
+ options[newName] = options[oldName];
+ delete options[oldName];
+ }
+ }
+
+ function internalWatch(options) {
+ if (typeof options !== 'object') return;
+
+ if (options.onlogin && typeof options.onlogin !== 'function' ||
+ options.onlogout && typeof options.onlogout !== 'function' ||
+ options.onready && typeof options.onready !== 'function')
+ {
+ throw new Error("non-function where function expected in parameters to navigator.id.watch()");
+ }
+
+ if (!options.onlogin) throw new Error("'onlogin' is a required argument to navigator.id.watch()");
+ if (!options.onlogout) throw new Error("'onlogout' is a required argument to navigator.id.watch()");
+
+ observers.login = options.onlogin || null;
+ observers.logout = options.onlogout || null;
+ // NOTE: Do not modify without reading GH-2017
+ observers.ready = options.onready || null;
+
+ // back compat support for loggedInEmail
+ checkRenamed(options, "loggedInEmail", "loggedInUser");
+ loggedInUser = options.loggedInUser;
+
+ _open_hidden_iframe();
+ }
+
+ var api_called;
+ function getRPAPI() {
+ var rp_api = api_called;
+ if (rp_api === "request") {
+ if (observers.ready) rp_api = "watch_with_onready";
+ else rp_api = "watch_without_onready";
+ }
+
+ return rp_api;
+ }
+
+ function internalRequest(options) {
+ checkDeprecated(options, "requiredEmail");
+ checkRenamed(options, "tosURL", "termsOfService");
+ checkRenamed(options, "privacyURL", "privacyPolicy");
+
+ if (options.termsOfService && !options.privacyPolicy) {
+ warn("termsOfService ignored unless privacyPolicy also defined");
+ }
+
+ if (options.privacyPolicy && !options.termsOfService) {
+ warn("privacyPolicy ignored unless termsOfService also defined");
+ }
+
+ options.rp_api = getRPAPI();
+ // reset the api_called in case the site implementor changes which api
+ // method called the next time around.
+ api_called = null;
+
+ options.start_time = (new Date()).getTime();
+
+ // focus an existing window
+ if (w) {
+ try {
+ w.focus();
+ }
+ catch(e) {
+ /* IE7 blows up here, do nothing */
+ }
+ return;
+ }
+
+ if (!BrowserSupport.isSupported()) {
+ var reason = BrowserSupport.getNoSupportReason(),
+ url = "unsupported_dialog";
+
+ if(reason === "LOCALSTORAGE_DISABLED") {
+ url = "cookies_disabled";
+ }
+
+ w = window.open(
+ ipServer + "/" + url,
+ null,
+ windowOpenOpts);
+ return;
+ }
+
+ // notify the iframe that the dialog is running so we
+ // don't do duplicative work
+ if (commChan) commChan.notify({ method: 'dialog_running' });
+
+ w = WinChan.open({
+ url: ipServer + '/sign_in',
+ relay_url: ipServer + '/relay',
+ window_features: windowOpenOpts,
+ window_name: '__persona_dialog',
+ params: {
+ method: "get",
+ params: options
+ }
+ }, function(err, r) {
+ // unpause the iframe to detect future changes in login state
+ if (commChan) {
+ // update the loggedInUser in the case that an assertion was generated, as
+ // this will prevent the comm iframe from thinking that state has changed
+ // and generating a new assertion. IF, however, this request is not a success,
+ // then we do not change the loggedInUser - and we will let the comm frame determine
+ // if generating a logout event is the right thing to do
+ if (!err && r && r.email) {
+ commChan.notify({ method: 'loggedInUser', params: r.email });
+ }
+ commChan.notify({ method: 'dialog_complete' });
+ }
+
+ // clear the window handle
+ w = undefined;
+ if (!err && r && r.assertion) {
+ try {
+ if (observers.login) observers.login(r.assertion);
+ } catch(e) {
+ // client's observer threw an exception
+ }
+ }
+
+ // if either err indicates the user canceled the signin (expected) or a
+ // null response was sent (unexpected), invoke the .oncancel() handler.
+ if (err === 'client closed window' || !r) {
+ if (options && options.oncancel) options.oncancel();
+ delete options.oncancel;
+ }
+ });
+ };
+
+ navigator.id = {
+ request: function(options) {
+ if (this != navigator.id)
+ throw new Error("all navigator.id calls must be made on the navigator.id object");
+ options = options || {};
+ checkCompat(false);
+ api_called = "request";
+ // returnTo is used for post-email-verification redirect
+ if (!options.returnTo) options.returnTo = document.location.pathname;
+ return internalRequest(options);
+ },
+ watch: function(options) {
+ if (this != navigator.id)
+ throw new Error("all navigator.id calls must be made on the navigator.id object");
+ checkCompat(false);
+ internalWatch(options);
+ },
+ // logout from the current website
+ // The callback parameter is DEPRECATED, instead you should use the
+ // the .onlogout observer of the .watch() api.
+ logout: function(callback) {
+ if (this != navigator.id)
+ throw new Error("all navigator.id calls must be made on the navigator.id object");
+ // allocate iframe if it is not allocated
+ _open_hidden_iframe();
+ // send logout message if the commChan exists
+ if (commChan) commChan.notify({ method: 'logout' });
+ if (typeof callback === 'function') {
+ warn('navigator.id.logout callback argument has been deprecated.');
+ setTimeout(callback, 0);
+ }
+ },
+ // get an assertion
+ get: function(callback, passedOptions) {
+ var opts = {};
+ passedOptions = passedOptions || {};
+ opts.privacyPolicy = passedOptions.privacyPolicy || undefined;
+ opts.termsOfService = passedOptions.termsOfService || undefined;
+ opts.privacyURL = passedOptions.privacyURL || undefined;
+ opts.tosURL = passedOptions.tosURL || undefined;
+ opts.siteName = passedOptions.siteName || undefined;
+ opts.siteLogo = passedOptions.siteLogo || undefined;
+ // api_called could have been set to getVerifiedEmail already
+ api_called = api_called || "get";
+ if (checkDeprecated(passedOptions, "silent")) {
+ // Silent has been deprecated, do nothing. Placing the check here
+ // prevents the callback from being called twice, once with null and
+ // once after internalWatch has been called. See issue #1532
+ if (callback) setTimeout(function() { callback(null); }, 0);
+ return;
+ }
+
+ checkCompat(true);
+ internalWatch({
+ onlogin: function(assertion) {
+ if (callback) {
+ callback(assertion);
+ callback = null;
+ }
+ },
+ onlogout: function() {}
+ });
+ opts.oncancel = function() {
+ if (callback) {
+ callback(null);
+ callback = null;
+ }
+ observers.login = observers.logout = observers.ready = null;
+ };
+ internalRequest(opts);
+ },
+ // backwards compatibility with old API
+ getVerifiedEmail: function(callback) {
+ warn("navigator.id.getVerifiedEmail has been deprecated");
+ checkCompat(true);
+ api_called = "getVerifiedEmail";
+ navigator.id.get(callback);
+ },
+ // required for forwards compatibility with native implementations
+ _shimmed: true
+ };
+ }
+ }());
++>>>>>>> b2g:resources/static/include_js/include.js
diff --cc resources/static/test/cases/common/js/network.js
index e7e141e,2b1dfc0..0000000
--- a/resources/static/test/cases/common/js/network.js
+++ b/resources/static/test/cases/common/js/network.js
@@@ -493,6 -449,71 +493,74 @@@
});
++<<<<<<< HEAD
++=======
+ asyncTest("requestPasswordReset - true status", function() {
+ network.requestPasswordReset(TEST_EMAIL, "password", "origin", function onSuccess(status) {
+ ok(status, "password reset request success");
+ start();
+ }, testHelpers.unexpectedFailure);
+ });
+
+ asyncTest("requestPasswordReset with XHR failure", function() {
+ failureCheck(network.requestPasswordReset, TEST_EMAIL, "password", "origin");
+ });
+
+ asyncTest("completePasswordReset with valid token, no password required", function() {
+ network.completePasswordReset("token", undefined, function(registered) {
+ ok(registered);
+ start();
+ }, testHelpers.unexpectedFailure);
+ });
+
+ asyncTest("completePasswordReset with valid token, bad password", function() {
+ transport.useResult("badPassword");
+ network.completePasswordReset("token", "password",
+ testHelpers.unexpectedSuccess,
+ testHelpers.expectedXHRFailure);
+ });
+
+ asyncTest("completePasswordReset with valid token, password required", function() {
+ network.completePasswordReset("token", "password", function(registered) {
+ ok(registered);
+ start();
+ }, testHelpers.unexpectedFailure);
+ });
+
+ asyncTest("completePasswordReset with invalid token", function() {
+ transport.useResult("invalid");
+
+ network.completePasswordReset("token", "password", function(registered) {
+ equal(registered, false);
+ start();
+ }, testHelpers.unexpectedFailure);
+ });
+
+ asyncTest("completePasswordReset with XHR failure", function() {
+ failureCheck(network.completePasswordReset, "token", "password");
+ });
+
+ asyncTest("checkPasswordReset pending", testVerificationPending.curry("checkPasswordReset"));
+ asyncTest("checkPasswordReset mustAuth", testVerificationMustAuth.curry("checkPasswordReset"));
+ asyncTest("checkPasswordReset complete", testVerificationComplete.curry("checkPasswordReset"));
+
+
+ asyncTest("requestEmailReverify - true status", function() {
+ network.requestEmailReverify(TEST_EMAIL, "origin", function onSuccess(status) {
+ ok(status, "password reset request success");
+ start();
+ }, testHelpers.unexpectedFailure);
+ });
+
+ asyncTest("requestEmailReverify with XHR failure", function() {
+ failureCheck(network.requestEmailReverify, TEST_EMAIL, "origin");
+ });
+
+ asyncTest("checkEmailReverify pending", testVerificationPending.curry("checkEmailReverify"));
+ asyncTest("checkEmailReverify mustAuth", testVerificationMustAuth.curry("checkEmailReverify"));
+ asyncTest("checkEmailReverify complete", testVerificationComplete.curry("checkEmailReverify"));
+
++>>>>>>> b2g
asyncTest("serverTime", function() {
// I am forcing the server time to be 1.25 seconds off.
transport.setContextInfo("server_time", new Date().getTime() - 1250);
diff --cc resources/static/test/cases/common/js/user.js
index 63e61b2,6d8ca5e..0000000
--- a/resources/static/test/cases/common/js/user.js
+++ b/resources/static/test/cases/common/js/user.js
@@@ -637,6 -483,117 +637,120 @@@
}, testHelpers.unexpectedFailure);
});
++<<<<<<< HEAD
++=======
+ asyncTest("requestPasswordReset with known email - true status", function() {
+ var returnTo = "http://samplerp.org";
+ lib.setReturnTo(returnTo);
+
+ lib.requestPasswordReset("registered@testuser.com", "password", function(status) {
+ equal(status.success, true, "password reset for known user");
+ equal(storage.getReturnTo(), returnTo, "RP URL is stored for verification");
+
+ start();
+ }, testHelpers.unexpectedXHRFailure);
+ });
+
+ asyncTest("requestPasswordReset with unknown email - false status, invalid_user", function() {
+ lib.requestPasswordReset("unregistered@testuser.com", "password", function(status) {
+ equal(status.success, false, "password not reset for unknown user");
+ equal(status.reason, "invalid_user", "invalid_user is the reason");
+ start();
+ }, testHelpers.unexpectedXHRFailure);
+ });
+
+ asyncTest("requestPasswordReset with throttle - false status, throttle", function() {
+ xhr.useResult("throttle");
+ lib.requestPasswordReset("registered@testuser.com", "password", function(status) {
+ equal(status.success, false, "password not reset for throttle");
+ equal(status.reason, "throttle", "password reset was throttled");
+ start();
+ }, testHelpers.unexpectedXHRFailure);
+ });
+
+ asyncTest("requestPasswordReset with XHR failure", function() {
+ failureCheck(lib.requestPasswordReset, "registered@testuser.com", "password");
+ });
+
+ asyncTest("completePasswordReset with a good token", function() {
+ storage.addEmail(TEST_EMAIL);
+ storage.setReturnTo(testOrigin);
+
+ lib.completePasswordReset("token", "password", function onSuccess(info) {
+ testObjectValuesEqual(info, {
+ valid: true,
+ email: TEST_EMAIL,
+ returnTo: testOrigin
+ });
+
+ equal(storage.getReturnTo(), "", "initiating origin was removed");
+
+ start();
+ }, testHelpers.unexpectedXHRFailure);
+ });
+
+ asyncTest("completePasswordReset with a bad token", function() {
+ xhr.useResult("invalid");
+
+ lib.completePasswordReset("token", "password", function onSuccess(info) {
+ equal(info.valid, false, "bad token calls onSuccess with a false validity");
+ start();
+ }, testHelpers.unexpectedXHRFailure);
+ });
+
+ asyncTest("completePasswordReset with an XHR failure", function() {
+ xhr.useResult("ajaxError");
+
+ lib.completePasswordReset(
+ "token",
+ "password",
+ testHelpers.unexpectedSuccess,
+ testHelpers.expectedXHRFailure
+ );
+ });
+
+ asyncTest("requestEmailReverify with owned unverified email - false status", function() {
+ storage.addEmail(TEST_EMAIL);
+
+ var returnTo = "http://samplerp.org";
+ lib.setReturnTo(returnTo);
+ lib.requestEmailReverify(TEST_EMAIL, function(status) {
+ equal(status.success, true, "password reset for known user");
+ equal(storage.getReturnTo(), returnTo, "RP URL is stored for verification");
+
+ start();
+ }, testHelpers.unexpectedXHRFailure);
+ });
+
+ asyncTest("requestEmailReverify with unowned email - false status, invalid_user", function() {
+ lib.requestEmailReverify(TEST_EMAIL, function(status) {
+ testObjectValuesEqual(status, {
+ success: false,
+ reason: "invalid_email"
+ });
+ start();
+ }, testHelpers.unexpectedXHRFailure);
+ });
+
+ asyncTest("requestEmailReverify owned email with throttle - false status, throttle", function() {
+ xhr.useResult("throttle");
+ storage.addEmail(TEST_EMAIL);
+
+ lib.requestEmailReverify(TEST_EMAIL, function(status) {
+ testObjectValuesEqual(status, {
+ success: false,
+ reason: "throttle"
+ });
+ start();
+ }, testHelpers.unexpectedXHRFailure);
+ });
+
+ asyncTest("requestEmailReverify with XHR failure", function() {
+ storage.addEmail(TEST_EMAIL);
+ failureCheck(lib.requestEmailReverify, TEST_EMAIL);
+ });
+
++>>>>>>> b2g
asyncTest("authenticate with valid credentials, also syncs email with server", function() {
lib.authenticate(TEST_EMAIL, "testuser", function(authenticated) {
equal(true, authenticated, "we are authenticated!");
@@@ -808,9 -781,137 +922,140 @@@
});
});
++<<<<<<< HEAD
++=======
+ asyncTest("addEmail", function() {
+ var returnTo = "http://samplerp.org";
+ lib.setReturnTo(returnTo);
+
+ lib.addEmail("testuser@testuser.com", "password", function(added) {
+ ok(added, "user was added");
+
+ var identities = lib.getStoredEmailKeypairs();
+ equal("testuser@testuser.com" in identities, false, "new email is not added until confirmation.");
+
+ equal(storage.getReturnTo(), returnTo, "RP URL is stored for verification");
+
+ start();
+ }, testHelpers.unexpectedXHRFailure);
+ });
+
+ asyncTest("addEmail with addition refused", function() {
+ xhr.useResult("throttle");
+
+ lib.addEmail("testuser@testuser.com", "password", function(added) {
+ equal(added, false, "user addition was refused");
+
+ var identities = lib.getStoredEmailKeypairs();
+ equal(false, "testuser@testuser.com" in identities, "Our new email is not added until confirmation.");
+
+ equal(typeof storage.getReturnTo(), "undefined", "initiatingOrigin is not stored");
+
+ start();
+ }, testHelpers.unexpectedXHRFailure);
+ });
+
+ asyncTest("addEmail with XHR failure", function() {
+ failureCheck(lib.addEmail, "testuser@testuser.com", "password");
+ });
+
+
+ asyncTest("waitForEmailValidation with `complete` backend response, user authenticated to assertion level - expect 'mustAuth'", function() {
+ testAddressVerificationPoll("password", "complete", "waitForEmailValidation", "complete");
+ });
+
+ asyncTest("waitForEmailValidation with assertion authentication, complete from backend - return mustAuth status", function() {
+ testAddressVerificationPoll("assertion", "complete", "waitForEmailValidation", "mustAuth");
+ });
+
+ asyncTest("waitForEmailValidation `mustAuth` response", function() {
+ testAddressVerificationPoll("assertion", "mustAuth", "waitForEmailValidation", "mustAuth");
+ });
+
+ asyncTest("waitForEmailValidation with `noRegistration` response", function() {
+ storage.setReturnTo(testOrigin);
+ xhr.useResult("noRegistration");
+
+ lib.waitForEmailValidation(
+ "registered@testuser.com",
+ testHelpers.unexpectedSuccess,
+ function(status) {
+ ok(storage.getReturnTo(), "staged on behalf of is cleared when validation completes");
+ ok(status, "noRegistration", "noRegistration response causes failure");
+ start();
+ });
+ });
+
+
+ asyncTest("waitForEmailValidation XHR failure", function() {
+ storage.setReturnTo(testOrigin);
+ xhr.useResult("ajaxError");
+
+ lib.waitForEmailValidation(
+ "registered@testuser.com",
+ testHelpers.unexpectedSuccess,
+ testHelpers.expectedXHRFailure
+ );
+ });
+
+
+ asyncTest("cancelEmailValidation: ~1 second", function() {
+ xhr.useResult("pending");
+
+ storage.setReturnTo(testOrigin);
+ lib.waitForEmailValidation(
+ "registered@testuser.com",
+ testHelpers.unexpectedSuccess,
+ testHelpers.unexpectedXHRFailure
+ );
+
+ setTimeout(function() {
+ lib.cancelUserValidation();
+ ok(storage.getReturnTo(), "staged on behalf of is not cleared when validation cancelled");
+ start();
+ }, 500);
+ });
+
+ asyncTest("verifyEmail with a good token - callback with email, returnTo, valid", function() {
+ storage.setReturnTo(testOrigin);
+ storage.addEmail(TEST_EMAIL);
+ lib.verifyEmail("token", "password", function onSuccess(info) {
+ testObjectValuesEqual(info, {
+ valid: true,
+ email: TEST_EMAIL,
+ returnTo: testOrigin
+ });
+ equal(storage.getReturnTo(), "", "initiating returnTo was removed");
+
+ start();
+ }, testHelpers.unexpectedXHRFailure);
+ });
+
+ asyncTest("verifyEmail with a bad token - callback with valid: false", function() {
+ xhr.useResult("invalid");
+
+ lib.verifyEmail("token", "password", function onSuccess(info) {
+ equal(info.valid, false, "bad token calls onSuccess with a false validity");
+
+ start();
+ }, testHelpers.unexpectedXHRFailure);
+ });
+
+ asyncTest("verifyEmail with an XHR failure", function() {
+ xhr.useResult("ajaxError");
+
+ lib.verifyEmail(
+ "token",
+ "password",
+ testHelpers.unexpectedSuccess,
+ testHelpers.expectedXHRFailure
+ );
+ });
+
++>>>>>>> b2g
asyncTest("syncEmailKeypair with successful sync", function() {
- lib.syncEmailKeypair("testemail@testemail.com", function(keypair) {
- var identity = lib.getStoredEmailKeypair("testemail@testemail.com");
+ lib.syncEmailKeypair("testuser@testuser.com", function(keypair) {
+ var identity = lib.getStoredEmailKeypair("testuser@testuser.com");
ok(identity, "we have an identity");
ok(identity.priv, "a private key is on the identity");
diff --cc resources/static/test/mocks/xhr.js
index 1a48a07,04c6fbf..0000000
--- a/resources/static/test/mocks/xhr.js
+++ b/resources/static/test/mocks/xhr.js
@@@ -177,32 -156,29 +177,41 @@@ BrowserID.Mocks.xhr = (function()
"post /wsapi/update_password valid": { success: true },
"post /wsapi/update_password incorrectPassword": { success: false },
"post /wsapi/update_password invalid": undefined,
- "get /wsapi/address_info?email=unregistered%40testuser.com invalid": undefined,
- "get /wsapi/address_info?email=unregistered%40testuser.com throttle": { type: "secondary", state: "unknown" },
- "get /wsapi/address_info?email=unregistered%40testuser.com valid": { type: "secondary", state: "unknown" },
- "get /wsapi/address_info?email=unregistered%40testuser.com unknown_secondary": { type: "secondary", state: "unknown" },
- "get /wsapi/address_info?email=unregistered%40testuser.com primary": { type: "primary", state: "unknown", auth: "https://auth_url", prov: "https://prov_url" },
- "get /wsapi/address_info?email=unregistered%40testuser.com primaryUnknown": { type: "primary", state: "unknown", auth: "https://auth_url", prov: "https://prov_url" },
-
- "get /wsapi/address_info?email=registered%40testuser.com valid": { type: "secondary", state: "known" },
- "get /wsapi/address_info?email=registered%40testuser.com known_secondary": { type: "secondary", state: "known" },
- "get /wsapi/address_info?email=registered%40testuser.com throttle": { type: "secondary", state: "known" },
- "get /wsapi/address_info?email=registered%40testuser.com primary": { type: "primary", state: "known", auth: "https://auth_url", prov: "https://prov_url" },
- "get /wsapi/address_info?email=registered%40testuser.com mustAuth": { type: "secondary", state: "known" },
- "get /wsapi/address_info?email=registered%40testuser.com secondaryTransition": { type: "secondary", state: "transition_to_secondary" },
- "get /wsapi/address_info?email=registered%40testuser.com secondaryTransitionPassword": { type: "secondary", state: "transition_no_password" },
- "get /wsapi/address_info?email=registered%40testuser.com primaryTransition": { type: "primary", state: "transition_to_primary", auth: "https://auth_url", prov: "https://prov_url" },
- "get /wsapi/address_info?email=registered%40testuser.com primaryOffline": { type: "primary", state: "offline", auth: "https://auth_url", prov: "https://prov_url" },
-
+ "get /wsapi/address_info?email=unregistered%40testuser.com&issuer=default invalid": undefined,
+ "get /wsapi/address_info?email=unregistered%40testuser.com&issuer=default throttle": { type: "secondary", state: "unknown" },
+ "get /wsapi/address_info?email=unregistered%40testuser.com&issuer=default valid": { type: "secondary", state: "unknown" },
+ "get /wsapi/address_info?email=unregistered%40testuser.com&issuer=default unknown_secondary": { type: "secondary", state: "unknown" },
+ "get /wsapi/address_info?email=unregistered%40testuser.com&issuer=default primary": { type: "primary", state: "unknown", auth: "https://auth_url", prov: "https://prov_url" },
+ "get /wsapi/address_info?email=unregistered%40testuser.com&issuer=default primaryUnknown": { type: "primary", state: "unknown", auth: "https://auth_url", prov: "https://prov_url" },
+
+ "get /wsapi/address_info?email=registered%40testuser.com&issuer=default valid": { type: "secondary", state: "known" },
+ "get /wsapi/address_info?email=registered%40testuser.com&issuer=default known_secondary": { type: "secondary", state: "known" },
+ "get /wsapi/address_info?email=registered%40testuser.com&issuer=default throttle": { type: "secondary", state: "known" },
+ "get /wsapi/address_info?email=registered%40testuser.com&issuer=default primary": { type: "primary", state: "known", auth: "https://auth_url", prov: "https://prov_url" },
+ "get /wsapi/address_info?email=registered%40testuser.com&issuer=default mustAuth": { type: "secondary", state: "known" },
+ "get /wsapi/address_info?email=registered%40testuser.com&issuer=default secondaryTransition": { type: "secondary", state: "transition_to_secondary" },
+ "get /wsapi/address_info?email=registered%40testuser.com&issuer=default secondaryTransitionPassword": { type: "secondary", state: "transition_no_password" },
+ "get /wsapi/address_info?email=registered%40testuser.com&issuer=default primaryTransition": { type: "primary", state: "transition_to_primary", auth: "https://auth_url", prov: "https://prov_url" },
+ "get /wsapi/address_info?email=registered%40testuser.com&issuer=default primaryOffline": { type: "primary", state: "offline", auth: "https://auth_url", prov: "https://prov_url" },
+
++<<<<<<< HEAD
+ "get /wsapi/address_info?email=testuser%40testuser.com valid": { type: "secondary", state: "known" },
+ "get /wsapi/address_info?email=testuser2%40testuser.com valid": { type: "secondary", state: "known" },
+ "get /wsapi/address_info?email=testuser%40testuser.com known_secondary": { type: "secondary", state: "known" },
+ "get /wsapi/address_info?email=testuser%40testuser.com unknown_secondary": { type: "secondary", state: "unknown" },
+ "get /wsapi/address_info?email=testuser%40testuser.com secondaryTransitionPassword": { type: "secondary", state: "transition_no_password" },
+ "get /wsapi/address_info?email=testuser%40testuser.com primary": { type: "primary", state: "known", auth: "https://auth_url", prov: "https://prov_url" },
+ "get /wsapi/address_info?email=testuser%40testuser.com primaryOffline": { type: "primary", state: "offline", auth: "https://auth_url", prov: "https://prov_url" },
+ "get /wsapi/address_info?email=testuser%40testuser.com ajaxError": undefined,
+ "post /wsapi/used_address_as_primary valid": { success: true },
++=======
+ "get /wsapi/address_info?email=testuser%40testuser.com&issuer=default valid": { type: "secondary", state: "known" },
+ "get /wsapi/address_info?email=testuser2%40testuser.com&issuer=default valid": { type: "secondary", state: "known" },
+ "get /wsapi/address_info?email=testuser%40testuser.com&issuer=default known_secondary": { type: "secondary", state: "known" },
+ "get /wsapi/address_info?email=testuser%40testuser.com&issuer=default unknown_secondary": { type: "secondary", state: "unknown" },
+ "get /wsapi/address_info?email=testuser%40testuser.com&issuer=default primary": { type: "primary", state: "known", auth: "https://auth_url", prov: "https://prov_url" },
+ "get /wsapi/address_info?email=testuser%40testuser.com&issuer=default ajaxError": undefined,
++>>>>>>> b2g
"post /wsapi/used_address_as_primary primaryTransition": { success: true },
"post /wsapi/used_address_as_primary primaryUnknown": { success: true },
"post /wsapi/used_address_as_primary primary": { success: false },
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment