mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-10-01 01:25:45 -04:00
eee9a1f004
* Mark username/password inputs as required * Mark 2FA input as required * Add autocomplete attributes * Add autocomplete suggestion to password change * Add autocomplete to 2FA dialog * Mark 2fa input as required
204 lines
7.6 KiB
Vue
204 lines
7.6 KiB
Vue
<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";
|
|
import { useToast } from "vue-toastification";
|
|
const toast = useToast();
|
|
|
|
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 */
|
|
show() {
|
|
this.modal.show();
|
|
},
|
|
|
|
/** Show dialog to confirm enabling 2FA */
|
|
confirmEnableTwoFA() {
|
|
this.$refs.confirmEnableTwoFA.show();
|
|
},
|
|
|
|
/** Show dialog to confirm disabling 2FA */
|
|
confirmDisableTwoFA() {
|
|
this.$refs.confirmDisableTwoFA.show();
|
|
},
|
|
|
|
/** Prepare 2FA configuration */
|
|
prepare2FA() {
|
|
this.processing = true;
|
|
|
|
this.$root.getSocket().emit("prepare2FA", this.currentPassword, (res) => {
|
|
this.processing = false;
|
|
|
|
if (res.ok) {
|
|
this.uri = res.uri;
|
|
} else {
|
|
toast.error(res.msg);
|
|
}
|
|
});
|
|
},
|
|
|
|
/** Save the current 2FA configuration */
|
|
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 {
|
|
toast.error(res.msg);
|
|
}
|
|
});
|
|
},
|
|
|
|
/** Disable 2FA for this user */
|
|
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 {
|
|
toast.error(res.msg);
|
|
}
|
|
});
|
|
},
|
|
|
|
/** Verify the token generated by the user */
|
|
verifyToken() {
|
|
this.$root.getSocket().emit("verifyToken", this.token, this.currentPassword, (res) => {
|
|
if (res.ok) {
|
|
this.tokenValid = res.valid;
|
|
} else {
|
|
toast.error(res.msg);
|
|
}
|
|
});
|
|
},
|
|
|
|
/** Get current status of 2FA */
|
|
getStatus() {
|
|
this.$root.getSocket().emit("twoFAStatus", (res) => {
|
|
if (res.ok) {
|
|
this.twoFAStatus = res.status;
|
|
} else {
|
|
toast.error(res.msg);
|
|
}
|
|
});
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
@import "../assets/vars.scss";
|
|
|
|
.dark {
|
|
.modal-dialog .form-text, .modal-dialog p {
|
|
color: $dark-font-color;
|
|
}
|
|
}
|
|
</style>
|