Set user info from api instead of only relying on the info encoded in the jwt token

This commit is contained in:
kolaente 2021-04-07 15:58:29 +02:00
parent b35c2d6f2c
commit 8a34ad34ab
Signed by untrusted user: konrad
GPG Key ID: F40E70337AB24C9B

View File

@ -7,14 +7,17 @@ export default {
state: () => ({ state: () => ({
authenticated: false, authenticated: false,
isLinkShareAuth: false, isLinkShareAuth: false,
info: {}, info: null,
needsTotpPasscode: false, needsTotpPasscode: false,
avatarUrl: '', avatarUrl: '',
lastUserInfoRefresh: null,
}), }),
mutations: { mutations: {
info(state, info) { info(state, info) {
state.info = info state.info = info
state.avatarUrl = info.getAvatarUrl() if (info !== null) {
state.avatarUrl = info.getAvatarUrl()
}
}, },
setUserSettings(state, {name, emailRemindersEnabled}) { setUserSettings(state, {name, emailRemindersEnabled}) {
state.info.name = name state.info.name = name
@ -32,6 +35,9 @@ export default {
reloadAvatar(state) { reloadAvatar(state) {
state.avatarUrl = `${state.info.getAvatarUrl()}&=${+new Date()}` state.avatarUrl = `${state.info.getAvatarUrl()}&=${+new Date()}`
}, },
lastUserRefresh(state) {
state.lastUserInfoRefresh = new Date()
},
}, },
actions: { actions: {
// Logs a user in with a set of credentials. // Logs a user in with a set of credentials.
@ -58,6 +64,7 @@ export default {
// Tell others the user is autheticated // Tell others the user is autheticated
ctx.commit('isLinkShareAuth', false) ctx.commit('isLinkShareAuth', false)
console.log('login')
ctx.dispatch('checkAuth') ctx.dispatch('checkAuth')
return Promise.resolve() return Promise.resolve()
}) })
@ -150,6 +157,13 @@ export default {
}, },
// Populates user information from jwt token saved in local storage in store // Populates user information from jwt token saved in local storage in store
checkAuth(ctx) { checkAuth(ctx) {
// This function can be called from multiple places at the same time and shortly after one another.
// To prevent hitting the api too frequently or race conditions, we check at most once per minute.
if (ctx.state.lastUserInfoRefresh !== null && ctx.state.lastUserInfoRefresh > (new Date()).setMinutes((new Date()).getMinutes() + 1)) {
return Promise.resolve()
}
const jwt = localStorage.getItem('token') const jwt = localStorage.getItem('token')
let authenticated = false let authenticated = false
if (jwt) { if (jwt) {
@ -159,12 +173,40 @@ export default {
.replace('_', '/') .replace('_', '/')
const info = new UserModel(JSON.parse(window.atob(base64))) const info = new UserModel(JSON.parse(window.atob(base64)))
const ts = Math.round((new Date()).getTime() / 1000) const ts = Math.round((new Date()).getTime() / 1000)
if (info.exp >= ts) { authenticated = info.exp >= ts
authenticated = true
}
ctx.commit('info', info) ctx.commit('info', info)
if (authenticated ) {
const HTTP = HTTPFactory()
// We're not returning the promise here to prevent blocking the initial ui render if the user is
// accessing the site with a token in local storage
HTTP.get('user', {
headers: {
Authorization: `Bearer ${jwt}`,
},
})
.then(r => {
const info = new UserModel(r.data)
info.type = ctx.state.info.type
info.email = ctx.state.info.email
info.exp = ctx.state.info.exp
info.emailRemindersEnabled = ctx.state.info.emailRemindersEnabled
ctx.commit('info', info)
ctx.commit('authenticated', authenticated)
ctx.commit('lastUserRefresh')
})
.catch(e => {
console.error('Error while refreshing user info:', e)
})
}
} }
ctx.commit('authenticated', authenticated) ctx.commit('authenticated', authenticated)
if (!authenticated) {
ctx.commit('info', null)
}
return Promise.resolve() return Promise.resolve()
}, },
// Renews the api token and saves it to local storage // Renews the api token and saves it to local storage