diff options
author | Daniel Baumann <daniel@debian.org> | 2024-11-26 09:28:28 +0100 |
---|---|---|
committer | Daniel Baumann <daniel@debian.org> | 2024-11-26 12:25:58 +0100 |
commit | a1882b67c41fe9901a0cd8059b5cc78a5beadec0 (patch) | |
tree | 2a24507c67aa99a15416707b2f7e645142230ed8 /src/components/TwoFADialog.vue | |
parent | Initial commit. (diff) | |
download | uptime-kuma-upstream.tar.xz uptime-kuma-upstream.zip |
Adding upstream version 2.0.0~beta.0+dfsg.upstream/2.0.0_beta.0+dfsgupstream
Signed-off-by: Daniel Baumann <daniel@debian.org>
Diffstat (limited to 'src/components/TwoFADialog.vue')
-rw-r--r-- | src/components/TwoFADialog.vue | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/src/components/TwoFADialog.vue b/src/components/TwoFADialog.vue new file mode 100644 index 0000000..6a0bf40 --- /dev/null +++ b/src/components/TwoFADialog.vue @@ -0,0 +1,225 @@ +<template> + <form @submit.prevent="submit"> + <div ref="modal" class="modal fade" tabindex="-1" data-bs-backdrop="static"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <h5 class="modal-title"> + {{ $t("Setup 2FA") }} + <span v-if="twoFAStatus == true" class="badge bg-primary">{{ $t("Active") }}</span> + <span v-if="twoFAStatus == false" class="badge bg-primary">{{ $t("Inactive") }}</span> + </h5> + <button :disabled="processing" type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" /> + </div> + <div class="modal-body"> + <div class="mb-3"> + <div v-if="uri && twoFAStatus == false" class="mx-auto text-center" style="width: 210px;"> + <vue-qrcode :key="uri" :value="uri" type="image/png" :quality="1" :color="{ light: '#ffffffff' }" /> + <button v-show="!showURI" type="button" class="btn btn-outline-primary btn-sm mt-2" @click="showURI = true">{{ $t("Show URI") }}</button> + </div> + <p v-if="showURI && twoFAStatus == false" class="text-break mt-2">{{ uri }}</p> + + <div v-if="!(uri && twoFAStatus == false)" class="mb-3"> + <label for="current-password" class="form-label"> + {{ $t("Current Password") }} + </label> + <input + id="current-password" + v-model="currentPassword" + type="password" + class="form-control" + autocomplete="current-password" + required + /> + </div> + + <button v-if="uri == null && twoFAStatus == false" class="btn btn-primary" type="button" @click="prepare2FA()"> + {{ $t("Enable 2FA") }} + </button> + + <button v-if="twoFAStatus == true" class="btn btn-danger" type="button" :disabled="processing" @click="confirmDisableTwoFA()"> + {{ $t("Disable 2FA") }} + </button> + + <div v-if="uri && twoFAStatus == false" class="mt-3"> + <label for="basic-url" class="form-label">{{ $t("twoFAVerifyLabel") }}</label> + <div class="input-group"> + <input v-model="token" type="text" maxlength="6" class="form-control" autocomplete="one-time-code" required> + <button class="btn btn-outline-primary" type="button" @click="verifyToken()">{{ $t("Verify Token") }}</button> + </div> + <p v-show="tokenValid" class="mt-2" style="color: green;">{{ $t("tokenValidSettingsMsg") }}</p> + </div> + </div> + </div> + + <div v-if="uri && twoFAStatus == false" class="modal-footer"> + <button type="submit" class="btn btn-primary" :disabled="processing || tokenValid == false" @click="confirmEnableTwoFA()"> + <div v-if="processing" class="spinner-border spinner-border-sm me-1"></div> + {{ $t("Save") }} + </button> + </div> + </div> + </div> + </div> + </form> + + <Confirm ref="confirmEnableTwoFA" btn-style="btn-danger" :yes-text="$t('Yes')" :no-text="$t('No')" @yes="save2FA"> + {{ $t("confirmEnableTwoFAMsg") }} + </Confirm> + + <Confirm ref="confirmDisableTwoFA" btn-style="btn-danger" :yes-text="$t('Yes')" :no-text="$t('No')" @yes="disable2FA"> + {{ $t("confirmDisableTwoFAMsg") }} + </Confirm> +</template> + +<script lang="ts"> +import { Modal } from "bootstrap"; +import Confirm from "./Confirm.vue"; +import VueQrcode from "vue-qrcode"; + +export default { + components: { + Confirm, + VueQrcode, + }, + props: {}, + data() { + return { + currentPassword: "", + processing: false, + uri: null, + tokenValid: false, + twoFAStatus: null, + token: null, + showURI: false, + }; + }, + mounted() { + this.modal = new Modal(this.$refs.modal); + this.getStatus(); + }, + methods: { + /** + * Show the dialog + * @returns {void} + */ + show() { + this.modal.show(); + }, + + /** + * Show dialog to confirm enabling 2FA + * @returns {void} + */ + confirmEnableTwoFA() { + this.$refs.confirmEnableTwoFA.show(); + }, + + /** + * Show dialog to confirm disabling 2FA + * @returns {void} + */ + confirmDisableTwoFA() { + this.$refs.confirmDisableTwoFA.show(); + }, + + /** + * Prepare 2FA configuration + * @returns {void} + */ + prepare2FA() { + this.processing = true; + + this.$root.getSocket().emit("prepare2FA", this.currentPassword, (res) => { + this.processing = false; + + if (res.ok) { + this.uri = res.uri; + } else { + this.$root.toastError(res.msg); + } + }); + }, + + /** + * Save the current 2FA configuration + * @returns {void} + */ + save2FA() { + this.processing = true; + + this.$root.getSocket().emit("save2FA", this.currentPassword, (res) => { + this.processing = false; + + if (res.ok) { + this.$root.toastRes(res); + this.getStatus(); + this.currentPassword = ""; + this.modal.hide(); + } else { + this.$root.toastError(res.msg); + } + }); + }, + + /** + * Disable 2FA for this user + * @returns {void} + */ + disable2FA() { + this.processing = true; + + this.$root.getSocket().emit("disable2FA", this.currentPassword, (res) => { + this.processing = false; + + if (res.ok) { + this.$root.toastRes(res); + this.getStatus(); + this.currentPassword = ""; + this.modal.hide(); + } else { + this.$root.toastError(res.msg); + } + }); + }, + + /** + * Verify the token generated by the user + * @returns {void} + */ + verifyToken() { + this.$root.getSocket().emit("verifyToken", this.token, this.currentPassword, (res) => { + if (res.ok) { + this.tokenValid = res.valid; + } else { + this.$root.toastError(res.msg); + } + }); + }, + + /** + * Get current status of 2FA + * @returns {void} + */ + getStatus() { + this.$root.getSocket().emit("twoFAStatus", (res) => { + if (res.ok) { + this.twoFAStatus = res.status; + } else { + this.$root.toastError(res.msg); + } + }); + }, + }, +}; +</script> + +<style lang="scss" scoped> +@import "../assets/vars.scss"; + +.dark { + .modal-dialog .form-text, .modal-dialog p { + color: $dark-font-color; + } +} +</style> |