diff --git a/browserid/static/dialog/resources/browserid-identities.js b/browserid/static/dialog/resources/browserid-identities.js index f902a72dd2939b33c5680d8b4f4a01566b3da72c..2430e84b241d0b96d167e8c167e86b76bfff0c8e 100644 --- a/browserid/static/dialog/resources/browserid-identities.js +++ b/browserid/static/dialog/resources/browserid-identities.js @@ -93,7 +93,7 @@ BrowserID.Identities = (function() { $('body')[func]('authenticated'); if (!authenticated) { - storage.clearEmails(); + storage.clear(); } } @@ -591,7 +591,7 @@ BrowserID.Identities = (function() { * @method clearStoredEmailKeypairs */ clearStoredEmailKeypairs: function() { - storage.clearEmails(); + storage.clear(); }, diff --git a/browserid/static/dialog/resources/storage.js b/browserid/static/dialog/resources/storage.js index 1a42ffa1749bbce52e72bc4ad43ffa90a0f74702..809f912a404b44e6590fd4c0d8f73552cae6247f 100644 --- a/browserid/static/dialog/resources/storage.js +++ b/browserid/static/dialog/resources/storage.js @@ -47,8 +47,12 @@ BrowserID.Storage = (function() { window.localStorage.emails = JSON.stringify(emails); } - function clearEmails() { + function clear() { storeEmails({}); + var localStorage = window.localStorage; + localStorage.removeItem("tempKeypair"); + localStorage.removeItem("stagedOnBehalfOf"); + localStorage.removeItem("sitesToEmail"); } function getEmails() { @@ -60,10 +64,16 @@ BrowserID.Storage = (function() { } // if we had a problem parsing or the emails are null - clearEmails(); + clear(); return {}; } + function getEmail(email) { + var ids = getEmails(); + + return ids && ids[email]; + } + function addEmail(email, obj) { var emails = getEmails(); emails[email] = obj; @@ -72,18 +82,35 @@ BrowserID.Storage = (function() { function removeEmail(email) { var emails = getEmails(); - delete emails[email]; - storeEmails(emails); + if(emails[email]) { + delete emails[email]; + storeEmails(emails); + + // remove any sites associated with this email address. + var sitesToEmail = JSON.parse(localStorage.sitesToEmail || "{}"); + for(var site in sitesToEmail) { + if(sitesToEmail[site] === email) { + delete sitesToEmail[site]; + } + } + localStorage.sitesToEmail = JSON.stringify(sitesToEmail); + } + else { + throw "unknown email address"; + } } function invalidateEmail(email) { - var id = getEmails()[email]; + var id = getEmail(email); if (id) { delete id.priv; delete id.pub; delete id.cert; addEmail(email, id); } + else { + throw "unknown email address"; + } } function storeTemporaryKeypair(keypair) { @@ -133,12 +160,73 @@ BrowserID.Storage = (function() { return origin; } + function setSiteEmail(site, email) { + if(getEmail(email)) { + var localStorage = window.localStorage; + + var sitesToEmail = JSON.parse(localStorage.sitesToEmail || "{}"); + sitesToEmail[site] = email; + + localStorage.sitesToEmail = JSON.stringify(sitesToEmail); + } + else { + throw "unknown email address"; + } + } + + function getSiteEmail(site) { + var sitesToEmail = JSON.parse(localStorage.sitesToEmail || "{}"); + return sitesToEmail[site]; + } + return { - getEmails: getEmails, + /** + * Add an email address and optional key pair. + * @method addEmail + */ addEmail: addEmail, + /** + * Get all email addresses and their associated key pairs + * @method getEmails + */ + getEmails: getEmails, + /** + * Get one email address and its key pair, if found. Returns undefined if + * not found. + * @method getEmail + */ + getEmail: getEmail, + /** + * Remove an email address, its key pairs, and any sites associated with + * email address. + * @throws "unknown email address" if email address is not known. + * @method removeEmail + */ removeEmail: removeEmail, + /** + * Remove the key information for an email address. + * @throws "unknown email address" if email address is not known. + * @method invalidateEmail + */ invalidateEmail: invalidateEmail, - clearEmails: clearEmails, + /** + * Set the associated email address for a site + * @throws "uknown email address" if the email address is not known. + * @method setSiteEmail + */ + setSiteEmail: setSiteEmail, + /** + * Get the associated email address for a site, if known. If not known, + * return undefined. + * @method getSiteEmail + */ + getSiteEmail: getSiteEmail, + /** + * Clear all stored data - email addresses, key pairs, temporary key pairs, + * site/email associations. + * @method clear + */ + clear: clear, storeTemporaryKeypair: storeTemporaryKeypair, retrieveTemporaryKeypair: retrieveTemporaryKeypair, setStagedOnBehalfOf: setStagedOnBehalfOf, diff --git a/browserid/static/dialog/test/qunit/browserid-identities_unit_test.js b/browserid/static/dialog/test/qunit/browserid-identities_unit_test.js index 50be6a8b48e2a723b129a131920e1e6a32be8079..2487d06272719e391a93f09fbe6541dfe3904b8c 100644 --- a/browserid/static/dialog/test/qunit/browserid-identities_unit_test.js +++ b/browserid/static/dialog/test/qunit/browserid-identities_unit_test.js @@ -375,7 +375,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/browserid-iden test("authenticateAndSync with valid authentication", function() { credentialsValid = true; keyRefresh = ["testuser@testuser.com"]; - storage.clearEmails(); + lib.clearStoredEmailKeypairs(); lib.authenticateAndSync("testuser@testuser.com", "testuser", function() { }, function(authenticated) { @@ -393,7 +393,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/browserid-iden test("authenticateAndSync with invalid authentication", function() { credentialsValid = false; keyRefresh = ["testuser@testuser.com"]; - storage.clearEmails(); + lib.clearStoredEmailKeypairs(); lib.authenticateAndSync("testuser@testuser.com", "testuser", function() { }, function(authenticated) { @@ -444,7 +444,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/browserid-iden test("syncEmailKeypair with successful sync", function() { - storage.clearEmails(); + lib.clearStoredEmailKeypairs(); syncValid = true; lib.syncEmailKeypair("testemail@testemail.com", function(keypair) { @@ -459,7 +459,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/browserid-iden test("syncEmailKeypair with invalid sync", function() { - storage.clearEmails(); + lib.clearStoredEmailKeypairs(); syncValid = false; lib.syncEmailKeypair("testemail@testemail.com", function(keypair) { @@ -556,7 +556,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/browserid-iden test("removeEmail that is not added", function() { - storage.clearEmails(); + lib.clearStoredEmailKeypairs(); lib.removeEmail("testemail@testemail.com", function() { var identities = lib.getStoredEmailKeypairs(); @@ -570,7 +570,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/browserid-iden test("syncEmails with no pre-loaded identities and no identities to add", function() { - storage.clearEmails(); + lib.clearStoredEmailKeypairs(); userEmails = {}; lib.syncEmails(function onSuccess() { @@ -584,7 +584,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/browserid-iden }); test("syncEmails with no pre-loaded identities and identities to add", function() { - storage.clearEmails(); + lib.clearStoredEmailKeypairs(); userEmails = {"testuser@testuser.com": {}}; lib.syncEmails(function onSuccess() { @@ -598,7 +598,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/browserid-iden }); test("syncEmails with identities preloaded and none to add", function() { - storage.clearEmails(); + lib.clearStoredEmailKeypairs(); userEmails = {"testuser@testuser.com": {}}; storage.addEmail("testuser@testuser.com", {}); lib.syncEmails(function onSuccess() { @@ -613,7 +613,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/browserid-iden test("syncEmails with identities preloaded and one to add", function() { - storage.clearEmails(); + lib.clearStoredEmailKeypairs(); storage.addEmail("testuser@testuser.com", {pubkey: pubkey, cert: random_cert}); userEmails = {"testuser@testuser.com": {pubkey: pubkey, cert: random_cert}, "testuser2@testuser.com": {pubkey: pubkey, cert: random_cert}}; @@ -631,7 +631,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/browserid-iden test("syncEmails with identities preloaded and one to remove", function() { - storage.clearEmails(); + lib.clearStoredEmailKeypairs(); storage.addEmail("testuser@testuser.com", {pub: pubkey, cert: random_cert}); storage.addEmail("testuser2@testuser.com", {pub: pubkey, cert: random_cert}); userEmails = {"testuser@testuser.com": { pub: pubkey, cert: random_cert}}; @@ -649,7 +649,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/browserid-iden test("getAssertion with known email that has key", function() { - storage.clearEmails(); + lib.clearStoredEmailKeypairs(); var keypair = jwk.KeyPair.generate("RS",64); lib.certifyEmailKeypair("testuser@testuser.com", keypair, function() { lib.getAssertion("testuser@testuser.com", function onSuccess(assertion) { @@ -663,7 +663,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/browserid-iden test("getAssertion with known email that does not have a key", function() { - storage.clearEmails(); + lib.clearStoredEmailKeypairs(); lib.persistEmail("testuser@testuser.com", function() { lib.getAssertion("testuser@testuser.com", function onSuccess(assertion) { equal("string", typeof assertion, "we have an assertion!"); @@ -676,7 +676,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/browserid-iden test("getAssertion with unknown email", function() { - storage.clearEmails(); + lib.clearStoredEmailKeypairs(); var keypair = jwk.KeyPair.generate("RS",64); lib.certifyEmailKeypair("testuser@testuser.com", keypair, function() { lib.getAssertion("testuser2@testuser.com", function onSuccess(assertion) { @@ -691,7 +691,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/browserid-iden test("logoutUser", function(onSuccess) { credentialsValid = true; keyRefresh = ["testuser@testuser.com"]; - storage.clearEmails(); + lib.clearStoredEmailKeypairs(); lib.authenticateAndSync("testuser@testuser.com", "testuser", function() { }, function(authenticated) { diff --git a/browserid/static/dialog/test/qunit/storage_unit_test.js b/browserid/static/dialog/test/qunit/storage_unit_test.js index 2c2f3c2d63564ec0bc83c5a10a122b4fc73d3aa2..305239e3422861f6ac9cfcb2998d2a3189b562f2 100644 --- a/browserid/static/dialog/test/qunit/storage_unit_test.js +++ b/browserid/static/dialog/test/qunit/storage_unit_test.js @@ -39,11 +39,11 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/storage", func module("BrowserID.Storage", { setup: function() { - storage.clearEmails(); + storage.clear(); }, teardown: function() { - storage.clearEmails(); + storage.clear(); } }); @@ -54,14 +54,16 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/storage", func equal(_.size(emails), 0, "object should be empty"); }); - test("addEmail, getEmails", function() { + test("addEmail, getEmails, getEmail", function() { storage.addEmail("testuser@testuser.com", {priv: "key"}); var emails = storage.getEmails(); equal(_.size(emails), 1, "object should have one item"); ok("testuser@testuser.com" in emails, "added email address is there"); - }); + var id = storage.getEmail("testuser@testuser.com"); + equal("key", id.priv, "email that was added is retrieved"); + }); test("removeEmail, getEmails", function() { storage.addEmail("testuser@testuser.com", {priv: "key"}); @@ -71,25 +73,90 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/storage", func equal(_.size(emails), 0, "object should have no items"); }); + test("removeEmail with invalid address", function() { + var error; + try { + storage.removeEmail("testuser@testuser.com"); + } + catch(e) { + error = e; + } + equal(error.toString(), "unknown email address", "removing an unknown email address"); + }); + - test("clearEmails", function() { + test("clear", function() { storage.addEmail("testuser@testuser.com", {priv: "key"}); - storage.clearEmails(); + storage.clear(); var emails = storage.getEmails(); equal(_.size(emails), 0, "object should have no items"); }); - test("invalidateEmail", function() { + test("invalidateEmail with valid email address", function() { storage.addEmail("testuser@testuser.com", {priv: "key", pub: "pub", cert: "cert"}); storage.invalidateEmail("testuser@testuser.com"); - var id = storage.getEmails()["testuser@testuser.com"]; + var id = storage.getEmail("testuser@testuser.com"); ok(id && !("priv" in id), "private key was removed"); ok(id && !("pub" in id), "public key was removed"); ok(id && !("cert" in id), "cert was removed"); }); + test("invalidateEmail with invalid email address", function() { + var error; + try { + storage.invalidateEmail("testuser@testuser.com"); + } + catch(e) { + error = e; + } + equal(error.toString(), "unknown email address", "Invalidating an unknown email address"); + }); + + test("getSiteEmail with site not found", function() { + var email = storage.getSiteEmail("www.testsite.com"); + + equal(typeof email, "undefined", "if site not found, returned undefined"); + }); + + test("setSiteEmail with email that is not known about", function() { + var error; + try { + storage.setSiteEmail("www.testsite.com", "testuser@testuser.com"); + } catch(e) { + error = e; + } + + equal(error.toString(), "unknown email address", "An unknown email address was added"); + }); + + test("setSiteEmail with valid email", function() { + storage.addEmail("testuser@testuser.com", {}); + storage.setSiteEmail("www.testsite.com", "testuser@testuser.com"); + var email = storage.getSiteEmail("www.testsite.com"); + + equal(email, "testuser@testuser.com", "set/get have the same email for the site"); + }); + + test("removeEmail after setSiteEmail removes site", function() { + storage.addEmail("testuser@testuser.com", {}); + storage.setSiteEmail("www.testsite.com", "testuser@testuser.com"); + storage.removeEmail("testuser@testuser.com"); + var email = storage.getSiteEmail("www.testsite.com"); + + equal(typeof email, "undefined", "after removing an email address, email for site is no longer available"); + }); + + test("clear clears site email info", function() { + storage.addEmail("testuser@testuser.com", {}); + storage.setSiteEmail("www.testsite.com", "testuser@testuser.com"); + storage.clear(); + var email = storage.getSiteEmail("www.testsite.com"); + + equal(typeof email, "undefined", "after clearing, site email is not found"); + }); + test("storeTemporaryKeypair", function() { // XXX needs a test });