90 lines
2.2 KiB
Vue
90 lines
2.2 KiB
Vue
|
<script setup lang="ts">
|
||
|
import { ref, inject } from 'vue';
|
||
|
import { Auth, check_token, isErrorResponse, TokenInjectType } from '@/api';
|
||
|
|
||
|
enum state {
|
||
|
SELECT,
|
||
|
MAIL,
|
||
|
TOTP
|
||
|
}
|
||
|
|
||
|
const currentState = ref<state>(state.SELECT);
|
||
|
|
||
|
const error = ref('');
|
||
|
const qrImage = ref('');
|
||
|
const secret = ref('');
|
||
|
const code = ref('');
|
||
|
|
||
|
const jwt = inject<TokenInjectType>('jwt') as TokenInjectType;
|
||
|
|
||
|
async function selectMail() {
|
||
|
const token = await check_token(jwt);
|
||
|
if (!token) return;
|
||
|
error.value = 'Working...';
|
||
|
const res = await Auth.tfa_setup(true, token);
|
||
|
if (isErrorResponse(res))
|
||
|
error.value = 'Failed to select 2fa type: ' + res.message;
|
||
|
else {
|
||
|
error.value = '';
|
||
|
currentState.value = state.MAIL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async function selectTotp() {
|
||
|
const token = await check_token(jwt);
|
||
|
if (!token) return;
|
||
|
error.value = 'Working...';
|
||
|
const res = await Auth.tfa_setup(false, token);
|
||
|
if (isErrorResponse(res))
|
||
|
error.value = 'Failed to select 2fa type: ' + res.message;
|
||
|
else {
|
||
|
qrImage.value = res.qrCode;
|
||
|
secret.value = res.secret;
|
||
|
error.value = '';
|
||
|
currentState.value = state.TOTP;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async function submit() {
|
||
|
const token = await check_token(jwt);
|
||
|
if (!token) return;
|
||
|
error.value = 'Working...';
|
||
|
const res = await Auth.tfa_complete(
|
||
|
currentState.value === state.MAIL,
|
||
|
code.value,
|
||
|
token
|
||
|
);
|
||
|
if (isErrorResponse(res))
|
||
|
error.value = 'Failed to submit code: ' + res.message;
|
||
|
else jwt.logout();
|
||
|
}
|
||
|
</script>
|
||
|
|
||
|
<template>
|
||
|
<div v-if="error !== ''" v-text="error"></div>
|
||
|
<template v-if="currentState === state.SELECT">
|
||
|
<div>Select 2 Factor authentication type:</div>
|
||
|
<div>
|
||
|
<button @click="selectMail">Mail</button>
|
||
|
<button @click="selectTotp">Google Authenticator</button>
|
||
|
</div>
|
||
|
</template>
|
||
|
<template v-else-if="currentState === state.MAIL">
|
||
|
<div>Please enter the code you got by mail</div>
|
||
|
<input type="text" placeholder="Code" v-model="code" />
|
||
|
<button @click="submit()">Submit</button>
|
||
|
</template>
|
||
|
<template v-else>
|
||
|
<img :src="qrImage" alt="QrCode" />
|
||
|
<details>
|
||
|
<summary>Show manual input code</summary>
|
||
|
{{ secret }}
|
||
|
</details>
|
||
|
<div>Please enter the current code</div>
|
||
|
<input type="text" placeholder="Code" v-model="code" />
|
||
|
<button @click="submit()">Submit</button>
|
||
|
</template>
|
||
|
</template>
|
||
|
|
||
|
<style scoped></style>
|