mirror of
https://github.com/donaldzou/WGDashboard.git
synced 2024-11-06 16:00:28 +01:00
fixing some Gunicorn bugs.. again..
This commit is contained in:
parent
bd71b6bad8
commit
0fdef6a0a2
@ -944,6 +944,7 @@ class DashboardConfig:
|
|||||||
"username": "admin",
|
"username": "admin",
|
||||||
"password": "admin",
|
"password": "admin",
|
||||||
"enable_totp": "false",
|
"enable_totp": "false",
|
||||||
|
"totp_verified": "false",
|
||||||
"totp_key": pyotp.random_base32()
|
"totp_key": pyotp.random_base32()
|
||||||
},
|
},
|
||||||
"Server": {
|
"Server": {
|
||||||
@ -1780,12 +1781,14 @@ Sign Up
|
|||||||
|
|
||||||
@app.route('/api/isTotpEnabled')
|
@app.route('/api/isTotpEnabled')
|
||||||
def API_isTotpEnabled():
|
def API_isTotpEnabled():
|
||||||
return ResponseObject(data=DashboardConfig.GetConfig("Account", "enable_totp")[1])
|
return (
|
||||||
|
ResponseObject(data=DashboardConfig.GetConfig("Account", "enable_totp")[1] and DashboardConfig.GetConfig("Account", "totp_verified")[1]))
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/Welcome_GetTotpLink')
|
@app.route('/api/Welcome_GetTotpLink')
|
||||||
def API_Welcome_GetTotpLink():
|
def API_Welcome_GetTotpLink():
|
||||||
if DashboardConfig.GetConfig("Other", "welcome_session")[1]:
|
if not DashboardConfig.GetConfig("Account", "totp_verified")[1]:
|
||||||
|
DashboardConfig.SetConfig("Account", "totp_key", pyotp.random_base32())
|
||||||
return ResponseObject(
|
return ResponseObject(
|
||||||
data=pyotp.totp.TOTP(DashboardConfig.GetConfig("Account", "totp_key")[1]).provisioning_uri(
|
data=pyotp.totp.TOTP(DashboardConfig.GetConfig("Account", "totp_key")[1]).provisioning_uri(
|
||||||
issuer_name="WGDashboard"))
|
issuer_name="WGDashboard"))
|
||||||
@ -1795,11 +1798,11 @@ def API_Welcome_GetTotpLink():
|
|||||||
@app.route('/api/Welcome_VerifyTotpLink', methods=["POST"])
|
@app.route('/api/Welcome_VerifyTotpLink', methods=["POST"])
|
||||||
def API_Welcome_VerifyTotpLink():
|
def API_Welcome_VerifyTotpLink():
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
if DashboardConfig.GetConfig("Other", "welcome_session")[1]:
|
|
||||||
totp = pyotp.TOTP(DashboardConfig.GetConfig("Account", "totp_key")[1]).now()
|
totp = pyotp.TOTP(DashboardConfig.GetConfig("Account", "totp_key")[1]).now()
|
||||||
print(totp)
|
if totp == data['totp']:
|
||||||
|
DashboardConfig.SetConfig("Account", "totp_verified", "true")
|
||||||
|
DashboardConfig.SetConfig("Account", "enable_totp", "true")
|
||||||
return ResponseObject(totp == data['totp'])
|
return ResponseObject(totp == data['totp'])
|
||||||
return ResponseObject(False)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/Welcome_Finish', methods=["POST"])
|
@app.route('/api/Welcome_Finish', methods=["POST"])
|
||||||
@ -1819,10 +1822,10 @@ def API_Welcome_Finish():
|
|||||||
"repeatNewPassword": data["repeatNewPassword"],
|
"repeatNewPassword": data["repeatNewPassword"],
|
||||||
"currentPassword": "admin"
|
"currentPassword": "admin"
|
||||||
})
|
})
|
||||||
updateEnableTotp, updateEnableTotpErr = DashboardConfig.SetConfig("Account", "enable_totp", data["enable_totp"])
|
# updateEnableTotp, updateEnableTotpErr = DashboardConfig.SetConfig("Account", "enable_totp", data["enable_totp"])
|
||||||
|
|
||||||
if not updateUsername or not updatePassword or not updateEnableTotp:
|
if not updateUsername or not updatePassword:
|
||||||
return ResponseObject(False, f"{updateUsernameErr},{updatePasswordErr},{updateEnableTotpErr}".strip(","))
|
return ResponseObject(False, f"{updateUsernameErr},{updatePasswordErr}".strip(","))
|
||||||
|
|
||||||
DashboardConfig.SetConfig("Other", "welcome_session", False)
|
DashboardConfig.SetConfig("Other", "welcome_session", False)
|
||||||
|
|
||||||
@ -1888,14 +1891,18 @@ _, WG_CONF_PATH = DashboardConfig.GetConfig("Server", "wg_conf_path")
|
|||||||
|
|
||||||
WireguardConfigurations: dict[str, WireguardConfiguration] = {}
|
WireguardConfigurations: dict[str, WireguardConfiguration] = {}
|
||||||
WireguardConfigurations = _getConfigurationList()
|
WireguardConfigurations = _getConfigurationList()
|
||||||
bgThread = threading.Thread(target=backGroundThread)
|
|
||||||
bgThread.daemon = True
|
|
||||||
bgThread.start()
|
|
||||||
|
|
||||||
scheduleJobThread = threading.Thread(target=peerJobScheduleBackgroundThread)
|
|
||||||
scheduleJobThread.daemon = True
|
def startThreads():
|
||||||
scheduleJobThread.start()
|
bgThread = threading.Thread(target=backGroundThread)
|
||||||
|
bgThread.daemon = True
|
||||||
|
bgThread.start()
|
||||||
|
|
||||||
|
scheduleJobThread = threading.Thread(target=peerJobScheduleBackgroundThread)
|
||||||
|
scheduleJobThread.daemon = True
|
||||||
|
scheduleJobThread.start()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
startThreads()
|
||||||
app.run(host=app_ip, debug=False, port=app_port)
|
app.run(host=app_ip, debug=False, port=app_port)
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
import dashboard
|
import dashboard
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
global sqldb, cursor, DashboardConfig, WireguardConfigurations, AllPeerJobs, JobLogger
|
global sqldb, cursor, DashboardConfig, WireguardConfigurations, AllPeerJobs, JobLogger
|
||||||
app_host, app_port = dashboard.gunicornConfig()
|
app_host, app_port = dashboard.gunicornConfig()
|
||||||
date = datetime.today().strftime('%Y_%m_%d_%H_%M_%S')
|
date = datetime.today().strftime('%Y_%m_%d_%H_%M_%S')
|
||||||
|
|
||||||
|
|
||||||
|
def post_worker_init(worker):
|
||||||
|
dashboard.startThreads()
|
||||||
|
|
||||||
|
|
||||||
worker_class = 'gthread'
|
worker_class = 'gthread'
|
||||||
workers = 1
|
workers = 1
|
||||||
threads = 1
|
threads = 1
|
||||||
|
44
src/static/app/dist/assets/index.js
vendored
44
src/static/app/dist/assets/index.js
vendored
File diff suppressed because one or more lines are too long
@ -0,0 +1,63 @@
|
|||||||
|
<script>
|
||||||
|
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
|
||||||
|
import {v4} from "uuid";
|
||||||
|
import {fetchPost} from "@/utilities/fetch.js";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "accountSettingsMFA",
|
||||||
|
setup(){
|
||||||
|
const store = DashboardConfigurationStore();
|
||||||
|
const uuid = `input_${v4()}`;
|
||||||
|
return {store, uuid};
|
||||||
|
},
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
status: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.status = this.store.Configuration.Account["enable_totp"]
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async resetMFA(){
|
||||||
|
await fetchPost("/api/updateDashboardConfigurationItem", {
|
||||||
|
section: "Account",
|
||||||
|
key: "totp_verified",
|
||||||
|
value: "false"
|
||||||
|
}, async (res) => {
|
||||||
|
await fetchPost("/api/updateDashboardConfigurationItem", {
|
||||||
|
section: "Account",
|
||||||
|
key: "enable_totp",
|
||||||
|
value: "false"
|
||||||
|
}, (res) => {
|
||||||
|
if (res.status){
|
||||||
|
this.$router.push("/2FASetup")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<strong>Multi-Factor Authentication</strong>
|
||||||
|
<div class="form-check form-switch ms-3">
|
||||||
|
<input class="form-check-input" type="checkbox"
|
||||||
|
v-model="this.status"
|
||||||
|
role="switch" id="allowAPIKeysSwitch">
|
||||||
|
</div>
|
||||||
|
<button class="btn bg-warning-subtle text-warning-emphasis border-1 border-warning-subtle ms-auto rounded-3 shadow-sm"
|
||||||
|
v-if="this.status" @click="this.resetMFA()">
|
||||||
|
<i class="bi bi-shield-lock-fill me-2"></i>
|
||||||
|
{{this.store.Configuration.Account["totp_verified"] ? "Reset" : "Setup" }} MFA
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -1,15 +1,17 @@
|
|||||||
<script>
|
<script>
|
||||||
import {fetchGet, fetchPost} from "@/utilities/fetch.js";
|
import {fetchGet, fetchPost} from "@/utilities/fetch.js";
|
||||||
import QRCode from "qrcode";
|
import QRCode from "qrcode";
|
||||||
|
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "totp",
|
name: "totp",
|
||||||
async setup(){
|
async setup(){
|
||||||
|
const store = DashboardConfigurationStore();
|
||||||
let l = ""
|
let l = ""
|
||||||
await fetchGet("/api/Welcome_GetTotpLink", {}, (res => {
|
await fetchGet("/api/Welcome_GetTotpLink", {}, (res => {
|
||||||
if (res.status) l = res.data;
|
if (res.status) l = res.data;
|
||||||
}));
|
}));
|
||||||
return {l}
|
return {l, store}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.l) {
|
if (this.l) {
|
||||||
@ -58,7 +60,12 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="mb-3">
|
<div class="container-fluid login-container-fluid d-flex main pt-5 overflow-scroll"
|
||||||
|
:data-bs-theme="this.store.Configuration.Server.dashboard_theme">
|
||||||
|
<div class="m-auto text-body" style="width: 500px">
|
||||||
|
<div class="d-flex flex-column">
|
||||||
|
<div>
|
||||||
|
<h1 class="dashboardLogo display-4">Multi-Factor Authentication</h1>
|
||||||
<p class="mb-2"><small class="text-muted">1. Please scan the following QR Code to generate TOTP</small></p>
|
<p class="mb-2"><small class="text-muted">1. Please scan the following QR Code to generate TOTP</small></p>
|
||||||
<canvas id="qrcode" class="rounded-3 mb-2"></canvas>
|
<canvas id="qrcode" class="rounded-3 mb-2"></canvas>
|
||||||
<div class="p-3 bg-body-secondary rounded-3 border mb-3">
|
<div class="p-3 bg-body-secondary rounded-3 border mb-3">
|
||||||
@ -66,7 +73,7 @@ export default {
|
|||||||
</p><a :href="this.l"><code style="line-break: anywhere">{{this.l}}</code></a>
|
</p><a :href="this.l"><code style="line-break: anywhere">{{this.l}}</code></a>
|
||||||
</div>
|
</div>
|
||||||
<label for="totp" class="mb-2"><small class="text-muted">2. Enter the TOTP generated by your authenticator to verify</small></label>
|
<label for="totp" class="mb-2"><small class="text-muted">2. Enter the TOTP generated by your authenticator to verify</small></label>
|
||||||
<div class="form-group">
|
<div class="form-group mb-2">
|
||||||
<input class="form-control text-center totp"
|
<input class="form-control text-center totp"
|
||||||
id="totp" maxlength="6" type="text" inputmode="numeric" autocomplete="one-time-code"
|
id="totp" maxlength="6" type="text" inputmode="numeric" autocomplete="one-time-code"
|
||||||
v-model="this.totp"
|
v-model="this.totp"
|
||||||
@ -79,7 +86,32 @@ export default {
|
|||||||
TOTP verified!
|
TOTP verified!
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="alert alert-warning rounded-3">
|
||||||
|
<i class="bi bi-exclamation-triangle-fill me-2"></i> If you ever lost your TOTP and can't login, please follow instruction on
|
||||||
|
<a href="https://github.com/donaldzou/WGDashboard" target="_blank">readme.md</a> to reset.
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div class="d-flex gap-3 mt-5 flex-column">
|
||||||
|
<RouterLink
|
||||||
|
to="/"
|
||||||
|
v-if="!this.verified"
|
||||||
|
class="btn bg-secondary-subtle text-secondary-emphasis
|
||||||
|
rounded-3
|
||||||
|
flex-grow-1 btn-lg border-1 border-secondary-subtle shadow d-flex">
|
||||||
|
I don't need MFA <i class="bi bi-chevron-right ms-auto"></i>
|
||||||
|
</RouterLink>
|
||||||
|
<RouterLink
|
||||||
|
to="/"
|
||||||
|
v-else class="btn btn-dark btn-lg d-flex btn-brand shadow align-items-center flex-grow-1 rounded-3">
|
||||||
|
Complete <i class="bi bi-chevron-right ms-auto"></i>
|
||||||
|
</RouterLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
@ -14,6 +14,7 @@ import PeerList from "@/components/configurationComponents/peerList.vue";
|
|||||||
import PeerCreate from "@/components/configurationComponents/peerCreate.vue";
|
import PeerCreate from "@/components/configurationComponents/peerCreate.vue";
|
||||||
import Ping from "@/views/ping.vue";
|
import Ping from "@/views/ping.vue";
|
||||||
import Traceroute from "@/views/traceroute.vue";
|
import Traceroute from "@/views/traceroute.vue";
|
||||||
|
import Totp from "@/components/setupComponent/totp.vue";
|
||||||
|
|
||||||
const checkAuth = async () => {
|
const checkAuth = async () => {
|
||||||
let result = false
|
let result = false
|
||||||
@ -103,6 +104,12 @@ const router = createRouter({
|
|||||||
meta: {
|
meta: {
|
||||||
requiresAuth: true
|
requiresAuth: true
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/2FASetup', component: Totp,
|
||||||
|
meta: {
|
||||||
|
requiresAuth: true
|
||||||
|
},
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
@ -11,11 +11,13 @@ import DashboardTheme from "@/components/settingsComponent/dashboardTheme.vue";
|
|||||||
import DashboardSettingsInputIPAddressAndPort
|
import DashboardSettingsInputIPAddressAndPort
|
||||||
from "@/components/settingsComponent/dashboardSettingsInputIPAddressAndPort.vue";
|
from "@/components/settingsComponent/dashboardSettingsInputIPAddressAndPort.vue";
|
||||||
import DashboardAPIKeys from "@/components/settingsComponent/dashboardAPIKeys.vue";
|
import DashboardAPIKeys from "@/components/settingsComponent/dashboardAPIKeys.vue";
|
||||||
|
import AccountSettingsMFA from "@/components/settingsComponent/accountSettingsMFA.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "settings",
|
name: "settings",
|
||||||
methods: {ipV46RegexCheck},
|
methods: {ipV46RegexCheck},
|
||||||
components: {
|
components: {
|
||||||
|
AccountSettingsMFA,
|
||||||
DashboardAPIKeys,
|
DashboardAPIKeys,
|
||||||
DashboardSettingsInputIPAddressAndPort,
|
DashboardSettingsInputIPAddressAndPort,
|
||||||
DashboardTheme,
|
DashboardTheme,
|
||||||
@ -49,7 +51,7 @@ export default {
|
|||||||
<PeersDefaultSettingsInput targetData="peer_mtu" title="MTU (Max Transmission Unit)"></PeersDefaultSettingsInput>
|
<PeersDefaultSettingsInput targetData="peer_mtu" title="MTU (Max Transmission Unit)"></PeersDefaultSettingsInput>
|
||||||
<PeersDefaultSettingsInput targetData="peer_keep_alive" title="Persistent Keepalive"></PeersDefaultSettingsInput>
|
<PeersDefaultSettingsInput targetData="peer_keep_alive" title="Persistent Keepalive"></PeersDefaultSettingsInput>
|
||||||
<PeersDefaultSettingsInput targetData="remote_endpoint" title="Peer Remote Endpoint"
|
<PeersDefaultSettingsInput targetData="remote_endpoint" title="Peer Remote Endpoint"
|
||||||
:warning="true" warningText="This will be change globally, and will be apply to all peer's QR code and configuration file."
|
:warning="true" warningText="This will be changed globally, and will be apply to all peer's QR code and configuration file."
|
||||||
></PeersDefaultSettingsInput>
|
></PeersDefaultSettingsInput>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -67,14 +69,16 @@ export default {
|
|||||||
</div>
|
</div>
|
||||||
<div class="card mb-4 shadow rounded-3">
|
<div class="card mb-4 shadow rounded-3">
|
||||||
<p class="card-header">Account Settings</p>
|
<p class="card-header">Account Settings</p>
|
||||||
<div class="card-body">
|
<div class="card-body d-flex gap-4 flex-column">
|
||||||
<AccountSettingsInputUsername targetData="username"
|
<AccountSettingsInputUsername targetData="username"
|
||||||
title="Username"
|
title="Username"
|
||||||
></AccountSettingsInputUsername>
|
></AccountSettingsInputUsername>
|
||||||
<hr>
|
<hr class="m-0">
|
||||||
<AccountSettingsInputPassword
|
<AccountSettingsInputPassword
|
||||||
targetData="password">
|
targetData="password">
|
||||||
</AccountSettingsInputPassword>
|
</AccountSettingsInputPassword>
|
||||||
|
<hr class="m-0">
|
||||||
|
<AccountSettingsMFA></AccountSettingsMFA>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<DashboardAPIKeys></DashboardAPIKeys>
|
<DashboardAPIKeys></DashboardAPIKeys>
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
<script>
|
<script>
|
||||||
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
|
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
|
||||||
import QRCode from 'qrcode'
|
|
||||||
import Totp from "@/components/setupComponent/totp.vue";
|
|
||||||
import {fetchPost} from "@/utilities/fetch.js";
|
import {fetchPost} from "@/utilities/fetch.js";
|
||||||
export default {
|
export default {
|
||||||
name: "setup",
|
name: "setup",
|
||||||
components: {Totp},
|
components: {},
|
||||||
setup(){
|
setup(){
|
||||||
const store = DashboardConfigurationStore();
|
const store = DashboardConfigurationStore();
|
||||||
return {store}
|
return {store}
|
||||||
@ -16,8 +14,7 @@ export default {
|
|||||||
username: "",
|
username: "",
|
||||||
newPassword: "",
|
newPassword: "",
|
||||||
repeatNewPassword: "",
|
repeatNewPassword: "",
|
||||||
enable_totp: false,
|
enable_totp: true
|
||||||
verified_totp: false
|
|
||||||
},
|
},
|
||||||
loading: false,
|
loading: false,
|
||||||
errorMessage: "",
|
errorMessage: "",
|
||||||
@ -30,7 +27,6 @@ export default {
|
|||||||
&& this.setup.newPassword.length >= 8
|
&& this.setup.newPassword.length >= 8
|
||||||
&& this.setup.repeatNewPassword.length >= 8
|
&& this.setup.repeatNewPassword.length >= 8
|
||||||
&& this.setup.newPassword === this.setup.repeatNewPassword
|
&& this.setup.newPassword === this.setup.repeatNewPassword
|
||||||
&& ((this.setup.enable_totp && this.setup.verified_totp) || !this.setup.enable_totp)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -39,9 +35,7 @@ export default {
|
|||||||
fetchPost("/api/Welcome_Finish", this.setup, (res) => {
|
fetchPost("/api/Welcome_Finish", this.setup, (res) => {
|
||||||
if (res.status){
|
if (res.status){
|
||||||
this.done = true;
|
this.done = true;
|
||||||
setTimeout(() => {
|
this.$router.push('/2FASetup')
|
||||||
this.$router.push('/')
|
|
||||||
}, 500)
|
|
||||||
}else{
|
}else{
|
||||||
document.querySelectorAll("#createAccount input").forEach(x => x.classList.add("is-invalid"))
|
document.querySelectorAll("#createAccount input").forEach(x => x.classList.add("is-invalid"))
|
||||||
this.errorMessage = res.message;
|
this.errorMessage = res.message;
|
||||||
@ -62,7 +56,7 @@ export default {
|
|||||||
<template>
|
<template>
|
||||||
<div class="container-fluid login-container-fluid d-flex main pt-5 overflow-scroll"
|
<div class="container-fluid login-container-fluid d-flex main pt-5 overflow-scroll"
|
||||||
:data-bs-theme="this.store.Configuration.Server.dashboard_theme">
|
:data-bs-theme="this.store.Configuration.Server.dashboard_theme">
|
||||||
<div class="mx-auto text-body" style="width: 500px">
|
<div class="m-auto text-body" style="width: 500px">
|
||||||
<span class="dashboardLogo display-4">Nice to meet you!</span>
|
<span class="dashboardLogo display-4">Nice to meet you!</span>
|
||||||
<p class="mb-5">Please fill in the following fields to finish setup 😊</p>
|
<p class="mb-5">Please fill in the following fields to finish setup 😊</p>
|
||||||
<div>
|
<div>
|
||||||
@ -94,26 +88,23 @@ export default {
|
|||||||
class="form-control" id="confirmPassword" name="confirmPassword" placeholder="and you can remember it :)" required>
|
class="form-control" id="confirmPassword" name="confirmPassword" placeholder="and you can remember it :)" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<!-- <div class="form-check form-switch">-->
|
||||||
<div class="form-check form-switch">
|
<!-- <input class="form-check-input" type="checkbox" role="switch" id="enable_totp" -->
|
||||||
<input class="form-check-input" type="checkbox" role="switch" id="enable_totp"
|
<!-- v-model="this.setup.enable_totp">-->
|
||||||
v-model="this.setup.enable_totp">
|
<!-- <label class="form-check-label" -->
|
||||||
<label class="form-check-label"
|
<!-- for="enable_totp">Enable 2 Factor Authentication? <strong>Strongly recommended</strong></label>-->
|
||||||
for="enable_totp">Enable 2 Factor Authentication? <strong>Strongly recommended</strong></label>
|
<!-- </div>-->
|
||||||
</div>
|
<!-- <Suspense>-->
|
||||||
<Suspense>
|
<!-- <Transition name="fade">-->
|
||||||
<Transition name="fade">
|
<!-- <Totp v-if="this.setup.enable_totp" @verified="this.setup.verified_totp = true"></Totp>-->
|
||||||
<Totp v-if="this.setup.enable_totp" @verified="this.setup.verified_totp = true"></Totp>
|
<!-- </Transition>-->
|
||||||
</Transition>
|
<!-- </Suspense>-->
|
||||||
</Suspense>
|
|
||||||
|
|
||||||
<button class="btn btn-dark btn-lg mb-5 d-flex btn-brand shadow align-items-center"
|
<button class="btn btn-dark btn-lg mb-5 d-flex btn-brand shadow align-items-center"
|
||||||
ref="signInBtn"
|
ref="signInBtn"
|
||||||
:disabled="!this.goodToSubmit || this.loading || this.done" @click="this.submit()">
|
:disabled="!this.goodToSubmit || this.loading || this.done" @click="this.submit()">
|
||||||
<span class="d-flex align-items-center w-100" v-if="!this.loading && !this.done">
|
<span class="d-flex align-items-center w-100" v-if="!this.loading && !this.done">
|
||||||
Finish<i class="bi bi-chevron-right ms-auto"></i></span>
|
Next<i class="bi bi-chevron-right ms-auto"></i></span>
|
||||||
<span class="d-flex align-items-center w-100" v-else-if="this.done">
|
|
||||||
Welcome to WGDashboard!</span>
|
|
||||||
<span class="d-flex align-items-center w-100" v-else>
|
<span class="d-flex align-items-center w-100" v-else>
|
||||||
Saving...<span class="spinner-border ms-auto spinner-border-sm" role="status">
|
Saving...<span class="spinner-border ms-auto spinner-border-sm" role="status">
|
||||||
<span class="visually-hidden">Loading...</span>
|
<span class="visually-hidden">Loading...</span>
|
||||||
|
Loading…
Reference in New Issue
Block a user