import { defineStore } from 'pinia'; import { ref, computed, watch } from 'vue'; import { api, jApi } from '@/boot/axios'; import useNotify from '@/composables/useNotify.js'; import { useAppStore } from '@/stores/app.js'; const { notify } = useNotify(); const TOKEN_MULTIMEDIA = 'tokenMultimedia'; const TOKEN = 'token'; export const useUserStore = defineStore('user', () => { const token = ref(''); const tokenMultimedia = ref(''); const isGuest = ref(false); const user = ref(null); // Usuario en uso => supplantedUser || mainUser const supplantedUser = ref(null); // Usuario suplantado const mainUser = ref(null); // Usuario principal logueado const keepLogin = ref(false); const intervalId = ref(null); const isCheckingToken = ref(false); const tokenConfig = ref(null); let router; const storage = computed(() => keepLogin.value ? localStorage : sessionStorage ); const isLoggedIn = computed(() => !!token.value); const init = async _router => { router = _router; isGuest.value = localStorage.getItem('hederaGuest') || false; await getToken(); if (!isLoggedIn.value) { const autoLoginStatus = await tryAutoLogin(); if (!autoLoginStatus) { router.push({ name: 'login' }); } } else { await fetchTokenConfig(); await fetchUser(); await supplantInit(); startInterval(); } }; const getToken = () => { const tokenValue = sessionStorage.getItem(TOKEN) || localStorage.getItem(TOKEN); token.value = tokenValue; return tokenValue; }; const getTokenMultimedia = () => { const tokenMultimediaValue = sessionStorage.getItem(TOKEN_MULTIMEDIA) || localStorage.getItem(TOKEN_MULTIMEDIA); tokenMultimedia.value = tokenMultimediaValue; return tokenMultimediaValue; }; const setToken = ({ _token, _tokenMultimedia }) => { storage.value.setItem(TOKEN, _token); storage.value.setItem(TOKEN_MULTIMEDIA, _tokenMultimedia); token.value = _token; tokenMultimedia.value = _tokenMultimedia; }; const destroyToken = async (url, storageType, key) => { if (storageType.getItem(key)) { try { await api.post(url, null, { headers: { Authorization: storageType.getItem(key) } }); } catch (error) { notify('errors.statusUnauthorized', 'negative'); } finally { storageType.removeItem(key); } } }; const destroy = async (destroyTokens = true) => { const tokens = { tokenMultimedia: 'Accounts/logout', token: 'VnUsers/logout' }; let destroyTokenPromises = []; try { if (destroyTokens) { const response = await api.get('VnUsers/validateToken'); const isValidToken = response?.data; if (isValidToken) { destroyTokenPromises = Object.entries(tokens).map( ([key, url]) => destroyToken(url, storage.value, key) ); } } } finally { localStorage.clear(); sessionStorage.clear(); await Promise.allSettled(destroyTokenPromises); user.value = null; $reset(); stopRenewer(); } }; const setSession = data => { setToken({ _token: data.token, _tokenMultimedia: data.tokenMultimedia }); storage.value.setItem('hederaLastUser', data.username); storage.value.setItem('created', data.created); storage.value.setItem('ttl', data.ttl); localStorage.setItem('keepLogin', keepLogin.value); }; const fetchMultimediaToken = async data => { try { const response = await api.get('VnUsers/ShareToken', { headers: { Authorization: data.token } }); const multimediaToken = response?.data?.multimediaToken; return multimediaToken; } catch (error) { throw new Error('Error fetching multimedia token'); } }; const onLogin = async () => { await fetchUser(); router.push({ name: 'home' }); }; const login = async (username, password, remember) => { try { const params = { user: username, password }; const { data } = await api.post('Accounts/login', params); const multimediaToken = await fetchMultimediaToken(data); if (!multimediaToken) return; keepLogin.value = remember; setSession({ created: Date.now(), tokenMultimedia: multimediaToken.id, username, ...data }); await fetchTokenConfig(); startInterval(); await onLogin(); } catch (error) { throw new Error('Error logging in'); } }; const tryAutoLogin = async () => { if (isGuest.value) { localStorage.setItem('hederaGuest', true); return true; } if (!token.value) getToken(); if (token.value) return true; return false; }; const logout = async () => { try { await destroy(); } catch (e) {} useAppStore().onLogout(); }; const fetchTokenConfig = async () => { try { const { data } = await api.get('AccessTokenConfigs/findOne', { filter: { fields: ['renewInterval', 'renewPeriod'] } }); if (!data) return; tokenConfig.value = data; storage.value.setItem('renewPeriod', data.renewPeriod); return data; } catch (error) { notify('errors.tokenConfig', 'negative'); console.error('Error fetching token config:', error); } }; const renewToken = async () => { const _token = getToken(); const tokenData = await api.post('VnUsers/renewToken', { headers: { Authorization: _token } }); const _tokenMultimedia = getTokenMultimedia(); const tokenMultimedia = await api.post('VnUsers/renewToken', { headers: { Authorization: _tokenMultimedia } }); setToken({ _token: tokenData?.data?.id || '', _tokenMultimedia: tokenMultimedia?.data?.id || '' }); }; const checkValidity = async () => { const created = +storage.value.getItem('created'); const ttl = +storage.value.getItem('ttl'); if (isCheckingToken.value || !created) return; isCheckingToken.value = true; const renewPeriodInSeconds = Math.min(ttl, tokenConfig.value?.renewPeriod) * 1000; const maxDate = created + renewPeriodInSeconds; const now = new Date().getTime(); if (isNaN(renewPeriodInSeconds) || now <= maxDate) { isCheckingToken.value = false; return; } await renewToken(); isCheckingToken.value = false; }; const stopRenewer = () => { clearInterval(intervalId.value); }; const startInterval = () => { stopRenewer(); const renewPeriod = +storage.value.getItem('renewPeriod'); if (!renewPeriod) return; intervalId.value = setInterval( () => checkValidity(), renewPeriod * 1000 ); }; const fetchUser = async (userType = 'user') => { try { const userData = await api.get('VnUsers/getCurrentUserData'); if (userType === 'user') mainUser.value = userData.data; else supplantedUser.value = userData.data; } catch (error) { console.error('Error fetching user: ', error); } }; const supplantUser = async supplantUser => { const json = await jApi.send('client/supplant', { supplantUser }); token.value = json; sessionStorage.setItem('supplantUser', supplantUser); await fetchUser('supplantedUser'); }; const supplantInit = async () => { const user = sessionStorage.getItem('supplantUser'); if (!user) return; await supplantUser(user); }; const logoutSupplantedUser = async () => { sessionStorage.removeItem('supplantUser'); supplantedUser.value = null; await api.post('Accounts/logout'); getToken(); await fetchUser(); }; const updateUserLang = async lang => { if (!user.value || user.value.lang === lang) return; user.value.lang = lang; }; const $reset = () => { token.value = ''; tokenMultimedia.value = ''; isGuest.value = false; user.value = null; supplantedUser.value = null; mainUser.value = null; keepLogin.value = false; intervalId.value = null; isCheckingToken.value = false; tokenConfig.value = null; }; watch( [mainUser, supplantedUser], () => (user.value = supplantedUser.value || mainUser.value), { immediate: true } ); return { token, tokenMultimedia, isGuest, user, supplantedUser, mainUser, keepLogin, intervalId, isCheckingToken, tokenConfig, isLoggedIn, storage, getToken, getTokenMultimedia, setToken, destroyToken, destroy, setSession, login, tryAutoLogin, logout, fetchTokenConfig, renewToken, checkValidity, stopRenewer, startInterval, fetchUser, supplantUser, supplantInit, logoutSupplantedUser, updateUserLang, init, $reset, onLogin }; });