Skip to content
Snippets Groups Projects
Commit ca4e6f07 authored by mhanson@gmail.com's avatar mhanson@gmail.com
Browse files

Merge branch 'master' of github.com:mozilla/mozidhacks

parents 80fe2fa1 fb5e1752
No related branches found
No related tags found
No related merge requests found
......@@ -54,3 +54,10 @@ exports.gotVerificationSecret = function(secret) {
};
return true;
};
/* takes an argument object including email, pass, and pubkey. */
exports.checkAuth = function(email, pass) {
console.log("e: " + email + " p: " + pass);
console.log(g_emails);
return (g_emails.hasOwnProperty(email) && g_emails[email].pass === pass);
};
......@@ -31,7 +31,7 @@ exports.badRequest = function(resp, reason)
exports.jsonResponse = function(resp, obj)
{
resp.writeHead(200, {"Content-Type": "application/json"});
if (obj) resp.write(JSON.stringify(obj));
if (obj !== undefined) resp.write(JSON.stringify(obj));
resp.end();
};
......
......@@ -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
......
......@@ -10,6 +10,20 @@ function logRequest(method, args) {
console.log("WSAPI ("+method+") " + (args ? JSON.stringify(args) : ""));
}
function checkParams(getArgs, resp, params) {
try {
params.forEach(function(k) {
if (!getArgs.hasOwnProperty(k) || typeof getArgs[k] !== 'string') {
throw k;
}
});
} catch(e) {
httputils.badRequest(resp, "missing '" + e + "' argument");
return false;
}
return true;
}
/* checks to see if an email address is known to the server
* takes 'email' as a GET argument */
exports.have_email = function(req, resp) {
......@@ -69,3 +83,16 @@ exports.registration_status = function(req, resp) {
httputils.jsonResponse(resp, "noRegistration");
}
};
exports.authenticate_user = function(req, resp) {
var urlobj = url.parse(req.url, true);
var getArgs = urlobj.query;
if (!checkParams(getArgs, resp, [ "email", "pass" ])) return;
if (db.checkAuth(getArgs.email, getArgs.pass)) {
httputils.jsonResponse(resp, true);
} else {
httputils.jsonResponse(resp, false);
}
};
......@@ -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
};
})();
......@@ -4,7 +4,7 @@
<link href="../dialog/style.css" type="text/css" media="screen" rel="stylesheet"></link>
</head>
<body id="body">
<div id="default_dialog" class="dialog">
<div id="authenticate_dialog" class="dialog">
<div class="title"> Sign in with Firefox ID </div>
<div class="content">
<div class="summary">Enter your email and Firefox ID password to log into <span class="sitename bad"></span>:</div>
......@@ -17,6 +17,9 @@
<div class="input"> <input type="password"></input></div>
<div class="note"> <a href="#">I forgot my password</a> </div>
</div>
<div class="attention_lame">
No such account exists with that email and/or password
</div>
<div class="actions">
<div class="action"><a href="#">Don't have a Firefox ID yet?</a></div>
</div>
......@@ -40,6 +43,9 @@
<div class="input"> <input type="password"></input></div>
<div class="note"><span class="bad">Enter a password</span></div>
</div>
<div class="attention_lame">
<span id="in_use_email">Email</span> in use, If this email is yours you can <a href="#">log in</a> with it?
</div>
</div>
</div>
<div id="confirm_email_dialog" class="dialog">
......@@ -70,12 +76,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>
......
......@@ -8,6 +8,8 @@
scope: "mozid"
});
var remoteOrigin = undefined;
function runSignInDialog(onsuccess, onerror) {
$(".dialog").hide();
......@@ -16,35 +18,94 @@
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"));
}
$("form#identities > div").unbind('click').click(function() {
$(this).find(':first').attr('checked', true);
});
$("#sign_in_dialog").fadeIn(500);
}
function runDefaultDialog(onsuccess, onerror) {
function runAuthenticateDialog(email, onsuccess, onerror) {
$(".dialog").hide();
$("#back").hide();
$("#cancel").show().unbind('click').click(function() {
onerror("canceled");
});
$("#submit").show().unbind('click').click(function() {
onerror("notImplemented");
var email = $("#authenticate_dialog input:eq(0)").val();
var pass = $("#authenticate_dialog input:eq(1)").val();
$.ajax({
url: '/wsapi/authenticate_user?email=' + encodeURIComponent(email) + '&pass=' + encodeURIComponent(pass),
success: function(status, textStatus, jqXHR) {
var authenticated = JSON.parse(status);
if (!authenticated) {
$("#authenticate_dialog div.attention_lame").hide().fadeIn(400);
} else {
runWaitingDialog(
"Finishing Log In...",
"In just a moment you'll be logged into BrowserID (XXX: this will never go away! write me!",
onsuccess, onerror);
// XXX: now it's time for the id synchronization process...
}
},
error: function() {
runErrorDialog(
"serverError",
"Error Authenticating!",
"There was a technical problem while trying to log you in. Yucky!",
onsuccess, onerror);
}
});
}).text("Sign In");
$("#default_dialog div.note > a").unbind('click').click(function() {
onerror("notImplemented");
});
$("#default_dialog div.note > a").unbind('click').click(function() {
// preseed the email input if whoever triggered us told us to
if (email) {
$("#authenticate_dialog input:eq(0)").val(email);
}
$("#authenticate_dialog div.note > a").unbind('click').click(function() {
onerror("notImplemented");
});
$("#default_dialog div.actions div.action").unbind('click').click(function() {
$("#authenticate_dialog div.actions div.action").unbind('click').click(function() {
runCreateDialog(onsuccess, onerror);
});
$("#default_dialog").fadeIn(500);
$("#authenticate_dialog div.attention_lame").hide();
$("#authenticate_dialog").fadeIn(
500,
function() {
// where should we put the focus? On login if empty, else password
var email = $("#authenticate_dialog input:eq(0)").val();
if (typeof email === 'string' && email.length) {
$("#authenticate_dialog input:eq(1)").focus();
} else {
$("#authenticate_dialog input:eq(0)").focus();
}
});
}
// a handle to a timeout of a running email check
......@@ -53,10 +114,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 +133,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 +152,6 @@
onsuccess,
onerror);
}
console.log("success");
console.log(data);
},
error: function(jqXHR, textStatus, errorThrown) {
runErrorDialog("serverError", "Registration Failed", jqXHR.responseText, onsuccess, onerror);
......@@ -151,11 +213,26 @@
$("#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();
$("#back").show().unbind('click').click(function() {
runDefaultDialog(onsuccess, onerror);
runAuthenticateDialog(undefined, onsuccess, onerror);
});
$("#cancel").show().unbind('click').click(function() {
onerror("canceled");
......@@ -169,14 +246,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,10 +268,13 @@
onsuccess, onerror);
}
});
}).text("Continue").addClass("disabled");
$("#create_dialog div.attention_lame").hide();
$("#create_dialog div.attention_lame a").unbind('click').click(function() {
var email = $("#create_dialog input:eq(0)").val();
runAuthenticateDialog(email, onsuccess, onerror);
});
function checkInput() {
$("#submit").removeClass("disabled");
......@@ -206,8 +291,10 @@
} else if (typeof valid === 'boolean') {
if (valid) {
$("#create_dialog div.note:eq(0)").html($('<span class="good"/>').text("Not registered"));
$("#create_dialog div.attention_lame").hide();
} else {
$("#create_dialog div.note:eq(0)").html($('<span class="bad"/>').text("Email in use"));
$("#create_dialog div.attention_lame").fadeIn(300);
$("#create_dialog div.attention_lame span.email").text(email);
$("#submit").addClass("disabled");
}
} else {
......@@ -263,11 +350,7 @@
}
// watch input dialogs
$("#create_dialog input:first").unbind('keyup').bind('keyup', function() {
checkInput();
});
$("#create_dialog input:gt(0)").unbind('keyup').bind('keyup', checkInput);
$("#create_dialog input").unbind('keyup').bind('keyup', checkInput);
// do a check at load time, in case the user is using the back button (enables the continue button!)
checkInput();
......@@ -275,6 +358,8 @@
$("#create_dialog").fadeIn(500);
}
runCreateDialog();
function errorOut(trans, code) {
function getVerboseMessage(code) {
......@@ -297,11 +382,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) {
......@@ -310,11 +408,19 @@
errorOut(trans, error);
});
} else {
runDefaultDialog(function(rv) {
runAuthenticateDialog(undefined, function(rv) {
trans.complete(rv);
}, function(error) {
errorOut(trans, error);
});
}
});
// 'Enter' in any input field triggers a click on the submit button
$('input').keypress(function(e){
if(e.which == 13) {
$('#submit').click();
e.preventDefault();
}
});
})();
......@@ -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;
......@@ -181,7 +187,7 @@ div.subtle {
opacity: .7;
}
div.dialog div.attention, div.dialog div.attention_awesome {
div.dialog div.attention, div.dialog div.attention_awesome, div.dialog div.attention_lame {
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
......@@ -189,6 +195,7 @@ div.dialog div.attention, div.dialog div.attention_awesome {
padding:13px;
margin: auto;
text-align: left;
margin-top: 1em;
}
div.dialog div.attention {
......@@ -201,4 +208,12 @@ div.dialog div.attention_awesome {
background-color: rgb(0,161,51);
color: white;
font-weight: bold;
}
\ No newline at end of file
}
div.dialog div.attention_lame {
border: 1px solid rgb(224,178,139);
background-color: rgb(253,239,208);
color: rgb(120,43,9);
font-size: .8em;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment