diff --git a/authority/server/run.js b/authority/server/run.js index 9b214a9737144603e812cfe75cad1b7085f0684a..cbcf9da3e553eaadb8f17a6d7a84233b12f2c2a1 100644 --- a/authority/server/run.js +++ b/authority/server/run.js @@ -17,8 +17,8 @@ exports.handler = function(request, response, serveFile) { wsapi[method](request, response); } catch(e) { var errMsg = "oops, error executing wsapi method: " + method + " (" + e.toString() +")"; - httputils.fourOhFour(response, errMsg); console.log(errMsg); + httputils.fourOhFour(response, errMsg); } } else { // node.js takes care of sanitizing the request path diff --git a/authority/static/dialog/crypto-stubs.js b/authority/static/dialog/crypto-stubs.js index be803e98373d4b1d5049fcd1aff7f50545a7dc32..99b5c349a06c605026487c24c5aa9a1eb84fb360 100644 --- a/authority/static/dialog/crypto-stubs.js +++ b/authority/static/dialog/crypto-stubs.js @@ -22,7 +22,17 @@ CryptoStubs = (function() { }; } + function createAssertion(audience, email, privkey) { + // XXX: in the future, we need to sign via JWT spec, now let's just glom together and stringify + return JSON.stringify({ + audience: audience, + email: email, + "valid-until": (new Date()).getTime() + (1000 * 120) // 2 mins from now. + }); + } + return { - genKeyPair: genKeyPair + genKeyPair: genKeyPair, + createAssertion: createAssertion }; })(); diff --git a/authority/static/dialog/index.html b/authority/static/dialog/index.html index 0cd21b90637c6bdd2edeacdc50e6ecdb7c96a81c..018d83679de6ab07180610be91f7b5a46eae86d9 100644 --- a/authority/static/dialog/index.html +++ b/authority/static/dialog/index.html @@ -70,12 +70,20 @@ <form id="identities" name="identities"> </form> </div> + <div class="actions"> + <div class="action"><a href="#">Add a new email address</a></div> + </div> </div> <div id="error_dialog" class="dialog"> <div class="title"> Sign in with Firefox ID </div> <div class="content"> </div> </div> +<div id="waiting_dialog" class="dialog"> + <div class="title"> Sign in with Firefox ID </div> + <div class="content"> + </div> +</div> <div id="bottom-bar"> <button id="back">Go Back</button> <button id="submit" class="righty action">Sign In</button> diff --git a/authority/static/dialog/main.js b/authority/static/dialog/main.js index 7f27a9719d106d651c7d13462c33a799d8e4c09a..1561829cdecb5212f3bedfeee98abbcf7111e5ad 100644 --- a/authority/static/dialog/main.js +++ b/authority/static/dialog/main.js @@ -8,6 +8,8 @@ scope: "mozid" }); + var remoteOrigin = undefined; + function runSignInDialog(onsuccess, onerror) { $(".dialog").hide(); @@ -16,12 +18,29 @@ onerror("canceled"); }); $("#submit").show().unbind('click').click(function() { - onerror("notImplemented"); + var email = $("#identities input:checked").parent().find("div").text(); + // yay! now we need to produce an assertion. + var privkey = JSON.parse(window.localStorage.emails)[email].priv; + var assertion = CryptoStubs.createAssertion(remoteOrigin, email, privkey); + onsuccess(assertion); }).text("Sign In"); $("#default_dialog div.actions div.action a").unbind('click').click(function() { onerror("notImplemented"); }); + + // now populate the selection list with all available emails + // we assume there are identities available, because without them + var emails = JSON.parse(window.localStorage.emails); + var first = true; + for (var k in emails) { + var id = $("<div />") + .append($("<input />").attr('type', 'radio').attr('name', 'identity').attr('checked', first)) + .append($("<div />").text(k)); + first = false; + id.appendTo($("form#identities")); + } + $("#sign_in_dialog").fadeIn(500); } @@ -53,10 +72,9 @@ var nextEmailToCheck = undefined; // a set of emails that we've checked for this session var checkedEmails = { - }; - function runConfirmEmailDialog(email, onsuccess, onerror) { + function runConfirmEmailDialog(email, keypair, onsuccess, onerror) { $(".dialog").hide(); $("span.email").text(email); @@ -73,7 +91,11 @@ // 'pending' - a registration is in progress // 'noRegistration' - no registration is in progress if (status === 'complete') { - // XXX: now we need to add all of the pertinent data to local storage + // now we need to add all of the pertinent data to local storage + var emails = {}; + if (window.localStorage.emails) emails = JSON.parse(window.localStorage.emails); + emails[email] = keypair; + window.localStorage.emails = JSON.stringify(emails); // and tell the user that everything is really quite awesome. runConfirmedEmailDialog(email, onsuccess, onerror); @@ -88,8 +110,6 @@ onsuccess, onerror); } - console.log("success"); - console.log(data); }, error: function(jqXHR, textStatus, errorThrown) { runErrorDialog("serverError", "Registration Failed", jqXHR.responseText, onsuccess, onerror); @@ -151,6 +171,21 @@ $("#error_dialog").fadeIn(500); } + function runWaitingDialog(title, message, onsuccess, onerror) { + $(".dialog").hide(); + + $("#waiting_dialog div.title").text(title); + $("#waiting_dialog div.content").text(message); + + $("#back").hide(); + $("#submit").hide(); + $("#cancel").show().unbind('click').click(function() { + onerror("canceled"); + }); + + $("#waiting_dialog").fadeIn(500); + } + function runCreateDialog(onsuccess, onerror) { $(".dialog").hide(); @@ -169,14 +204,19 @@ var pass = $("#create_dialog input:eq(1)").val(); var keypair = CryptoStubs.genKeyPair(); - // XXX: we should be showing the user a waiting/status page here + // kick the user to waiting/status page while we talk to the server. + runWaitingDialog( + "One Moment Please...", + "We're creating your account, this should only take a couple seconds", + onsuccess, + onerror + ); $.ajax({ url: '/wsapi/stage_user?email=' + encodeURIComponent(email) + '&pass=' + encodeURIComponent(pass) + '&pubkey=' + encodeURIComponent(keypair.pub), success: function() { - // account successfully staged, now wait for email confirmation - runConfirmEmailDialog(email, onsuccess, onerror); + runConfirmEmailDialog(email, keypair, onsuccess, onerror); }, error: function() { runErrorDialog( @@ -186,8 +226,6 @@ onsuccess, onerror); } }); - - }).text("Continue").addClass("disabled"); @@ -297,11 +335,24 @@ chan.bind("getVerifiedEmail", function(trans, s) { trans.delayReturn(true); + remoteOrigin = trans.origin; + // set the requesting site $(".sitename").text(trans.origin.replace(/^.*:\/\//, "")); - // XXX: check to see if there's any pubkeys stored in the browser + // check to see if there's any pubkeys stored in the browser var haveIDs = false; + try { + var emails = JSON.parse(window.localStorage.emails); + if (typeof emails !== 'object') throw "emails blob bogus!"; + for (var k in emails) { + if (!emails.hasOwnProperty(k)) continue; + haveIDs = true; + break; + } + } catch(e) { + window.localStorage.emails = JSON.stringify({}); + } if (haveIDs) { runSignInDialog(function(rv) { diff --git a/authority/static/dialog/style.css b/authority/static/dialog/style.css index 5de639d084b8f0d11e533819c3a8b4a03a887a13..f1cd65060c09caf03db8dd2cb1bae559ab25fa80 100644 --- a/authority/static/dialog/style.css +++ b/authority/static/dialog/style.css @@ -93,10 +93,15 @@ div.actions { margin-left: 79px; } +#identities { + width: 450px; + margin: auto; +} + #identities > div { - margin-left: .8em; margin-bottom: .5em; height: 1.4em; + font-size: .9em; } #identities > div > * { @@ -131,21 +136,22 @@ div.input > div.note { margin-top: .7em; } -div.content > div.input { +div.content { width: 450px; - height: 3em; margin: auto; + text-align: left; +} + +div.content > div.input { + height: 3em; font-size: .8em; } div.content > div.summary { text-align: left; - width: 450px; - margin: auto; margin-bottom: 2em; } - div.content > div.input > div.label { width: 80px; text-align: left;