diff --git a/src/components/Home.vue b/src/components/Home.vue index 6b19b8c..8370a7f 100644 --- a/src/components/Home.vue +++ b/src/components/Home.vue @@ -37,7 +37,7 @@ export default { methods: { logout() { //TODO - For guest accounts, show warning about not being able to rejoin. - this.$store.dispatch("auth/logout"); + this.$store.dispatch("logout"); this.$nextTick(() => { this.$navigation.push({path: "/login"}, -1); }) diff --git a/src/components/Join.vue b/src/components/Join.vue index 1893e02..7d32e2d 100644 --- a/src/components/Join.vue +++ b/src/components/Join.vue @@ -60,6 +60,7 @@
{{ data.item.name }}
+ @@ -200,6 +201,14 @@ export default { .substring(0, 1) .toUpperCase(); }, + sharedComputer: { + get: function () { + return !this.$store.state.useLocalStorage; + }, + set: function (sharedComputer) { + this.$store.commit('setUseLocalStorage', !sharedComputer); + }, + } }, watch: { roomId: { @@ -264,7 +273,7 @@ export default { if (this.$matrix.ready) { return Promise.resolve(this.$matrix.currentUser); } - return this.$store.dispatch("auth/login", this.currentUser || this.guestUser); + return this.$store.dispatch("login", this.currentUser || this.guestUser); }, getRoomInfo() { diff --git a/src/components/Login.vue b/src/components/Login.vue index f75cc33..9325638 100644 --- a/src/components/Login.vue +++ b/src/components/Login.vue @@ -120,7 +120,7 @@ export default { user.normalize(); this.loading = true; - this.$store.dispatch("auth/login", user).then( + this.$store.dispatch("login", user).then( () => { if (this.$matrix.currentRoomId) { this.$navigation.push({name: "Chat", params: { roomId: util.sanitizeRoomId(this.$matrix.currentRoomId) }}, -1); diff --git a/src/components/Profile.vue b/src/components/Profile.vue index a8f6471..678e013 100644 --- a/src/components/Profile.vue +++ b/src/components/Profile.vue @@ -146,7 +146,7 @@ export default { methods: { logout() { //TODO - For guest accounts, show warning about not being able to rejoin. - this.$store.dispatch("auth/logout"); + this.$store.dispatch("logout"); this.$nextTick(() => { this.$navigation.push({path: "/login"}, -1); }) diff --git a/src/main.js b/src/main.js index 6ac96b5..4b6ed62 100644 --- a/src/main.js +++ b/src/main.js @@ -1,8 +1,8 @@ import Vue from 'vue' import App from './App.vue' import vuetify from './plugins/vuetify'; -import router from './router' import store from './store' +import router from './router' import matrix from './services/matrix.service' import navigation from './services/navigation.service' import cleaninsights from './services/cleaninsights.service' @@ -151,8 +151,8 @@ Vue.use(navigation, router); new Vue({ vuetify, - router, store, + router, matrix, cleaninsights, render: h => h(App) diff --git a/src/router/index.js b/src/router/index.js index 72a1aa5..8a088b0 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -84,7 +84,7 @@ const router = new VueRouter({ router.beforeEach((to, from, next) => { const publicPages = ['/login']; var authRequired = !publicPages.includes(to.path); - const loggedIn = localStorage.getItem('user'); + const loggedIn = router.app.$store.state.auth.user; if (to.name == 'Chat' || to.name == 'Join') { if (!to.params.roomId && to.hash) { diff --git a/src/services/matrix.service.js b/src/services/matrix.service.js index 597a7f3..5c0827d 100644 --- a/src/services/matrix.service.js +++ b/src/services/matrix.service.js @@ -7,9 +7,6 @@ import config from "../assets/config"; const LocalStorageCryptoStore = require("matrix-js-sdk/lib/crypto/store/localStorage-crypto-store") .LocalStorageCryptoStore; -sdk.setCryptoStoreFactory( - () => new LocalStorageCryptoStore(window.localStorage) -); export default { install(Vue, options) { @@ -86,10 +83,15 @@ export default { }, methods: { + createCryptoStore() { + console.log("create crypto store"); + return new LocalStorageCryptoStore(this.$store.getters.storage); + }, login(user) { const tempMatrixClient = sdk.createClient(User.homeServerUrl(user.home_server)); var promiseLogin; - + + const self = this; if (user.access_token) { // Logged in on "real" account promiseLogin = Promise.resolve(user); @@ -109,7 +111,7 @@ export default { console.log("Response", response); response.password = pass; response.is_guest = true; - localStorage.setItem('user', JSON.stringify(response)); + this.$store.commit("setUser", response); return response; }) } else { @@ -125,15 +127,15 @@ export default { // Copy over needed properties u = Object.assign(user, response); } - localStorage.setItem('user', JSON.stringify(u)); + this.$store.commit("setUser", u); return response; }) } return promiseLogin - .then(user => { - return this.getMatrixClient(user); - }) + .then((user) => { + return self.getMatrixClient(user); + }); }, clearCryptoStore() { @@ -141,12 +143,13 @@ export default { // TODO - for some reason "clearStores" called in "logout" only clears the "account" crypto // data item, not all sessions etc. Why? We need to do that manually here! const toRemove = []; - for (let i = 0; i < localStorage.length; ++i) { - const key = localStorage.key(i); + const storage = this.$store.getters.storage; + for (let i = 0; i < storage.length; ++i) { + const key = storage.key(i); if (key.startsWith("crypto.")) toRemove.push(key); } for (const key of toRemove) { - localStorage.removeItem(key); + storage.removeItem(key); } }, @@ -164,7 +167,7 @@ export default { } - localStorage.removeItem('user'); + this.$store.commit("setUser", null); this.$store.commit("setCurrentRoomId", null); this.rooms = []; this.userDisplayName = null; @@ -188,7 +191,7 @@ export default { }) }, - async getMatrixClient(user) { + getMatrixClient(user) { if (user === undefined) { user = this.$store.state.auth.user; } @@ -204,9 +207,9 @@ export default { }) } - const matrixStore = new sdk.MemoryStore(window.localStorage); + const matrixStore = new sdk.MemoryStore(this.$store.getters.storage); const webStorageSessionStore = new sdk.WebStorageSessionStore( - window.localStorage + this.$store.getters.storage ); var homeServer = user.home_server; @@ -334,14 +337,14 @@ export default { // we need to hang on to the generated password and use that to login to a new // session, so only wipe the token in s that case. // Clear the access token - var user = JSON.parse(localStorage.getItem('user')); + var user = JSON.parse(this.$store.state.auth.user); if (user.is_guest) { delete user.access_token; - localStorage.setItem('user', JSON.stringify(user)); + this.$store.commit("setUser", user); // Login again this.login(user); } else { - localStorage.removeItem('user'); + this.$store.commit("setUser", null); this.$store.commit("setCurrentRoomId", null); this.$navigation.push({ path: "/login" }, -1); } @@ -567,7 +570,7 @@ export default { // Forget password and remove the 'is_guest' flag, we are now a "real" user! self.currentUser.password = undefined; self.currentUser.is_guest = false; - localStorage.setItem('user', JSON.stringify(self.currentUser)); + self.$store.commit("setUser", self.currentUser); }) .then(() => { return true; @@ -598,7 +601,7 @@ export default { }) } else { const tempMatrixClient = sdk.createClient(config.defaultServer); - var tempUserString = localStorage.getItem('tempuser'); + var tempUserString = this.$store.state.tempuser; var tempUser = null; if (tempUserString) { tempUser = JSON.parse(tempUserString); @@ -619,7 +622,7 @@ export default { console.log("Response", response); response.password = pass; response.is_guest = true; - localStorage.setItem('tempuser', JSON.stringify(response)); + this.$store.commit("setTempUser", response); return response; }); } @@ -697,6 +700,8 @@ export default { } }) + sdk.setCryptoStoreFactory(matrixService.createCryptoStore.bind(matrixService)); + Vue.prototype.$matrix = matrixService; } } diff --git a/src/store/auth.module.js b/src/store/auth.module.js deleted file mode 100644 index 38aabbe..0000000 --- a/src/store/auth.module.js +++ /dev/null @@ -1,47 +0,0 @@ -const user = JSON.parse(localStorage.getItem('user')); -const initialState = user - ? { status: { loggedIn: true }, user } - : { status: { loggedIn: false }, user: null }; - -export const auth = { - namespaced: true, - state: initialState, - actions: { - login({ commit }, user) { - return this._vm.$matrix.login(user).then( - user => { - commit('loginSuccess', user); - return Promise.resolve(user); - }, - error => { - commit('loginFailure'); - return Promise.reject(error); - } - ); - }, - logout({ commit }) { - this._vm.$matrix.logout(); - commit('logout'); - }, - }, - mutations: { - loginSuccess(state, user) { - state.status.loggedIn = true; - state.user = user; - }, - loginFailure(state) { - state.status.loggedIn = false; - state.user = null; - }, - logout(state) { - state.status.loggedIn = false; - state.user = null; - }, - registerSuccess(state) { - state.status.loggedIn = false; - }, - registerFailure(state) { - state.status.loggedIn = false; - } - } -}; \ No newline at end of file diff --git a/src/store/index.js b/src/store/index.js index 0aeb98f..f0b8e7e 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -2,31 +2,119 @@ import Vue from 'vue' import Vuex from 'vuex' import VuexPersist from 'vuex-persist' -import { auth } from './auth.module'; - Vue.use(Vuex) -const vuexPersist = new VuexPersist({ + +// A Vuex plugin to persist the user object to either session or local storage, based on flag in the store state. +// +const persistUserPlugin = store => { + var user; + if (store.state.useLocalStorage) { + user = JSON.parse(window.localStorage.getItem('user')); + } else { + user = JSON.parse(window.sessionStorage.getItem('user')); + } + const initialState = user ? { status: { loggedIn: true }, user } : { status: { loggedIn: false }, user: null }; + store.state.auth = initialState; + + store.subscribe((mutation, state) => { + if (mutation.type == 'setUser' || mutation.type == 'setUseLocalStorage') { + if (state.useLocalStorage) { + window.localStorage.setItem('user', JSON.stringify(state.auth.user)); + window.sessionStorage.removeItem('user'); + } else { + window.sessionStorage.setItem('user', JSON.stringify(state.auth.user)); + window.localStorage.removeItem('user'); + } + } + }) +} + + +const vuexPersistLocalStorage = new VuexPersist({ key: 'settings', storage: localStorage, - reducer: state => ({ - currentRoomId: state.currentRoomId - }) - }) + reducer: state => { + if (state.useLocalStorage) { + return { + currentRoomId: state.currentRoomId, + }; + } else { + return {}; + } + } +}) + +const vuexPersistSessionStorage = new VuexPersist({ + key: 'settings', + storage: sessionStorage, + reducer: state => { + if (!state.useLocalStorage) { + return { + currentRoomId: state.currentRoomId, + }; + } else { + return {}; + } + } +}) + +const defaultUseSessionStorage = (sessionStorage.getItem('user') != null); export default new Vuex.Store({ - state: { - currentRoomId: null - }, + state: { currentRoomId: null, auth: null, tempuser: null, useLocalStorage: !defaultUseSessionStorage }, mutations: { + loginSuccess(state, user) { + state.auth.status.loggedIn = true; + state.auth.user = user; + }, + loginFailure(state) { + state.auth.status.loggedIn = false; + state.auth.user = null; + }, + logout(state) { + state.auth.status.loggedIn = false; + state.auth.user = null; + }, setCurrentRoomId(state, roomId) { state.currentRoomId = roomId; }, + setUser(state, user) { + state.auth.user = JSON.stringify(user); + }, + setTempUser(state, user) { + state.tempuser = JSON.stringify(user); + }, + setUseLocalStorage(state, useLocalStorage) { + state.useLocalStorage = useLocalStorage; + } }, actions: { + login({ commit }, user) { + return this._vm.$matrix.login(user).then( + user => { + commit('loginSuccess', user); + return Promise.resolve(user); + }, + error => { + commit('loginFailure'); + return Promise.reject(error); + } + ); + }, + logout({ commit }) { + this._vm.$matrix.logout(); + commit('logout'); + }, }, - modules: { - auth + getters: { + storage: state => { + if (state.useLocalStorage) { + return window.localStorage; + } else { + return window.sessionStorage; + } + } }, - plugins: [vuexPersist.plugin] + plugins: [vuexPersistLocalStorage.plugin, vuexPersistSessionStorage.plugin, persistUserPlugin] })