diff options
author | vnugent <public@vaughnnugent.com> | 2024-06-07 15:45:56 -0400 |
---|---|---|
committer | vnugent <public@vaughnnugent.com> | 2024-06-07 15:45:56 -0400 |
commit | f77ff50150e6ff5d1f2b03c4f465846d5bb49a96 (patch) | |
tree | 1096bba241834211a25f7895db21e1a8d581ea17 /front-end/src/views/Login | |
parent | f9e2109c27af5ece546261c018d4b2781860ff1c (diff) |
Squashed commit of the following:v0.1.5-alpha
commit 8ed4663e539d9c2ea58aaad02a1fc2896956f6b6
Author: vnugent <public@vaughnnugent.com>
Date: Fri Jun 7 15:43:48 2024 -0400
fix: invalid chars in status cookie name
commit 9d1df65d99732a68b4fe96dcc75273442cbd322f
Author: vnugent <public@vaughnnugent.com>
Date: Thu Jun 6 21:31:30 2024 -0400
fix: Some container fixes and compatability
commit 5ecd6b39cccdc9500540b10685605b5fcba61f69
Author: vnugent <public@vaughnnugent.com>
Date: Thu Jun 6 17:19:48 2024 -0400
Update and expose storage config for container
commit 3a62bafd210a2e00d23d3df773e47011e09eba6e
Author: vnugent <public@vaughnnugent.com>
Date: Thu Jun 6 16:18:36 2024 -0400
ci: build admin lib before building front-end
commit 35920ad6c8596fc14bcfed66303511e8c249be8d
Author: vnugent <public@vaughnnugent.com>
Date: Thu Jun 6 15:56:36 2024 -0400
ci: Local vite config, force set lib versions
commit 3c228b3cc5172fae398af8de72b64bd780ace20c
Author: vnugent <public@vaughnnugent.com>
Date: Wed Jun 5 19:55:39 2024 -0400
ci: Update packages and add container build
commit 21d2719701f851d4a555c363b141f289f14a5192
Author: vnugent <public@vaughnnugent.com>
Date: Wed Jun 5 15:58:07 2024 -0400
fix: #1 new channel page when hitting new button
commit eefba88ac4e2c70517aa71c79ed94c346f9de554
Author: vnugent <public@vaughnnugent.com>
Date: Wed Jun 5 15:26:15 2024 -0400
chore: Package updates
commit 9eed4022a79f2cba139c9f8a359bfc8c1f9c31c5
Author: vnugent <public@vaughnnugent.com>
Date: Wed Jun 5 14:44:08 2024 -0400
ci: Stage blocking changes
Diffstat (limited to 'front-end/src/views/Login')
-rw-r--r-- | front-end/src/views/Login/components/Social.vue | 52 | ||||
-rw-r--r-- | front-end/src/views/Login/components/UserPass.vue | 123 | ||||
-rw-r--r-- | front-end/src/views/Login/index.vue | 30 |
3 files changed, 103 insertions, 102 deletions
diff --git a/front-end/src/views/Login/components/Social.vue b/front-end/src/views/Login/components/Social.vue index 3c93d0e..2087524 100644 --- a/front-end/src/views/Login/components/Social.vue +++ b/front-end/src/views/Login/components/Social.vue @@ -1,13 +1,29 @@ <script setup lang="ts"> -import { shallowRef } from 'vue' import { apiCall, useWait, type OAuthMethod } from '@vnuge/vnlib.browser' -import { capitalize } from 'lodash-es'; +import { capitalize, map } from 'lodash-es'; import { useStore } from '../../../store'; +import { useAsyncState } from '@vueuse/core'; +import { shallowRef } from 'vue'; +import { Mutable } from '@vueuse/core'; const { waiting } = useWait() const store = useStore() +const buttonCont = shallowRef<HTMLDivElement | null>(null) + +const filterSvgIcon = (oauth: OAuthMethod[]) => { + return map(oauth, (method: Mutable<OAuthMethod>) => { + //parse the base64 icon as an svg + if (method.icon) { + return{ + ...method, + icon: atob(method.icon).replace(/(width|height)="[^"]*"/g, '') + } + } + return method; + }) +} -const methods = shallowRef<OAuthMethod[]>([]) +const { state: methods, isReady } = useAsyncState(store.socialOauth().then(p => filterSvgIcon(p.methods)), []); //Invoke login wrapped in api call const submitLogin = (method: OAuthMethod) => apiCall(async () => { @@ -15,34 +31,24 @@ const submitLogin = (method: OAuthMethod) => apiCall(async () => { 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> <template> - <div class="flex flex-col gap-3"> + <div ref="buttonCont" v-if="isReady" class="flex flex-col gap-3"> <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="getIcon(method)" size="xl" /> + <button type="submit" class="btn social-button" :disabled="waiting" @click.prevent="submitLogin(method)"> + + <div v-html="method.icon" class="w-6 h-6" > + </div> + Login with {{ capitalize(method.id) }} </button> </div> </div> + <div v-else class="my-8"> + <fa-icon icon="spinner" size="2xl" spin /> + </div> + </template> diff --git a/front-end/src/views/Login/components/UserPass.vue b/front-end/src/views/Login/components/UserPass.vue index bc9d8d1..16c8aab 100644 --- a/front-end/src/views/Login/components/UserPass.vue +++ b/front-end/src/views/Login/components/UserPass.vue @@ -1,67 +1,13 @@ -<template> - <div class=""> - <h3>Login</h3> - <div v-if="mfaUpgrade?.type === MfaMethod.TOTP"> - <Totp @clear="totpClear" :upgrade="mfaUpgrade" /> - </div> - - <form v-else id="user-pass-submit-form" method="post" action="/login" @submit.prevent="SubmitLogin"> - <fieldset class="" :disabled="waiting" > - <div> - <div class="float-label"> - <input - id="username" - v-model="v$.username.$model" - type="email" - class="w-full primary input" - placeholder="Email" - :class="{ 'data-invalid': v$.username.$invalid }" - @input="onInput" - > - <label for="username">Email</label> - </div> - </div> - <div class="py-3"> - <div class="mb-2 float-label"> - <input - id="password" - v-model="v$.password.$model" - type="password" - class="w-full primary input" - placeholder="Password" - :class="{ 'data-invalid': v$.password.$invalid }" - @input="onInput" - > - <label for="password">Password</label> - </div> - </div> - </fieldset> - <button type="submit" form="user-pass-submit-form" class="btn primary" :disabled="waiting"> - <!-- Display spinner if waiting, otherwise the sign-in icon --> - <fa-icon :class="{'animate-spin':waiting}" :icon="waiting ? 'spinner' : 'sign-in-alt'"/> - Log-in - </button> - <div class="flex flex-row justify-between gap-3 pt-3 pb-2 form-links"> - <router-link to="/pwreset"> - Forgot password - </router-link> - <router-link to="/register"> - Register a new account - </router-link> - </div> - </form> - </div> -</template> <script setup lang="ts"> import { ref, shallowRef, reactive, defineAsyncComponent, Ref } from 'vue' import { useTimeoutFn, set } from '@vueuse/core' import { useVuelidate } from '@vuelidate/core' -import { isEqual } from 'lodash-es' +import { isEmpty } from 'lodash-es' import { required, maxLength, minLength, email, helpers } from '@vuelidate/validators' import { - useVuelidateWrapper, useMfaLogin, totpMfaProcessor, IMfaFlowContinuiation, MfaMethod, + useVuelidateWrapper, useMfaLogin, totpMfaProcessor, IMfaFlowContinuiation, apiCall, useMessage, useWait, debugLog, WebMessage, type VuelidateInstance } from '@vnuge/vnlib.browser' @@ -126,12 +72,21 @@ const SubmitLogin = async () => { //Try to get response as a flow continuation const mfa = response as IMfaFlowContinuiation - // Response is a totp upgrade request - if (isEqual(mfa.type, MfaMethod.TOTP)) { - //Store the upgrade message + // Response is an mfa upgrade + if (!isEmpty(mfa.type)) { + + /** + * If mfa has a type assicated, then we should have a handler matched + * with it to continue the flow + * + * All mfa upgrades will have a token expiration, and an assoicated + * type string name (string) + */ + set(mfaUpgrade, mfa); - //Setup timeout timer + set(mfaTimeout, mfa.expires! * 1000); + mfaTimer.start(); } //If login without mfa was successful @@ -145,11 +100,51 @@ const SubmitLogin = async () => { }) } -const totpClear = () => { - //Clear timer +const mfaClear = () => { mfaTimer.stop(); - //Clear upgrade message set(mfaUpgrade, undefined); } -</script>
\ No newline at end of file +</script> + +<template> + <div class=""> + <h3>Login</h3> + + <div v-if="mfaUpgrade?.type === 'totp'"> + <Totp @clear="mfaClear()" :upgrade="mfaUpgrade" /> + </div> + + <form v-else id="user-pass-submit-form" method="post" action="/login" @submit.prevent="SubmitLogin"> + <fieldset class="" :disabled="waiting"> + <div> + <div class="float-label"> + <input id="username" v-model="v$.username.$model" type="email" class="w-full primary input" + placeholder="Email" :class="{ 'data-invalid': v$.username.$invalid }" @input="onInput"> + <label for="username">Email</label> + </div> + </div> + <div class="py-3"> + <div class="mb-2 float-label"> + <input id="password" v-model="v$.password.$model" type="password" class="w-full primary input" + placeholder="Password" :class="{ 'data-invalid': v$.password.$invalid }" @input="onInput"> + <label for="password">Password</label> + </div> + </div> + </fieldset> + <button type="submit" form="user-pass-submit-form" class="btn primary" :disabled="waiting"> + <!-- Display spinner if waiting, otherwise the sign-in icon --> + <fa-icon :class="{ 'animate-spin': waiting }" :icon="waiting ? 'spinner' : 'sign-in-alt'" /> + Log-in + </button> + <div class="flex flex-row justify-between gap-3 pt-3 pb-2 form-links"> + <router-link to="/pwreset"> + Forgot password + </router-link> + <router-link to="/register"> + Register a new account + </router-link> + </div> + </form> + </div> +</template>
\ 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 476ebf4..8532390 100644 --- a/front-end/src/views/Login/index.vue +++ b/front-end/src/views/Login/index.vue @@ -38,7 +38,7 @@ const submitLogout = async () => { <div class="login-container"> <div v-if="!loggedIn"> - <UserPass/> + <UserPass /> </div> <div v-else> @@ -46,13 +46,13 @@ const submitLogout = async () => { <p class="mt-3 mb-5 text-lg"> You are currently logged-in. </p> - <div class=""> - <button form="user-pass-submit-form" class="btn primary" @click="submitLogout" :disabled="waiting"> - <!-- Display spinner if waiting, otherwise the sign-in icon --> - <fa-icon :class="{'animate-spin':waiting}" :icon="waiting ? 'spinner' : 'sign-in-alt'"/> - Log-out - </button> - </div> + <div class=""> + <button form="user-pass-submit-form" class="btn primary" @click="submitLogout" :disabled="waiting"> + <!-- Display spinner if waiting, otherwise the sign-in icon --> + <fa-icon :class="{'animate-spin':waiting}" :icon="waiting ? 'spinner' : 'sign-in-alt'" /> + Log-out + </button> + </div> </div> <div v-if="!loggedIn" class="w-full mt-6"> @@ -62,9 +62,13 @@ const submitLogout = async () => { <!-- pki button, forward to the pki route --> <div v-if="pkiEnabled" class="mt-4"> <router-link to="/login/pki"> - <button type="submit" class="btn red social-button" :disabled="waiting"> - <fa-icon :icon="['fa','certificate']" size="xl" /> - Login with PKI Credential + <button type="submit" class="btn social-button" :disabled="waiting"> + <span> + <svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" viewBox="0 0 256 256"> + <path fill="currentColor" d="M248 128a56 56 0 1 0-96 39.14V224a8 8 0 0 0 11.58 7.16L192 216.94l28.42 14.22A8 8 0 0 0 232 224v-56.86A55.81 55.81 0 0 0 248 128Zm-56-40a40 40 0 1 1-40 40a40 40 0 0 1 40-40Zm3.58 112.84a8 8 0 0 0-7.16 0L168 211.06v-32.47a55.94 55.94 0 0 0 48 0v32.47ZM136 192a8 8 0 0 1-8 8H40a16 16 0 0 1-16-16V56a16 16 0 0 1 16-16h176a16 16 0 0 1 16 16a8 8 0 0 1-16 0H40v128h88a8 8 0 0 1 8 8Zm-16-56a8 8 0 0 1-8 8H72a8 8 0 0 1 0-16h40a8 8 0 0 1 8 8Zm0-32a8 8 0 0 1-8 8H72a8 8 0 0 1 0-16h40a8 8 0 0 1 8 8Z" /> + </svg> + </span> + Login with OTP </button> </router-link> </div> @@ -90,9 +94,5 @@ const submitLogout = async () => { @apply flex flex-row justify-center gap-3 items-center; } - a { - @apply ease-in-out duration-100; - @apply hover:text-primary-600 dark:hover:text-primary-500; - } } </style> |