diff options
author | vnugent <public@vaughnnugent.com> | 2024-01-07 01:53:03 -0500 |
---|---|---|
committer | vnugent <public@vaughnnugent.com> | 2024-01-07 01:53:03 -0500 |
commit | e01aae6c30f18003ceae07c092cddeb488e8f472 (patch) | |
tree | d7dd1b9bd931d1b274243bfb34fb44885c94e395 /front-end/src | |
parent | ce77fe97522bc9c37ccc275efebb94e920c1f2ae (diff) |
package updates & social auth setup
Diffstat (limited to 'front-end/src')
-rw-r--r-- | front-end/src/App.vue | 10 | ||||
-rw-r--r-- | front-end/src/main.ts | 2 | ||||
-rw-r--r-- | front-end/src/store/socialMfaPlugin.ts | 80 | ||||
-rw-r--r-- | front-end/src/views/Login/components/Social.vue | 26 | ||||
-rw-r--r-- | front-end/src/views/Login/index.vue | 4 | ||||
-rw-r--r-- | front-end/src/views/Login/social/[type].vue | 3 |
6 files changed, 90 insertions, 35 deletions
diff --git a/front-end/src/App.vue b/front-end/src/App.vue index d6ac36f..2f29fde 100644 --- a/front-end/src/App.vue +++ b/front-end/src/App.vue @@ -3,7 +3,7 @@ <title>{{ metaTile }}</title> </head> <!-- Import environment component top level as the entrypoint --> - <Environment @logout="store.socialOauth.logout"> + <Environment @logout="logout"> <template #main> <router-view /> </template> @@ -15,6 +15,7 @@ import { computed } from 'vue'; import { useStore } from './store'; import { storeToRefs } from 'pinia'; import Environment from './bootstrap/Environment.vue'; +import { apiCall } from '@vnuge/vnlib.browser'; const store = useStore() const { siteTitle, pageTitle } = storeToRefs(store) @@ -22,6 +23,13 @@ const { siteTitle, pageTitle } = storeToRefs(store) //Compute meta title from the default site title and the page title const metaTile = computed(() => `${pageTitle.value} | ${siteTitle.value}`) +const logout = () => { + apiCall(async () => { + const { logout } = await store.socialOauth() + await logout() + }) +} + store.setSiteTitle('CMNext Admin') store.setPageTitle('Blog') diff --git a/front-end/src/main.ts b/front-end/src/main.ts index cda44fa..4d62df4 100644 --- a/front-end/src/main.ts +++ b/front-end/src/main.ts @@ -97,7 +97,7 @@ createVnApp({ //Enable mfa with totp settings plugin (optional pki config) .use(mfaSettingsPlugin('/account/mfa', '/account/pki')) //Setup social mfa plugin - .use(socialMfaPlugin) + .use(socialMfaPlugin()) //Setup blog state .use(cmnextAdminPlugin(router, 'https://cdn.ckeditor.com/ckeditor5/40.0.0/super-build/ckeditor.js', 15)) diff --git a/front-end/src/store/socialMfaPlugin.ts b/front-end/src/store/socialMfaPlugin.ts index d328399..b9bce27 100644 --- a/front-end/src/store/socialMfaPlugin.ts +++ b/front-end/src/store/socialMfaPlugin.ts @@ -1,42 +1,70 @@ - import 'pinia' -import { } from 'vue'; -import { useSocialOauthLogin, createSocialMethod, useUser } from '@vnuge/vnlib.browser' -import { } from '@vueuse/core'; +import { MaybeRef } from 'vue'; +import { useSocialOauthLogin, useUser, SocialOAuthPortal, fromPortals, useAxios } from '@vnuge/vnlib.browser' +import { get } from '@vueuse/core'; import { PiniaPluginContext, PiniaPlugin, storeToRefs } from 'pinia' -import { } from 'lodash-es'; +import { defer } from 'lodash-es'; + +type SocialMfaPlugin = ReturnType<typeof useSocialOauthLogin> declare module 'pinia' { export interface PiniaCustomProperties { - socialOauth: ReturnType<typeof useSocialOauthLogin> + socialOauth(): Promise<SocialMfaPlugin> } } -export const socialMfaPlugin: PiniaPlugin = ({ store }: PiniaPluginContext) => { - - const { } = storeToRefs(store) - const { logout } = useUser() +export const socialMfaPlugin = (portalEndpoint?: MaybeRef<string>): PiniaPlugin => { - //Setup social providers - const socialOauth = useSocialOauthLogin([ - //createSocialMethod('github', '/login/social/github'), - //createSocialMethod('discord', '/login/social/discord'), - ]) + return ({ store }: PiniaPluginContext) => { - /** - * Override the logout function to default to a social logout, - * if the social logout fails, then we will logout the user - */ + const { } = storeToRefs(store) + const { logout } = useUser() - const logoutFunc = socialOauth.logout; + /** + * Override the logout function to default to a social logout, + * if the social logout fails, then we will logout the user + */ + const setLogoutMethod = (socialOauth: SocialMfaPlugin) => { + const logoutFunc = socialOauth.logout; - (socialOauth as any).logout = async () => { - if (await logoutFunc() === false) { - await logout() + (socialOauth as any).logout = async () => { + if (await logoutFunc() === false) { + await logout() + } + } } - } - return { - socialOauth + const _loadPromise = new Promise<SocialMfaPlugin>((resolve, reject) => { + + if(get(portalEndpoint) == null) { + const socialOauth = useSocialOauthLogin([]) + setLogoutMethod(socialOauth) + return resolve(socialOauth) + } + + defer(async () => { + try { + //Get axios instance + const axios = useAxios(null) + + //Get all enabled portals + const { data } = await axios.get<SocialOAuthPortal[]>(get(portalEndpoint)); + //Setup social providers from server portals + const socialOauth = useSocialOauthLogin(fromPortals(data)); + setLogoutMethod(socialOauth); + + resolve(socialOauth) + + } catch (error) { + reject(error) + } + }) + }) + + const socialOauth = () => _loadPromise + + return { + socialOauth, + } } }
\ No newline at end of file diff --git a/front-end/src/views/Login/components/Social.vue b/front-end/src/views/Login/components/Social.vue index 2cea930..4d22074 100644 --- a/front-end/src/views/Login/components/Social.vue +++ b/front-end/src/views/Login/components/Social.vue @@ -1,22 +1,21 @@ <template> - <div class="flex flex-col gap-3"> - <div v-for="method in store.socialOauth.methods" :key="method.Id" class=""> + <div v-for="method in methods" :key="method.Id" class=""> <button type="submit" class="btn social-button" :disabled="waiting" @click.prevent="submitLogin(method)" > - <fa-icon :icon="['fab', method.Id]" size="xl" /> + <fa-icon :icon="getIcon(method)" size="xl" /> Login with {{ capitalize(method.Id) }} </button> </div> </div> - </template> <script setup lang="ts"> +import { shallowRef } from 'vue' import { apiCall, useWait, type OAuthMethod } from '@vnuge/vnlib.browser' import { capitalize } from 'lodash-es'; import { useStore } from '../../../store'; @@ -24,7 +23,24 @@ import { useStore } from '../../../store'; const { waiting } = useWait() const store = useStore() +const methods = shallowRef<OAuthMethod[]>([]) + //Invoke login wrapped in api call -const submitLogin = (method: OAuthMethod) => apiCall(() => store.socialOauth.beginLoginFlow(method)) +const submitLogin = (method: OAuthMethod) => apiCall(async () => { + const { beginLoginFlow } = await store.socialOauth(); + await beginLoginFlow(method) +}) + +const getIcon = (method: OAuthMethod): string[] => { + switch (method.Id) { + case 'auth0': + return ['fa', 'certificate'] + default: + return ['fab', method.Id] + } +} + +//Load methods once the fetch completes +store.socialOauth().then(m => methods.value = m.methods); </script>
\ No newline at end of file diff --git a/front-end/src/views/Login/index.vue b/front-end/src/views/Login/index.vue index 5d8f298..6a55aeb 100644 --- a/front-end/src/views/Login/index.vue +++ b/front-end/src/views/Login/index.vue @@ -62,7 +62,9 @@ const submitLogout = async () => { //Submit logout request await apiCall(async ({ toaster }) => { // Attempt to logout - await store.socialOauth.logout() + const { logout } = await store.socialOauth() + await logout() + // Push a new toast message toaster.general.success({ id: 'logout-success', diff --git a/front-end/src/views/Login/social/[type].vue b/front-end/src/views/Login/social/[type].vue index 68e8b77..51da94f 100644 --- a/front-end/src/views/Login/social/[type].vue +++ b/front-end/src/views/Login/social/[type].vue @@ -64,7 +64,8 @@ tryOnMounted(() => defer(() => { apiCall(async ({ toaster }) => { try{ //Complete the login - await store.socialOauth.completeLogin(); + const { completeLogin } = await store.socialOauth(); + await completeLogin() toaster.general.success({ title:'Login Successful', |