mirror of
https://github.com/unraid/api.git
synced 2026-01-15 21:19:53 -06:00
feat: install key and account config webgui requests
This commit is contained in:
@@ -51,7 +51,7 @@ const ariaLablledById = computed((): string|undefined => props.title ? `ModalTit
|
||||
title="Click to close modal"
|
||||
/>
|
||||
</TransitionChild>
|
||||
<div class="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
|
||||
<div class="text-center flex min-h-full items-center justify-center p-4 md:p-0">
|
||||
<TransitionChild
|
||||
appear
|
||||
as="template"
|
||||
|
||||
@@ -3,6 +3,7 @@ import { storeToRefs } from 'pinia';
|
||||
import 'tailwindcss/tailwind.css';
|
||||
import '~/assets/main.css';
|
||||
import { useCallbackStore } from '~/store/callback';
|
||||
import { useInstallKeyStore } from '~/store/installKey';
|
||||
|
||||
export interface Props {
|
||||
open?: boolean;
|
||||
@@ -13,28 +14,33 @@ withDefaults(defineProps<Props>(), {
|
||||
});
|
||||
|
||||
const callbackStore = useCallbackStore();
|
||||
const { decryptedData } = storeToRefs(callbackStore);
|
||||
const { callbackLoading, decryptedData } = storeToRefs(callbackStore);
|
||||
|
||||
const close = () => {
|
||||
if (callbackLoading.value) return console.debug('[close] not allowed');
|
||||
callbackStore.hide();
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal
|
||||
:open="open"
|
||||
@close="callbackStore.hide()"
|
||||
@close="close"
|
||||
max-width="max-w-800px"
|
||||
:show-close-x="!callbackLoading"
|
||||
>
|
||||
<div class="text-center relative w-full flex flex-col gap-y-16px">
|
||||
<header>
|
||||
<h1 class="text-24px font-semibold flex flex-wrap justify-center gap-x-1">Callback Feedback</h1>
|
||||
</header>
|
||||
|
||||
<BrandLoading class="w-90px mx-auto" />
|
||||
<BrandLoading v-if="callbackLoading" class="w-90px mx-auto" />
|
||||
<pre class="text-left text-black p-8px w-full overflow-scroll bg-gray-400">{{ JSON.stringify(decryptedData, null, 2) }}</pre>
|
||||
|
||||
<div class="w-full max-w-xs flex flex-col gap-y-16px mx-auto">
|
||||
<div v-if="!callbackLoading" class="w-full max-w-xs flex flex-col gap-y-16px mx-auto">
|
||||
<button
|
||||
@click="callbackStore.hide()"
|
||||
@click="close"
|
||||
class="text-12px tracking-wide inline-block mx-8px opacity-60 hover:opacity-100 focus:opacity-100 underline transition"
|
||||
:title="'Close Promo'"
|
||||
>
|
||||
{{ 'Close' }}
|
||||
</button>
|
||||
|
||||
@@ -68,14 +68,14 @@ const installButtonClasses = 'text-white text-14px text-center w-full flex flex-
|
||||
:show-close-x="true"
|
||||
max-width="max-w-800px"
|
||||
>
|
||||
<div class="text-center relative w-full p-24px">
|
||||
<div class="text-center relative w-full md:p-24px">
|
||||
<header>
|
||||
<h1 class="text-24px font-semibold flex flex-wrap justify-center gap-x-1">
|
||||
Introducing Unraid Connect
|
||||
<span><UpcBeta class="relative -top-1" /></span>
|
||||
</h1>
|
||||
<h2 class="text-20px">
|
||||
Enhance your Unraid experience with these features
|
||||
Enhance your Unraid experience
|
||||
</h2>
|
||||
</header>
|
||||
|
||||
|
||||
25
composables/services/request.ts
Normal file
25
composables/services/request.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import wretch from 'wretch';
|
||||
import FormUrlAddon from 'wretch/addons/formUrl';
|
||||
import QueryStringAddon from 'wretch/addons/queryString';
|
||||
|
||||
import { useErrorsStore } from '~/store/errors';
|
||||
|
||||
const errorsStore = useErrorsStore();
|
||||
|
||||
export const request = wretch()
|
||||
.addon(FormUrlAddon)
|
||||
.addon(QueryStringAddon)
|
||||
.errorType('json')
|
||||
.resolve((response) => {
|
||||
return (
|
||||
response
|
||||
.error("Error", (error) => {
|
||||
console.log('global catch (Error class)', error);
|
||||
errorsStore.setError(error);
|
||||
})
|
||||
.error("TypeError", (error) => {
|
||||
console.log('global type error catch (TypeError class)', error);
|
||||
errorsStore.setError(error);
|
||||
})
|
||||
);
|
||||
});
|
||||
36
composables/services/webgui.ts
Normal file
36
composables/services/webgui.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { request } from '~/composables/services/request';
|
||||
/**
|
||||
* @name WebguiInstallKey
|
||||
* @description used to auto install key urls
|
||||
* @type GET - data should be passed using wretch's `.query({ url: String })`
|
||||
* @param {string} url - URL of license key
|
||||
*/
|
||||
export const WebguiInstallKey = request.url('/webGui/include/InstallKey.php');
|
||||
/**
|
||||
* @type POST
|
||||
* @dataType - `formUrl(Object)` https://github.com/elbywan/wretch#formurlinput-object--string
|
||||
* @param {string} csrf_token
|
||||
* @param {string} '#file' - ex: getters.myServersCfgPath
|
||||
* @param {string} '#section' - ex: 'remote'
|
||||
* @param {string} apikey
|
||||
* @param {string} avatar
|
||||
* @param {string} email
|
||||
* @param {string} username
|
||||
*/
|
||||
export const WebguiUpdate = request.url('/update.php');
|
||||
/**
|
||||
* @name WebguiUpdateDns
|
||||
* @dataForm formUrl
|
||||
* @description Used after Sign In to ensure URLs will work correctly
|
||||
* @note this request is delayed by 500ms to allow server to process key install fully
|
||||
* @todo potentially remove delay
|
||||
* @param csrf_token
|
||||
* @type POST
|
||||
*/
|
||||
export const WebguiUpdateDns = request.url('/webGui/include/UpdateDNS.php');
|
||||
/**
|
||||
* @name WebguiUpdateDns
|
||||
* @description used after Sign In to ensure URLs will work correctly
|
||||
* @type POST
|
||||
*/
|
||||
export const WebguiUnraidApiCommand = request.url('/plugins/dynamix.my.servers/include/unraid-api.php');
|
||||
8562
package-lock.json
generated
8562
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,7 @@
|
||||
"@types/node": "^18",
|
||||
"@vueuse/core": "^10.1.2",
|
||||
"@vueuse/nuxt": "^10.1.2",
|
||||
"amazon-cognito-identity-js": "^6.2.0",
|
||||
"nuxt": "^3.5.1",
|
||||
"nuxt-custom-elements": "^2.0.0-beta.12"
|
||||
},
|
||||
@@ -29,7 +30,8 @@
|
||||
"crypto-js": "^4.1.1",
|
||||
"dayjs": "^1.11.7",
|
||||
"focus-trap": "^7.4.3",
|
||||
"hex-to-rgba": "^2.0.1"
|
||||
"hex-to-rgba": "^2.0.1",
|
||||
"wretch": "^2.5.2"
|
||||
},
|
||||
"overrides": {
|
||||
"vue": "latest"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useToggle } from '@vueuse/core';
|
||||
import { defineStore, createPinia, setActivePinia } from "pinia";
|
||||
import { defineStore, createPinia, setActivePinia } from 'pinia';
|
||||
import { useCallbackStore } from './callback';
|
||||
import { useServerStore } from './server';
|
||||
|
||||
import { WebguiUpdate } from '~/composables/services/webgui';
|
||||
import type { CallbackAction } from '~/types/callback';
|
||||
/**
|
||||
* @see https://stackoverflow.com/questions/73476371/using-pinia-with-vue-js-web-components
|
||||
* @see https://github.com/vuejs/pinia/discussions/1085
|
||||
@@ -13,7 +13,8 @@ export const useAccountStore = defineStore('account', () => {
|
||||
const callbackStore = useCallbackStore();
|
||||
const serverStore = useServerStore();
|
||||
// State
|
||||
const accountVisible = ref<boolean>(false);
|
||||
const updating = ref(false);
|
||||
const updateSuccess = ref<boolean|undefined>(undefined);
|
||||
// Actions
|
||||
const recover = () => {
|
||||
console.debug('[recover]');
|
||||
@@ -43,24 +44,63 @@ export const useAccountStore = defineStore('account', () => {
|
||||
type: 'signOut',
|
||||
});
|
||||
};
|
||||
const accountHide = () => accountVisible.value = false;
|
||||
const accountShow = () => accountVisible.value = true;
|
||||
const accountToggle = useToggle(accountVisible);
|
||||
|
||||
watch(accountVisible, (newVal, _oldVal) => {
|
||||
console.debug('[accountVisible]', newVal, _oldVal);
|
||||
});
|
||||
/**
|
||||
* @description Update myservers.cfg for both Sign In & Sign Out
|
||||
* @note unraid-api requires apikey & token realted keys to be lowercase
|
||||
*/
|
||||
const updatePluginConfig = async (action: CallbackAction) => {
|
||||
console.debug('[updatePluginConfig]', action);
|
||||
updating.value = true;
|
||||
const userPayload = {
|
||||
...(action.user
|
||||
? {
|
||||
accesstoken: action.user.signInUserSession.accessToken.jwtToken,
|
||||
apikey: serverStore.apiKey,
|
||||
// avatar: action.user?.attributes.avatar,
|
||||
email: action.user?.attributes.email,
|
||||
idtoken: action.user.signInUserSession.idToken.jwtToken,
|
||||
refreshtoken: action.user.signInUserSession.refreshToken.token,
|
||||
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: action.user?.attributes.preferred_username,
|
||||
}
|
||||
: {
|
||||
accesstoken: '',
|
||||
apikey: '',
|
||||
avatar: '',
|
||||
email: '',
|
||||
idtoken: '',
|
||||
refreshtoken: '',
|
||||
username: '',
|
||||
}),
|
||||
};
|
||||
try {
|
||||
const response = await WebguiUpdate
|
||||
.formUrl({
|
||||
csrf_token: serverStore.csrf,
|
||||
'#file': 'dynamix.my.servers/myservers.cfg',
|
||||
'#section': 'remote',
|
||||
...userPayload,
|
||||
})
|
||||
.post();
|
||||
console.debug('[updatePluginConfig] WebguiUpdate response', response);
|
||||
updateSuccess.value = true;
|
||||
} catch (error) {
|
||||
console.debug('[updatePluginConfig] WebguiUpdate error', error);
|
||||
updateSuccess.value = false;
|
||||
} finally {
|
||||
updating.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
// State
|
||||
accountVisible,
|
||||
accountHide,
|
||||
accountShow,
|
||||
updating,
|
||||
updateSuccess,
|
||||
// Actions
|
||||
recover,
|
||||
replace,
|
||||
signIn,
|
||||
signOut,
|
||||
accountToggle,
|
||||
updatePluginConfig,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import AES from 'crypto-js/aes';
|
||||
import Utf8 from 'crypto-js/enc-utf8';
|
||||
import { defineStore, createPinia, setActivePinia } from "pinia";
|
||||
import type { CallbackSendPayload } from '~/types/callback';
|
||||
import { defineStore, createPinia, setActivePinia } from 'pinia';
|
||||
import { useAccountStore } from './account';
|
||||
import { useInstallKeyStore } from './installKey';
|
||||
import type { CallbackSendPayload, CallbackReceivePayload } from '~/types/callback';
|
||||
import type {
|
||||
ServerAccountCallbackSendPayload,
|
||||
ServerPurchaseCallbackSendPayload,
|
||||
@@ -14,14 +16,16 @@ setActivePinia(createPinia());
|
||||
|
||||
export const useCallbackStore = defineStore('callback', () => {
|
||||
// store helpers
|
||||
const accountStore = useAccountStore();
|
||||
const installKeyStore = useInstallKeyStore();
|
||||
// const config = useRuntimeConfig(); // results in a nuxt error after web components are built
|
||||
// const encryptKey = config.public.callbackKey;
|
||||
const encryptKey = 'Uyv2o8e*FiQe8VeLekTqyX6Z*8XonB';
|
||||
// state
|
||||
const currentUrl = ref();
|
||||
const callbackFeedbackVisible = ref<boolean>(false);
|
||||
const decryptedData = ref();
|
||||
const encryptedMessage = ref('');
|
||||
const callbackLoading = ref(false);
|
||||
const decryptedData = ref<CallbackReceivePayload|null>(null);
|
||||
const encryptedMessage = ref<string|null>(null);
|
||||
// actions
|
||||
const send = (url: string = 'https://unraid.ddev.site/init-purchase', payload: CallbackSendPayload) => {
|
||||
console.debug('[send]');
|
||||
@@ -45,25 +49,39 @@ export const useCallbackStore = defineStore('callback', () => {
|
||||
if (!callbackValue) {
|
||||
return console.debug('[watcher] no callback to handle');
|
||||
}
|
||||
callbackLoading.value = true;
|
||||
const decryptedMessage = AES.decrypt(callbackValue, encryptKey);
|
||||
decryptedData.value = JSON.parse(decryptedMessage.toString(Utf8));
|
||||
console.debug('[watcher]', decryptedMessage, decryptedData.value);
|
||||
if (!decryptedData.value) return console.error('Callback Watcher: Data not present');
|
||||
if (!decryptedData.value.action) return console.error('Callback Watcher: Required "action" not present');
|
||||
if (!decryptedData.value) {
|
||||
callbackLoading.value = false;
|
||||
return console.error('Callback Watcher: Data not present');
|
||||
}
|
||||
if (!decryptedData.value.actions) {
|
||||
callbackLoading.value = false;
|
||||
return console.error('Callback Watcher: Required "action" not present');
|
||||
}
|
||||
// Display the feedback modal
|
||||
show();
|
||||
// Parse the data and perform actions
|
||||
switch (decryptedData.value.action) {
|
||||
case 'install':
|
||||
console.debug(`Installing key ${decryptedData.value.keyUrl}\n\nOEM: ${decryptedData.value.oem}\n\nSender: ${decryptedData.value.sender}`);
|
||||
break;
|
||||
case 'register':
|
||||
console.debug('[Register action]');
|
||||
break;
|
||||
default:
|
||||
console.error('Callback Watcher: Invalid "action"');
|
||||
break;
|
||||
}
|
||||
decryptedData.value.actions.forEach(async (action, index, array) => {
|
||||
console.debug('[action]', action);
|
||||
if (action.keyUrl) {
|
||||
const response = await installKeyStore.install(action);
|
||||
console.debug('[action] installKeyStore.install response', response);
|
||||
}
|
||||
if (action.user) {
|
||||
const response = await accountStore.updatePluginConfig(action);
|
||||
console.debug('[action] accountStore.updatePluginConfig', response);
|
||||
}
|
||||
// all actions have run
|
||||
if (array.length === (index + 1)) {
|
||||
console.debug('[actions] DONE');
|
||||
setTimeout(() => {
|
||||
callbackLoading.value = false;
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const hide = () => {
|
||||
@@ -87,8 +105,9 @@ export const useCallbackStore = defineStore('callback', () => {
|
||||
|
||||
return {
|
||||
// state
|
||||
decryptedData,
|
||||
callbackFeedbackVisible,
|
||||
callbackLoading,
|
||||
decryptedData,
|
||||
// actions
|
||||
send,
|
||||
watcher,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useToggle } from '@vueuse/core';
|
||||
import { defineStore, createPinia, setActivePinia } from "pinia";
|
||||
import { defineStore, createPinia, setActivePinia } from 'pinia';
|
||||
/**
|
||||
* @see https://stackoverflow.com/questions/73476371/using-pinia-with-vue-js-web-components
|
||||
* @see https://github.com/vuejs/pinia/discussions/1085
|
||||
|
||||
30
store/errors.ts
Normal file
30
store/errors.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { defineStore, createPinia, setActivePinia } from 'pinia';
|
||||
// import { useAccountStore } from './account';
|
||||
// import { useCallbackStore } from './callback';
|
||||
// import { useInstallKeyStore } from './installKey';
|
||||
// import { useServerStore } from './server';
|
||||
|
||||
/**
|
||||
* @see https://stackoverflow.com/questions/73476371/using-pinia-with-vue-js-web-components
|
||||
* @see https://github.com/vuejs/pinia/discussions/1085
|
||||
*/
|
||||
setActivePinia(createPinia());
|
||||
|
||||
export const useErrorsStore = defineStore('errors', () => {
|
||||
// const accountStore = useAccountStore();
|
||||
// const callbackStore = useCallbackStore();
|
||||
// const installKeyStore = useInstallKeyStore();
|
||||
// const serverStore = useServerStore();
|
||||
|
||||
/** @todo type the errors */
|
||||
const errors = ref<any[]>([]);
|
||||
|
||||
const setError = (error: any) => {
|
||||
errors.value.push(error);
|
||||
};
|
||||
|
||||
return {
|
||||
errors,
|
||||
setError,
|
||||
};
|
||||
});
|
||||
53
store/installKey.ts
Normal file
53
store/installKey.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { defineStore, createPinia, setActivePinia } from 'pinia';
|
||||
import { delay } from 'wretch/middlewares';
|
||||
import { WebguiInstallKey, WebguiUpdateDns } from '~/composables/services/webgui';
|
||||
import { useServerStore } from './server';
|
||||
import type { CallbackAction } from '~/types/callback';
|
||||
/**
|
||||
* @see https://stackoverflow.com/questions/73476371/using-pinia-with-vue-js-web-components
|
||||
* @see https://github.com/vuejs/pinia/discussions/1085
|
||||
*/
|
||||
setActivePinia(createPinia());
|
||||
|
||||
export const useInstallKeyStore = defineStore('installKey', () => {
|
||||
const serverStore = useServerStore();
|
||||
|
||||
const installing = ref(false);
|
||||
const success = ref<boolean|undefined>();
|
||||
|
||||
const install = async (action: CallbackAction) => {
|
||||
console.debug('[install]');
|
||||
installing.value = true;
|
||||
try {
|
||||
const response = await WebguiInstallKey
|
||||
.query({ url: action.keyUrl })
|
||||
.get();
|
||||
console.log('[install] WebguiInstallKey response', response);
|
||||
success.value = true;
|
||||
try {
|
||||
const response = await WebguiUpdateDns
|
||||
.middlewares([
|
||||
delay(500)
|
||||
])
|
||||
.formUrl({ csrf_token: serverStore.csrf })
|
||||
.post();
|
||||
console.log('[install] WebguiUpdateDns response', response);
|
||||
} catch (error) {
|
||||
console.log('[install] WebguiUpdateDns error', error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('[install] WebguiInstallKey error', error);
|
||||
success.value = false;
|
||||
} finally {
|
||||
installing.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
// State
|
||||
installing,
|
||||
success,
|
||||
// Actions
|
||||
install,
|
||||
};
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useToggle } from '@vueuse/core';
|
||||
import { defineStore, createPinia, setActivePinia } from "pinia";
|
||||
import { defineStore, createPinia, setActivePinia } from 'pinia';
|
||||
|
||||
/**
|
||||
* @see https://stackoverflow.com/questions/73476371/using-pinia-with-vue-js-web-components
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useToggle } from '@vueuse/core';
|
||||
import { defineStore, createPinia, setActivePinia } from "pinia";
|
||||
import { defineStore, createPinia, setActivePinia } from 'pinia';
|
||||
|
||||
/**
|
||||
* @see https://stackoverflow.com/questions/73476371/using-pinia-with-vue-js-web-components
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useToggle } from '@vueuse/core';
|
||||
import { defineStore, createPinia, setActivePinia } from "pinia";
|
||||
import { defineStore, createPinia, setActivePinia } from 'pinia';
|
||||
import { useCallbackStore } from './callback';
|
||||
import { useServerStore } from './server';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineStore, createPinia, setActivePinia } from "pinia";
|
||||
import { defineStore, createPinia, setActivePinia } from 'pinia';
|
||||
import { ArrowRightOnRectangleIcon, GlobeAltIcon, KeyIcon } from '@heroicons/vue/24/solid';
|
||||
|
||||
import { useAccountStore } from './account';
|
||||
@@ -30,6 +30,7 @@ export const useServerStore = defineStore('server', () => {
|
||||
*/
|
||||
const avatar = ref<string>(''); // @todo potentially move to a user store
|
||||
const apiKey = ref<string>(''); // @todo potentially move to a user store
|
||||
const csrf = ref<string>(''); // required to make requests to Unraid webgui
|
||||
const description = ref<string>('');
|
||||
const deviceCount = ref<number>(0);
|
||||
const expireTime = ref<number>(0);
|
||||
@@ -397,6 +398,7 @@ export const useServerStore = defineStore('server', () => {
|
||||
console.debug('[setServer] data', data);
|
||||
if (typeof data?.apiKey !== 'undefined') apiKey.value = data.apiKey;
|
||||
if (typeof data?.avatar !== 'undefined') avatar.value = data.avatar;
|
||||
if (typeof data?.csrf !== 'undefined') csrf.value = data.csrf;
|
||||
if (typeof data?.description !== 'undefined') description.value = data.description;
|
||||
if (typeof data?.deviceCount !== 'undefined') deviceCount.value = data.deviceCount;
|
||||
if (typeof data?.expireTime !== 'undefined') expireTime.value = data.expireTime;
|
||||
@@ -429,6 +431,7 @@ export const useServerStore = defineStore('server', () => {
|
||||
// state
|
||||
apiKey,
|
||||
avatar,
|
||||
csrf,
|
||||
description,
|
||||
deviceCount,
|
||||
expireTime,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineStore, createPinia, setActivePinia } from "pinia";
|
||||
import { defineStore, createPinia, setActivePinia } from 'pinia';
|
||||
import hexToRgba from 'hex-to-rgba';
|
||||
import type { Theme } from "~/types/theme";
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useToggle } from '@vueuse/core';
|
||||
import { defineStore, createPinia, setActivePinia } from "pinia";
|
||||
import { defineStore, createPinia, setActivePinia } from 'pinia';
|
||||
import { useCallbackStore } from './callback';
|
||||
import { useServerStore } from './server';
|
||||
|
||||
|
||||
@@ -1,9 +1,50 @@
|
||||
import type { CognitoUser, ChallengeName } from 'amazon-cognito-identity-js';
|
||||
import type {
|
||||
ServerAccountCallbackSendPayload,
|
||||
ServerPurchaseCallbackSendPayload,
|
||||
ServerStateDataActionType,
|
||||
} from '~/types/server';
|
||||
|
||||
/**
|
||||
* These user interfaces are mimiced from the Auth repo
|
||||
*/
|
||||
export interface UserInfo {
|
||||
'custom:ips_id'?: string;
|
||||
email?: string;
|
||||
email_verifed?: 'true' | 'false';
|
||||
preferred_username?: string;
|
||||
sub?: string;
|
||||
username?: string;
|
||||
}
|
||||
|
||||
export interface AuthUser extends CognitoUser {
|
||||
attributes: UserInfo;
|
||||
username?: string;
|
||||
preferredMFA: ChallengeName;
|
||||
signInUserSession: {
|
||||
accessToken: {
|
||||
jwtToken: string;
|
||||
};
|
||||
idToken: {
|
||||
jwtToken: string;
|
||||
};
|
||||
refreshToken: {
|
||||
token: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface CallbackSendPayload extends ServerAccountCallbackSendPayload, ServerPurchaseCallbackSendPayload {
|
||||
type: ServerStateDataActionType;
|
||||
}
|
||||
|
||||
export interface CallbackAction {
|
||||
keyUrl?: string;
|
||||
type: ServerStateDataActionType;
|
||||
user?: AuthUser;
|
||||
}
|
||||
|
||||
export interface CallbackReceivePayload {
|
||||
actions: CallbackAction[];
|
||||
sender: string;
|
||||
}
|
||||
@@ -23,6 +23,7 @@ export enum ServerState {
|
||||
export interface Server {
|
||||
apiKey?: string;
|
||||
avatar?: string;
|
||||
csrf?: string;
|
||||
description?: string;
|
||||
deviceCount?: number;
|
||||
expireTime?: number;
|
||||
|
||||
Reference in New Issue
Block a user