diff --git a/package-lock.json b/package-lock.json index 547acbd..ba6a5de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2529,6 +2529,11 @@ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz", "integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==" }, + "argh": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/argh/-/argh-0.1.4.tgz", + "integrity": "sha1-PrTWEpc/xrbcbvM49W91nyrFw6Y=" + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -3020,8 +3025,7 @@ "bluebird": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", - "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==", - "dev": true + "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==" }, "bn.js": { "version": "4.11.8", @@ -3504,6 +3508,11 @@ } } }, + "camelify": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/camelify/-/camelify-0.0.2.tgz", + "integrity": "sha1-4UNHKrbvJbiUpOhcNUyZd6sfHhU=" + }, "caniuse-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", @@ -3840,6 +3849,11 @@ "simple-swizzle": "^0.2.2" } }, + "colors": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", + "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=" + }, "combined-stream": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", @@ -5923,6 +5937,22 @@ "locate-path": "^3.0.0" } }, + "findup": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/findup/-/findup-0.1.5.tgz", + "integrity": "sha1-itkpozk7rGJ5V6fl3kYjsGsOLOs=", + "requires": { + "colors": "~0.6.0-1", + "commander": "~2.1.0" + }, + "dependencies": { + "commander": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz", + "integrity": "sha1-0SG7roYNmZKj1Re6lvVliOR8Z4E=" + } + } + }, "fkill": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/fkill/-/fkill-6.1.0.tgz", @@ -9114,9 +9144,9 @@ } }, "node-sass": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.12.0.tgz", - "integrity": "sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.0.tgz", + "integrity": "sha512-W1XBrvoJ1dy7VsvTAS5q1V45lREbTlZQqFbiHb3R3OTTCma0XBtuG6xZ6Z4506nR4lmHPTqVRwxT6KgtWC97CA==", "requires": { "async-foreach": "^0.1.3", "chalk": "^1.1.1", @@ -9125,7 +9155,7 @@ "get-stdin": "^4.0.1", "glob": "^7.0.3", "in-publish": "^2.0.0", - "lodash": "^4.17.11", + "lodash": "^4.17.15", "meow": "^3.7.0", "mkdirp": "^0.5.1", "nan": "^2.13.2", @@ -9168,6 +9198,11 @@ "which": "^1.2.9" } }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, "lru-cache": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", @@ -12343,6 +12378,33 @@ "path-key": "^2.0.0" } }, + "npm-sass": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/npm-sass/-/npm-sass-2.3.0.tgz", + "integrity": "sha512-/Msbyq/rsqMJslcxRrRNdxTR2VUTEXETNsYhPWw/lSb+QgpnDdWi4LOocfEpCleDPLzP7FnkM7w9Bc0mKP3xcg==", + "requires": { + "argh": "^0.1.4", + "bluebird": "^3.5.1", + "camelify": "0.0.2", + "findup": "^0.1.5", + "glob": "^6.0.1", + "node-sass": "^4.9.0" + }, + "dependencies": { + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, "npmlog": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", diff --git a/package.json b/package.json index 31aa5c6..5911fae 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,9 @@ "i": "^0.3.6", "jquery": "^3.3.1", "js-cookie": "^2.2.0", - "node-sass": "^4.12.0", + "node-sass": "^4.13.0", "npm": "^6.9.0", + "npm-sass": "^2.3.0", "popper.js": "^1.15.0", "socket.io-client": "^2.3.0", "vee-validate": "^2.2.4", diff --git a/src/App.vue b/src/App.vue index 25bc755..cbe0082 100644 --- a/src/App.vue +++ b/src/App.vue @@ -28,8 +28,6 @@ About - Logout - Login {{ $t('Rooms') }} {{ $t('Recorders') }} @@ -57,18 +55,25 @@ - + Profile - Sign Out + Sign Out + Login - ({{tokenValidity}}) | - ({{refreshTokenValidity}}) + ({{$t('Session will timeout in: ')}}{{tokenValidity}}) + {{$t('Session has expired!')}} {{$t('Click here to refresh session')}} +  | ({{refreshTokenValidity}}) + + + + {{$t('Can\'t renew session – please login again!')}} @@ -94,6 +99,7 @@ langs: ['de', 'en', 'es'], dismissSecs: 5, dismissCountDown: 0, + autoRenewSession: false, }; }, methods: { @@ -105,6 +111,14 @@ countDownChanged(dismissCountDown) { this.dismissCountDown = dismissCountDown; }, + + logout() { + this.$store.dispatch('logout', {revokeRefreshToken: true}); + this.$router.push({name: 'home'}); + }, + refreshToken() { + this.$store.dispatch('refreshToken'); + } }, mounted() { EventBus.$on('failedLoadingRecorders', (msg) => { @@ -113,23 +127,37 @@ EventBus.$on('failedLoadingRooms', (msg) => { this.showErrorMessage(msg); }); - EventBus.$on('failedRefreshingToken', (msg)=>{ + EventBus.$on('failedRefreshingToken', (msg) => { this.refreshFailed = true; }); this.$nextTick(() => { window.setInterval(() => { - // this.$log.debug(getRemainingJwtValiditySeconds(this.$store.state.access_token)); - this.tokenValidity = getRemainingJwtValiditySeconds(this.$store.state.access_token); - this.refreshTokenValidity = getRemainingJwtValiditySeconds(this.$store.state.refresh_token); + //this.$log.debug(getRemainingJwtValiditySeconds(this.$store.state.access_token)); + let tokenValidity = getRemainingJwtValiditySeconds(this.$store.state.access_token); + + //this.tokenValidity = this.tokenValidity.format('mm:ss'); + let refreshTokenValidity = getRemainingJwtValiditySeconds(this.$store.state.refresh_token); + // this.$log.debug(this.$store.state); - if (this.tokenValidity < 50 && this.refreshTokenValidity > 30 && !this.refreshFailed) { + if (tokenValidity < 50 && refreshTokenValidity > 30 && this.autoRenewSession && !this.refreshFailed) { this.$store.dispatch('refreshToken'); // renew access token } - if(this.refreshFailed){ + if (this.autoRenewSession && this.refreshFailed) { this.$store.dispatch('resetToken'); // delete all token info if refresh fails - this.$router.push({ name: 'login'}); + this.$router.push({name: 'login'}); this.refreshFailed = false; } + if (isNaN(tokenValidity)) { + this.tokenValidity = false; + } else { + this.tokenValidity = new Date(1000 * tokenValidity).toISOString().substr(14, 5); + } + if (isNaN(tokenValidity)) { + this.refreshTokenValidity = false; + } else { + this.refreshTokenValidity = new Date(1000 * refreshTokenValidity).toISOString().substr(11, 8); + } + }, 1000); }); diff --git a/src/api/index.ts b/src/api/index.ts index afdd11f..c8244b0 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -23,6 +23,10 @@ export function authenticate(userData: any) { return axios.post(`${API_URL}/auth/login`, userData); } +export function revokeRefreshKey(jwt: any) { + return axios.post(`${API_URL}/auth/revokeRefreshToken`, { headers: { Authorization: `Bearer ${jwt}` } }); +} + export function register(userData: any) { return axios.post(`${API_URL}/auth/register`, userData); } diff --git a/src/components/Login.vue b/src/components/Login.vue index 1520a1a..134d170 100644 --- a/src/components/Login.vue +++ b/src/components/Login.vue @@ -2,54 +2,55 @@ @@ -64,6 +65,9 @@ email: '', password: '', errorMsg: '', + redirectMsg: '', + redirectTarget: 'profile', + redirectTime: 5, loginProviders: [], }; }, @@ -79,6 +83,10 @@ oidc_login() { this.$store.dispatch('oidc_login', '\\oidc_login_redirection'); }, + logout() { + this.$store.dispatch('logout', {revokeRefreshToken: true}); + this.$router.push({name: 'home'}); + }, }, mounted() { // this.$parent.$data.isLoading = true; @@ -104,6 +112,22 @@ this.$cookies.remove('tokens'); } this.$log.debug(this.$cookies.keys()); + + this.$nextTick(() => { + if (this.authenticated) { + if (this.$route.query.redirectionTarget) { + this.redirectTarget = this.$route.query.redirectionTarget; + } + let interval = window.setInterval(() => { + console.log(this.redirectTime); + this.redirectTime = this.redirectTime - 1; + if (this.redirectTime < 0) { + clearInterval(interval); + this.$router.push({name: this.redirectTarget}); + } + }, 1000); + } + }); }, beforeDestroy() { EventBus.$off('failedRegistering'); diff --git a/src/store.ts b/src/store.ts index 1118f0c..a8677a6 100644 --- a/src/store.ts +++ b/src/store.ts @@ -14,7 +14,7 @@ import { postNewSurvey, authenticate, register, - oidc_login, fetchUsers, getFreshToken, fetchProfile, fetchUserGroups, + oidc_login, fetchUsers, getFreshToken, fetchProfile, fetchUserGroups, revokeRefreshKey, } from '@/api'; import {isValidJwt, EventBus} from '@/utils'; @@ -184,6 +184,17 @@ const actions = { EventBus.$emit('failedAuthentication', error); }); }, + logout(context: any, revokeRefreshToken: any) { + context.commit('setTokens', {tokens: {access_token: '', refresh_token: ''}}); + if(revokeRefreshToken){ + return revokeRefreshKey(context.state.access_token) + .catch((error) => { + Vue.$log.warn('Error Authenticating (Could not revoke refresh token): ', error); + EventBus.$emit('failedRevokingRefreshToken', error); + }); + } + //this.clearAll(); + }, oidc_login(context: any, redirectionUrl: any) { // context.commit('setUserData', { userData }); return oidc_login(redirectionUrl)