From c3d37c1ff9f3cb30834bb6e97c49845be9363b2f Mon Sep 17 00:00:00 2001
From: Richard van der Hoff <richard@matrix.org>
Date: Wed, 31 May 2017 17:28:46 +0100
Subject: [PATCH 1/2] Call MatrixClient.clearStores on logout

... to make sure that we don't have any sensitive data sitting around in the
stores.
---
 src/Lifecycle.js                        | 38 +++++++++++++++++++------
 src/components/structures/MatrixChat.js |  4 +--
 2 files changed, 31 insertions(+), 11 deletions(-)

diff --git a/src/Lifecycle.js b/src/Lifecycle.js
index bf7b25fd2b..a3bec14492 100644
--- a/src/Lifecycle.js
+++ b/src/Lifecycle.js
@@ -237,7 +237,7 @@ function _handleRestoreFailure(e) {
             + ' This is a once off; sorry for the inconvenience.',
         );
 
-        _clearLocalStorage();
+        _clearStorage();
 
         return q.reject(new Error(
             _t('Unable to restore previous session') + ': ' + msg,
@@ -258,7 +258,7 @@ function _handleRestoreFailure(e) {
     return def.promise.then((success) => {
         if (success) {
             // user clicked continue.
-            _clearLocalStorage();
+            _clearStorage();
             return false;
         }
 
@@ -332,6 +332,10 @@ export function setLoggedIn(credentials) {
     }
 
     // stop any running clients before we create a new one with these new credentials
+    //
+    // XXX: why do we have any running clients here? Maybe on sign-in after
+    // initial use as a guest? but what about our persistent storage? we need to
+    // be careful not to leak e2e data created as one user into another session.
     stopMatrixClient();
 
     MatrixClientPeg.replaceUsingCreds(credentials);
@@ -402,13 +406,19 @@ export function startMatrixClient() {
  * a session has been logged out / ended.
  */
 export function onLoggedOut() {
-    _clearLocalStorage();
-    stopMatrixClient();
+    stopMatrixClient(true);
     dis.dispatch({action: 'on_logged_out'});
 }
 
-function _clearLocalStorage() {
+function _clearStorage() {
     Analytics.logout();
+
+    const cli = MatrixClientPeg.get();
+    if (cli) {
+        // TODO: *really* ought to wait for the promise to complete
+        cli.clearStores().done();
+    }
+
     if (!window.localStorage) {
         return;
     }
@@ -425,9 +435,13 @@ function _clearLocalStorage() {
 }
 
 /**
- * Stop all the background processes related to the current client
+ * Stop all the background processes related to the current client.
+ *
+ * Optionally clears persistent stores.
+ *
+ * @param {boolean} clearStores true to clear the persistent stores.
  */
-export function stopMatrixClient() {
+export function stopMatrixClient(clearStores) {
     Notifier.stop();
     UserActivity.stop();
     Presence.stop();
@@ -436,7 +450,13 @@ export function stopMatrixClient() {
     if (cli) {
         cli.stopClient();
         cli.removeAllListeners();
-        cli.store.deleteAllData();
-        MatrixClientPeg.unset();
     }
+
+    if (clearStores) {
+        // note that we have to do this *after* stopping the client, but
+        // *before* clearing the MatrixClientPeg.
+        _clearStorage();
+    }
+
+    MatrixClientPeg.unset();
 }
diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js
index 64b5354eda..f53128fba9 100644
--- a/src/components/structures/MatrixChat.js
+++ b/src/components/structures/MatrixChat.js
@@ -292,7 +292,7 @@ module.exports = React.createClass({
     },
 
     componentWillUnmount: function() {
-        Lifecycle.stopMatrixClient();
+        Lifecycle.stopMatrixClient(false);
         dis.unregister(this.dispatcherRef);
         UDEHandler.stopListening();
         window.removeEventListener("focus", this.onFocus);
@@ -364,7 +364,7 @@ module.exports = React.createClass({
                 // is completed in another browser, we'll be 401ed for using
                 // a guest access token for a non-guest account.
                 // It will be restarted in onReturnToGuestClick
-                Lifecycle.stopMatrixClient();
+                Lifecycle.stopMatrixClient(false);
 
                 this.notifyNewScreen('register');
                 break;

From b3e97161268c3e5a2bf6a41748e289564fb29db7 Mon Sep 17 00:00:00 2001
From: Richard van der Hoff <github@rvanderhoff.org.uk>
Date: Thu, 1 Jun 2017 17:52:25 +0100
Subject: [PATCH 2/2] Revert "add labels to language picker"

---
 .../views/elements/LanguageDropdown.js        |  9 ++++++++-
 src/languageHandler.js                        | 19 +++++--------------
 2 files changed, 13 insertions(+), 15 deletions(-)

diff --git a/src/components/views/elements/LanguageDropdown.js b/src/components/views/elements/LanguageDropdown.js
index 49f89aa469..25a920d2e0 100644
--- a/src/components/views/elements/LanguageDropdown.js
+++ b/src/components/views/elements/LanguageDropdown.js
@@ -40,7 +40,14 @@ export default class LanguageDropdown extends React.Component {
     }
 
     componentWillMount() {
-        languageHandler.getAllLanguagesFromJson().then((langs) => {
+        languageHandler.getAllLanguageKeysFromJson().then((langKeys) => {
+            const langs = [];
+            langKeys.forEach((languageKey) => {
+                langs.push({
+                    value: languageKey,
+                    label: _t(languageKey)
+                });
+            });
             langs.sort(function(a, b){
                 if(a.label < b.label) return -1;
                 if(a.label > b.label) return 1;
diff --git a/src/languageHandler.js b/src/languageHandler.js
index ab29dd926e..1c3acab082 100644
--- a/src/languageHandler.js
+++ b/src/languageHandler.js
@@ -133,7 +133,7 @@ export function setLanguage(preferredLangs) {
             throw new Error("Unable to find an appropriate language");
         }
 
-        return getLanguage(i18nFolder + availLangs[langToUse].fileName);
+        return getLanguage(i18nFolder + availLangs[langToUse]);
     }).then((langData) => {
         counterpart.registerTranslations(langToUse, langData);
         counterpart.setLocale(langToUse);
@@ -142,25 +142,16 @@ export function setLanguage(preferredLangs) {
 
         // Set 'en' as fallback language:
         if (langToUse != "en") {
-            return getLanguage(i18nFolder + availLangs['en'].fileName);
+            return getLanguage(i18nFolder + availLangs['en']);
         }
     }).then((langData) => {
         if (langData) counterpart.registerTranslations('en', langData);
     });
 };
 
-export function getAllLanguagesFromJson() {
-    return getLangsJson().then((langsObject) => {
-        var langs = [];
-        for (var langKey in langsObject) {
-            if (langsObject.hasOwnProperty(langKey)) {
-                langs.push({
-                    'value': langKey,
-                    'label': langsObject[langKey].label
-                });
-            }
-        }
-        return langs;
+export function getAllLanguageKeysFromJson() {
+    return getLangsJson().then((langs) => {
+        return Object.keys(langs);
     });
 }