feat: 2FA input dialog

This commit is contained in:
ThatOneCalculator 2023-06-15 19:32:27 -07:00
parent 2de85c19fc
commit b63f9cb84e
5 changed files with 68 additions and 15 deletions

View File

@ -87,6 +87,7 @@
"vue-isyourpasswordsafe": "^2.0.0", "vue-isyourpasswordsafe": "^2.0.0",
"vue-plyr": "^7.0.0", "vue-plyr": "^7.0.0",
"vue-prism-editor": "2.0.0-alpha.2", "vue-prism-editor": "2.0.0-alpha.2",
"vue3-otp-input": "^0.4.1",
"vuedraggable": "4.1.0" "vuedraggable": "4.1.0"
} }
} }

View File

@ -99,18 +99,15 @@
><i class="ph-lock ph-bold ph-lg"></i ><i class="ph-lock ph-bold ph-lg"></i
></template> ></template>
</MkInput> </MkInput>
<MkInput <vue3-otp-input
input-classes="otp-input"
inputType="number"
:num-inputs="6"
v-model="token" v-model="token"
type="text" :should-auto-focus="true"
pattern="^[0-9]{6}$" @on-complete="onSubmit"
autocomplete="one-time-code"
:spellcheck="false"
required required
> />
<template #prefix>
<i class="ph-poker-chip ph-bold ph-lg"></i>
</template>
</MkInput>
<MkButton <MkButton
type="submit" type="submit"
:disabled="signing" :disabled="signing"
@ -159,6 +156,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import Vue3OtpInput from "vue3-otp-input";
import { defineAsyncComponent } from "vue"; import { defineAsyncComponent } from "vue";
import { toUnicode } from "punycode/"; import { toUnicode } from "punycode/";
import MkButton from "@/components/MkButton.vue"; import MkButton from "@/components/MkButton.vue";
@ -392,4 +390,27 @@ function showSuspendedDialog() {
} }
} }
} }
.otp-input {
width: 40px;
height: 40px;
padding: 5px;
margin: 0 10px;
font-size: 20px;
border-radius: 4px;
border: 2px solid var(--accent);
background-color: var(--accentedBg);
text-align: center;
}
.otp-input.is-complete {
border-color: var(--success) !important;
}
.otp-input.error {
border-color: var(--error) !important;
}
.otp-input::-webkit-inner-spin-button,
.otp-input::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
</style> </style>

View File

@ -94,5 +94,7 @@ const ok = () => {
.qr { .qr {
width: 20em; width: 20em;
max-width: 100%; max-width: 100%;
border-radius: 10px;
border: 3px solid var(--accent);
} }
</style> </style>

View File

@ -5,7 +5,10 @@
<div v-if="$i" class="_gaps_s"> <div v-if="$i" class="_gaps_s">
<MkFolder> <MkFolder>
<template #icon <template #icon
><i class="ph-shield-check ph-bold ph-lg"></i ><i
class="ph-shield-check ph-bold ph-lg"
style="margin-right: 0.5rem"
></i
></template> ></template>
<template #label>{{ i18n.ts.totp }}</template> <template #label>{{ i18n.ts.totp }}</template>
<template #caption>{{ i18n.ts.totpDescription }}</template> <template #caption>{{ i18n.ts.totpDescription }}</template>
@ -13,13 +16,19 @@
<div v-text="i18n.ts._2fa.alreadyRegistered" /> <div v-text="i18n.ts._2fa.alreadyRegistered" />
<template v-if="$i.securityKeysList.length > 0"> <template v-if="$i.securityKeysList.length > 0">
<MkButton @click="renewTOTP" <MkButton @click="renewTOTP"
><i class="ph-shield-check ph-bold ph-lg"></i ><i
class="ph-shield-check ph-bold ph-lg"
style="margin-right: 0.5rem"
></i
>{{ i18n.ts._2fa.renewTOTP }}</MkButton >{{ i18n.ts._2fa.renewTOTP }}</MkButton
> >
<MkInfo>{{ i18n.ts._2fa.whyTOTPOnlyRenew }}</MkInfo> <MkInfo>{{ i18n.ts._2fa.whyTOTPOnlyRenew }}</MkInfo>
</template> </template>
<MkButton v-else @click="unregisterTOTP" <MkButton v-else @click="unregisterTOTP"
><i class="ph-shield-slash ph-bold ph-lg"></i ><i
class="ph-shield-slash ph-bold ph-lg"
style="margin-right: 0.5rem"
></i
>{{ i18n.ts.unregister }}</MkButton >{{ i18n.ts.unregister }}</MkButton
> >
</div> </div>
@ -32,7 +41,12 @@
</MkFolder> </MkFolder>
<MkFolder> <MkFolder>
<template #icon><i class="ph-key ph-bold ph-lg"></i></template> <template #icon
><i
class="ph-key ph-bold ph-lg"
style="margin-right: 0.5rem"
></i
></template>
<template #label>{{ i18n.ts.securityKeyAndPasskey }}</template> <template #label>{{ i18n.ts.securityKeyAndPasskey }}</template>
<div class="_gaps_s"> <div class="_gaps_s">
<MkInfo> <MkInfo>
@ -54,7 +68,10 @@
<template v-else> <template v-else>
<MkButton primary @click="addSecurityKey" <MkButton primary @click="addSecurityKey"
><i class="ph-key ph-bold ph-lg"></i ><i
class="ph-key ph-bold ph-lg"
style="margin-right: 0.5rem"
></i
>{{ i18n.ts._2fa.registerSecurityKey }}</MkButton >{{ i18n.ts._2fa.registerSecurityKey }}</MkButton
> >
<MkFolder <MkFolder

View File

@ -906,6 +906,9 @@ importers:
vue-prism-editor: vue-prism-editor:
specifier: 2.0.0-alpha.2 specifier: 2.0.0-alpha.2
version: 2.0.0-alpha.2(vue@3.3.4) version: 2.0.0-alpha.2(vue@3.3.4)
vue3-otp-input:
specifier: ^0.4.1
version: 0.4.1(vue@3.3.4)
vuedraggable: vuedraggable:
specifier: 4.1.0 specifier: 4.1.0
version: 4.1.0(vue@3.3.4) version: 4.1.0(vue@3.3.4)
@ -15213,6 +15216,15 @@ packages:
vue: 3.3.4 vue: 3.3.4
dev: true dev: true
/vue3-otp-input@0.4.1(vue@3.3.4):
resolution: {integrity: sha512-wVl9i3DcWlO0C7fBI9V+RIP3crm/1tY72fuhvb3YM2JfbLoYofB96aPl5AgFhA0Cse5bQEMYtIvOeiqW3rfbAw==}
engines: {node: '>=16.0.0', npm: '>=8.0.0'}
peerDependencies:
vue: ^3.0.*
dependencies:
vue: 3.3.4
dev: true
/vue@2.7.14: /vue@2.7.14:
resolution: {integrity: sha512-b2qkFyOM0kwqWFuQmgd4o+uHGU7T+2z3T+WQp8UBjADfEv2n4FEMffzBmCKNP0IGzOEEfYjvtcC62xaSKeQDrQ==} resolution: {integrity: sha512-b2qkFyOM0kwqWFuQmgd4o+uHGU7T+2z3T+WQp8UBjADfEv2n4FEMffzBmCKNP0IGzOEEfYjvtcC62xaSKeQDrQ==}
dependencies: dependencies: