diff --git a/package.json b/package.json index 2a34343..94fabdb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "passwall-extension", - "version": "1.0.6", + "version": "1.0.8", "private": true, "scripts": { "serve": "vue-cli-service build --mode development --watch", diff --git a/src/mixins/list.js b/src/mixins/list.js index 5259439..c5863c7 100644 --- a/src/mixins/list.js +++ b/src/mixins/list.js @@ -3,9 +3,7 @@ import { mapState } from 'vuex' export default { beforeRouteEnter(to, from, next) { next(vm => { - if (!to.params.cache) { vm.fetchAll() - } }) }, methods: { diff --git a/src/popup/config.js b/src/popup/config.js index 3045037..afb8684 100644 --- a/src/popup/config.js +++ b/src/popup/config.js @@ -33,10 +33,10 @@ import vOutsideEvents from 'vue-outside-events' Vue.use(vOutsideEvents) import Notifications from 'vue-notification' -Vue.use(Notifications, { duration: 2500 }) -Vue.prototype.$notifyError = text => Vue.prototype.$notify({ type: 'error', duration: 5000, text }) -Vue.prototype.$notifyWarn = text => Vue.prototype.$notify({ type: 'warn', duration: 5000, text }) -Vue.prototype.$notifySuccess = text => Vue.prototype.$notify({ type: 'success', duration: 5000, text }) +Vue.use(Notifications, { duration: 3000 }) +Vue.prototype.$notifyError = text => Vue.prototype.$notify({ type: 'error', text }) +Vue.prototype.$notifyWarn = text => Vue.prototype.$notify({ type: 'warn', text }) +Vue.prototype.$notifySuccess = text => Vue.prototype.$notify({ type: 'success', text }) window.wait = new VueWait({ registerComponent: false, @@ -44,8 +44,8 @@ window.wait = new VueWait({ }) Vue.directive('click-outside', { - bind: function(el, binding, vnode) { - el.clickOutsideEvent = function(event) { + bind: function (el, binding, vnode) { + el.clickOutsideEvent = function (event) { // here I check that click was outside the el and his children if (!(el == event.target || el.contains(event.target))) { // and if it did, call method provided in attribute value @@ -54,7 +54,7 @@ Vue.directive('click-outside', { } document.body.addEventListener('click', el.clickOutsideEvent) }, - unbind: function(el) { + unbind: function (el) { document.body.removeEventListener('click', el.clickOutsideEvent) } }) @@ -65,28 +65,42 @@ requireComponent.keys().forEach(fileName => { Vue.component(componentConfig.default.name, componentConfig.default) }) -Vue.prototype.$request = async (callback, waitKey, errorCallback = null) => { - try { - window.wait.start(waitKey) +Vue.prototype.$request = async (callback, waitKey, errorCallback = null, retry = false) => { + window.wait.start(waitKey) + + try { await callback() } catch (error) { - console.log(error) + console.error(error) - if (error.response) { - if (error.response.status === 401 && !router.app._route.meta.auth) { + // No connection + if (!error.response) { + Vue.prototype.$notifyError('Network Error !') + Vue.prototype.$wait.end(waitKey) + return + } + + if (error.response.status === 401 && !router.app._route.meta.auth && !retry) { + // Refresh token + try { + await store.dispatch('RefreshToken') + // Retry the connection + return Vue.prototype.$request(callback, waitKey, errorCallback, true) + } catch (refreshError) { + Vue.prototype.$notifyError('Authorization expired.') + + // Reset all tokens await store.dispatch('Logout') return router.push({ name: 'Login' }) } + } - if (errorCallback) { - errorCallback(error) - } else if (error.response.status >= 500) { - Vue.prototype.$notifyError(i18n.t('API500ErrorMessage')) - } else if (error.response.data.Message && error.response.status != 401) { - Vue.prototype.$notifyError(error.response.data.Message) - } - } else { - Vue.prototype.$notifyError('Network Error !') + if (errorCallback) { + errorCallback(error) + } else if (error.response.status >= 500) { + Vue.prototype.$notifyError(i18n.t('API500ErrorMessage')) + } else if (error.response.data.Message && error.response.status != 401) { + Vue.prototype.$notifyError(error.response.data.Message) } } finally { window.wait.end(waitKey) @@ -100,7 +114,7 @@ if ( window.screenLeft > window.screen.width || window.screenTop > window.screen.height ) { - chrome.runtime.getPlatformInfo(function(info) { + chrome.runtime.getPlatformInfo(function (info) { if (info.os === 'mac') { const fontFaceSheet = new CSSStyleSheet() fontFaceSheet.insertRule(` diff --git a/src/popup/router/index.js b/src/popup/router/index.js index 417caf9..821f439 100644 --- a/src/popup/router/index.js +++ b/src/popup/router/index.js @@ -2,6 +2,7 @@ import Vue from 'vue' import Router from 'vue-router' import AuthCheck from './auth-check' import ClearSearch from '@p/router/clear-search' +import Storage from '@/utils/storage' Vue.use(Router) @@ -119,13 +120,42 @@ const router = new Router({ ] }) +router.afterEach((to, from) => { + Storage.setItem('latest_route', to.name) + Storage.setItem('latest_route_param_detail', to.params.detail) + Storage.setItem('create_form', null) +}) + router.afterEach((to, from) => { const toDepth = to.path.split('/').length const fromDepth = from.path.split('/').length to.meta.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left' }) + router.afterEach(ClearSearch) router.beforeEach(AuthCheck) +let isFirstTransition = true; +router.beforeEach(async (to, from, next) => { + const lastRouteName = await Storage.getItem('latest_route') + const detail = await Storage.getItem('latest_route_param_detail') + const shouldRedirect = Boolean( + to.name === "Logins" && lastRouteName && isFirstTransition + ) + + if (shouldRedirect) { + if (lastRouteName.search("Detail") > -1) { + next({ name: lastRouteName, params: { detail, id: detail.id } }) + } else { + next({ name: lastRouteName }) + } + } else { + next() + } + + isFirstTransition = false + +}) + export default router diff --git a/src/popup/store/index.js b/src/popup/store/index.js index 442fe0f..eee6c75 100644 --- a/src/popup/store/index.js +++ b/src/popup/store/index.js @@ -44,6 +44,27 @@ export default new Vuex.Store({ state.master_hash = await Storage.getItem('master_hash') }, + async RefreshToken({ state }, payload) { + + var token = await Storage.getItem('refresh_token') + const { data } = await AuthService.Refresh({refresh_token:token}) + + state.access_token = data.access_token + state.refresh_token = data.refresh_token + state.transmission_key = data.transmission_key.substr(0, 32) + CryptoUtils.transmissionKey = state.transmission_key + + // P.S.: Because we don't have a payload, we didn't update the master hash + + await Promise.all([ + Storage.setItem('access_token', data.access_token), + Storage.setItem('refresh_token', data.refresh_token), + Storage.setItem('transmission_key', state.transmission_key) + ]) + + HTTPClient.setHeader('Authorization', `Bearer ${state.access_token}`) + }, + async Login({ state }, payload) { payload.master_password = CryptoUtils.sha256Encrypt(payload.master_password) @@ -72,6 +93,7 @@ export default new Vuex.Store({ async Logout({ state }) { const email = await Storage.getItem('email') + const server = await Storage.getItem('server') await Storage.clear() state.access_token = null state.refresh_token = null @@ -79,6 +101,7 @@ export default new Vuex.Store({ state.master_hash = null state.user = null await Storage.setItem('email', email) + await Storage.setItem('server', server) }, async loadStore({ state }) { state.user = await Storage.getItem('user') diff --git a/src/popup/views/BankAccounts/create.vue b/src/popup/views/BankAccounts/create.vue index 621d9a3..d23c654 100644 --- a/src/popup/views/BankAccounts/create.vue +++ b/src/popup/views/BankAccounts/create.vue @@ -16,7 +16,8 @@