diff --git a/store/account.ts b/store/account.ts index 3fd1ef617..299626068 100644 --- a/store/account.ts +++ b/store/account.ts @@ -1,6 +1,7 @@ import { defineStore, createPinia, setActivePinia } from 'pinia'; -import { useCallbackStore } from './callbackActions'; -import { useServerStore } from './server'; +import { useCallbackStore } from '~/store/callbackActions'; +import { useErrorsStore } from '~/store/errors'; +import { useServerStore } from '~/store/server'; import { WebguiUpdate } from '~/composables/services/webgui'; import { ACCOUNT } from '~/helpers/urls'; import type { ExternalSignIn, ExternalSignOut } from '~/store/callback'; @@ -12,6 +13,7 @@ setActivePinia(createPinia()); export const useAccountStore = defineStore('account', () => { const callbackStore = useCallbackStore(); + const errorsStore = useErrorsStore(); const serverStore = useServerStore(); // State @@ -108,26 +110,6 @@ export const useAccountStore = defineStore('account', () => { accountAction.value = action; accountActionStatus.value = 'updating'; - const userPayload = { - ...(accountAction.value.user - ? { - apikey: accountAction.value.apiKey, - // avatar: '', - email: accountAction.value.user?.email, - regWizTime: `${Date.now()}_${serverStore.guid}`, // set when signing in the first time and never unset for the sake of displaying Sign In/Up in the UPC without needing to validate guid every time - username: accountAction.value.user?.preferred_username, - } - : { - accesstoken: '', - apikey: '', - avatar: '', - email: '', - idtoken: '', - refreshtoken: '', - username: '', - }), - }; - if (!serverStore.registered && !accountAction.value.user) { console.debug('[accountStore.updatePluginConfig] Not registered skipping sign out'); accountActionHide.value = true; @@ -136,6 +118,25 @@ export const useAccountStore = defineStore('account', () => { } try { + const userPayload = { + ...(accountAction.value.user + ? { + apikey: accountAction.value.apiKey, + // avatar: '', + email: accountAction.value.user?.email, + regWizTime: `${Date.now()}_${serverStore.guid}`, // set when signing in the first time and never unset for the sake of displaying Sign In/Up in the UPC without needing to validate guid every time + username: accountAction.value.user?.preferred_username, + } + : { + accesstoken: '', + apikey: '', + avatar: '', + email: '', + idtoken: '', + refreshtoken: '', + username: '', + }), + }; const response = await WebguiUpdate .formUrl({ csrf_token: serverStore.csrf, @@ -151,11 +152,13 @@ export const useAccountStore = defineStore('account', () => { .catch(err => { console.debug('[accountStore.updatePluginConfig] WebguiUpdate err', err); accountActionStatus.value = 'failed'; + errorsStore.setError(err); }); return response; } catch(err) { console.debug('[accountStore.updatePluginConfig] WebguiUpdate catch err', err); accountActionStatus.value = 'failed'; + errorsStore.setError(err); } }; diff --git a/store/callback.ts b/store/callback.ts index cecfd7af4..008c21015 100644 --- a/store/callback.ts +++ b/store/callback.ts @@ -108,20 +108,25 @@ export const useCallbackStoreGeneric = ( const send = (url: string, payload: SendPayloads, sendType?: 'fromUpc' | 'forUpc') => { console.debug('[callback.send]'); - const stringifiedData = JSON.stringify({ - actions: [ - ...payload, - ], - sender: window.location.href, - type: sendType ?? defaultSendType, - }); - const encryptedMessage = AES.encrypt(stringifiedData, encryptionKey).toString(); - // build and go to url - const destinationUrl = new URL(url); - destinationUrl.searchParams.set('data', encodeURI(encryptedMessage)); - console.debug('[callback.send]', encryptedMessage, destinationUrl); - window.location.href = destinationUrl.toString(); - return; + try { + const stringifiedData = JSON.stringify({ + actions: [ + ...payload, + ], + sender: window.location.href, + type: sendType ?? defaultSendType, + }); + const encryptedMessage = AES.encrypt(stringifiedData, encryptionKey).toString(); + // build and go to url + const destinationUrl = new URL(url); + destinationUrl.searchParams.set('data', encodeURI(encryptedMessage)); + console.debug('[callback.send]', encryptedMessage, destinationUrl); + window.location.href = destinationUrl.toString(); + return; + } catch (error) { + console.error(error); + throw new Error("Unable to create callback event"); + } }; const watcher = () => { @@ -133,11 +138,16 @@ export const useCallbackStoreGeneric = ( return console.debug('[callback.watcher] no callback to handle'); } - const decryptedMessage = AES.decrypt(callbackValue, encryptionKey); - const decryptedData: QueryPayloads = JSON.parse(decryptedMessage.toString(Utf8)); - console.debug('[callback.watcher]', decryptedMessage, decryptedData); - // Parse the data and perform actions - callbackActions.redirectToCallbackType(decryptedData); + try { + const decryptedMessage = AES.decrypt(callbackValue, encryptionKey); + const decryptedData: QueryPayloads = JSON.parse(decryptedMessage.toString(Utf8)); + console.debug('[callback.watcher]', decryptedMessage, decryptedData); + // Parse the data and perform actions + callbackActions.redirectToCallbackType(decryptedData); + } catch (error) { + console.error(error); + throw new Error("Couldn't decrypt callback data"); + } }; return { diff --git a/store/callbackActions.ts b/store/callbackActions.ts index dabc76b6c..40e3c0604 100644 --- a/store/callbackActions.ts +++ b/store/callbackActions.ts @@ -4,15 +4,13 @@ import { addPreventClose, removePreventClose } from '~/composables/preventClose' import { useAccountStore } from '~/store/account'; import { useInstallKeyStore } from '~/store/installKey'; import { useCallbackStoreGeneric, type ExternalPayload, type ExternalKeyActions, type QueryPayloads } from '~/store/callback'; -import { remove } from '@vue/shared'; -// import { useServerStore } from './server'; export const useCallbackActionsStore = defineStore( 'callbackActions', () => { const accountStore = useAccountStore(); const installKeyStore = useInstallKeyStore(); - // const serverStore = useServerStore(); + type CallbackStatus = 'error' | 'loading' | 'ready' | 'success'; const callbackStatus = ref('ready'); diff --git a/store/errors.ts b/store/errors.ts index 3a4f64061..a5a77d7cc 100644 --- a/store/errors.ts +++ b/store/errors.ts @@ -1,8 +1,8 @@ import { defineStore, createPinia, setActivePinia } from 'pinia'; -// import { useAccountStore } from './account'; -// import { useCallbackStore } from './callbackActions'; -// import { useInstallKeyStore } from './installKey'; -// import { useServerStore } from './server'; +// import { useAccountStore } from '~/store/account'; +// import { useCallbackStore, useCallbackActionsStore } from '~/store/callbackActions'; +// import { useInstallKeyStore } from '~/store/installKey'; +// import { useServerStore } from '~/store/server'; /** * @see https://stackoverflow.com/questions/73476371/using-pinia-with-vue-js-web-components @@ -13,18 +13,29 @@ setActivePinia(createPinia()); export const useErrorsStore = defineStore('errors', () => { // const accountStore = useAccountStore(); // const callbackStore = useCallbackStore(); + // const callbackActionsStore = useCallbackActionsStore(); // const installKeyStore = useInstallKeyStore(); // const serverStore = useServerStore(); /** @todo type the errors */ const errors = ref([]); + const removeError = (index: number) => { + errors.value = errors.value.filter((_error, i) => i !== index); + }; + + const resetErrors = () => { + errors.value = []; + }; + const setError = (error: any) => { errors.value.push(error); }; return { errors, + removeError, + resetErrors, setError, }; }); diff --git a/store/installKey.ts b/store/installKey.ts index e21723c41..2557c3df5 100644 --- a/store/installKey.ts +++ b/store/installKey.ts @@ -1,6 +1,7 @@ import { defineStore, createPinia, setActivePinia } from 'pinia'; import { delay } from 'wretch/middlewares'; import { WebguiInstallKey, WebguiUpdateDns } from '~/composables/services/webgui'; +import { useErrorsStore } from '~/store/errors'; import { useServerStore } from '~/store/server'; import type { ExternalKeyActions } from '~/store/callback'; /** @@ -10,6 +11,7 @@ import type { ExternalKeyActions } from '~/store/callback'; setActivePinia(createPinia()); export const useInstallKeyStore = defineStore('installKey', () => { + const errorsStore = useErrorsStore(); const serverStore = useServerStore(); const keyInstallStatus = ref<'failed' | 'installing' | 'ready' | 'success'>('ready'); @@ -55,6 +57,7 @@ export const useInstallKeyStore = defineStore('installKey', () => { } catch (error) { console.error('[install] WebguiInstallKey error', error); keyInstallStatus.value = 'failed'; + errorsStore.setError(error); } };