diff --git a/resources/static/communication_iframe/start.js b/resources/static/communication_iframe/start.js index 4d9de7afbdf1921cabcc1e5b9dd8519d1f996d1b..506b74c0ea2a7a9561866173f9a746ddcf98e0fa 100644 --- a/resources/static/communication_iframe/start.js +++ b/resources/static/communication_iframe/start.js @@ -28,16 +28,7 @@ var loggedInUser = undefined; - // one of two events will cause us to begin checking to - // see if an event shall be emitted - either an explicit - // loggedInUser event or page load. - chan.bind("loggedInUser", function(trans, email) { - loggedInUser = email; - }); - - chan.bind("loaded", function(trans, params) { - setRemoteOrigin(trans.origin); - + function checkAndEmit() { user.getSilentAssertion(loggedInUser, function(email, assertion) { if (email) { // only send login events when the assertion is defined - when @@ -45,15 +36,34 @@ // when the site already has the user logged in and does not want // the resources or cost required to generate an assertion if (assertion) chan.notify({ method: 'login', params: assertion }); + loggedInUser = email; } else if (loggedInUser !== null) { // only send logout events when loggedInUser is not null, which is an // indicator that the site thinks the user is logged out chan.notify({ method: 'logout' }); + loggedInUser = null; } }, function(err) { chan.notify({ method: 'logout' }); + loggedInUser = null; }); + } + function watchState() { + storage.watchLoggedIn(remoteOrigin, checkAndEmit); + } + + // one of two events will cause us to begin checking to + // see if an event shall be emitted - either an explicit + // loggedInUser event or page load. + chan.bind("loggedInUser", function(trans, email) { + loggedInUser = email; + }); + + chan.bind("loaded", function(trans, params) { + setRemoteOrigin(trans.origin); + checkAndEmit(); + watchState(); trans.complete(); }); diff --git a/resources/static/css/style.css b/resources/static/css/style.css index cab5f6f6f370ed8554dd055e3509186c942069f5..23781ec37d78e6dbb92f6b337e3e8432b4f6fd98 100644 --- a/resources/static/css/style.css +++ b/resources/static/css/style.css @@ -404,6 +404,13 @@ div.steps { margin-right: 0; } +#logout_everywhere .completion_text { + float: right; + display: none; + color: #090; +} + + button.delete { background-color: #EA7676; border: 1px solid #B13D3D; diff --git a/resources/static/pages/manage_account.js b/resources/static/pages/manage_account.js index 9bb92ea310d2570617ea49a45a78dcb5aa8d947d..59bc9ccc3154516c4956f224e02b4e13ecff9938 100644 --- a/resources/static/pages/manage_account.js +++ b/resources/static/pages/manage_account.js @@ -96,6 +96,11 @@ BrowserID.manageAccount = (function() { } } + function logoutEverywhere(oncomplete) { + storage.logoutEverywhere(); + setTimeout(oncomplete, 0); + } + function startEdit(event) { // XXX add some helpers in the dom library to find section. event.preventDefault(); @@ -194,6 +199,13 @@ BrowserID.manageAccount = (function() { dom.bindEvent("button.edit", "click", startEdit); dom.bindEvent("button.done", "click", cancelEdit); + dom.bindEvent("button.logout_everywhere", "click", function() { + logoutEverywhere(function() { + $("button.logout_everywhere").fadeOut(700, function() { + $("#logout_everywhere .completion_text").show(); + }); + }); + }); dom.bindEvent("#edit_password_form", "submit", cancelEvent(changePassword)); user.checkAuthentication(function(auth_level) { diff --git a/resources/static/shared/storage.js b/resources/static/shared/storage.js index 0e7cfa0deb376f79c80130579555d354528f7d75..b21fbbcbe282919ab97595769a8292ce721d7dbd 100644 --- a/resources/static/shared/storage.js +++ b/resources/static/shared/storage.js @@ -187,9 +187,23 @@ BrowserID.Storage = (function() { return allInfo[origin]; } function watchLoggedIn(origin, callback) { - throw "not yet implemented"; - } + var lastState = getLoggedIn(origin); + + function checkState() { + var currentState = getLoggedIn(origin); + if (lastState !== currentState) { + callback(); + lastState = currentState; + }; + } + // does IE8 not have addEventListener, nor does it support storage events. + if (window.addEventListener) window.addEventListener('storage', checkState, false); + else window.setInterval(checkState, 2000); + } + function logoutEverywhere() { + storage.loggedIn = "{}"; + } return { /** @@ -275,6 +289,12 @@ BrowserID.Storage = (function() { */ watchLoggedIn: watchLoggedIn, + /** clear all logged in preferences + * @param {string} origin - the site to watch the status of + * @param {function} callback - a callback to invoke when state changes + */ + logoutEverywhere: logoutEverywhere, + /** * Clear all stored data - email addresses, key pairs, temporary key pairs, * site/email associations. diff --git a/resources/views/index.ejs b/resources/views/index.ejs index 57f1c8d7b96254292d735fb74bf6bab32639dd4a..6b1f49aec9e17322ae8d9f2f5d9c3ce2d079850c 100644 --- a/resources/views/index.ejs +++ b/resources/views/index.ejs @@ -21,6 +21,16 @@ </ul> </section> + <section id="logout_everywhere"> + <header class="cf buttonrow"> + <h2>Logout from all websites</h2> + <div class="completion_text"> Logged Out! </div> + <button class="logout_everywhere">logout</button> + </header> + + <div class="email">You can sign in again by entering your password. None of your website accounts will be lost.</div></li> + </section> + <section id="edit_password"> <header class="buttonrow cf"> <h2>Password</h2>