mirror of
https://github.com/donaldzou/WGDashboard.git
synced 2024-11-06 07:50:13 +01:00
fixing some Gunicorn bugs.. again..
This commit is contained in:
parent
bd71b6bad8
commit
0fdef6a0a2
@ -944,6 +944,7 @@ class DashboardConfig:
|
||||
"username": "admin",
|
||||
"password": "admin",
|
||||
"enable_totp": "false",
|
||||
"totp_verified": "false",
|
||||
"totp_key": pyotp.random_base32()
|
||||
},
|
||||
"Server": {
|
||||
@ -1780,12 +1781,14 @@ Sign Up
|
||||
|
||||
@app.route('/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')
|
||||
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(
|
||||
data=pyotp.totp.TOTP(DashboardConfig.GetConfig("Account", "totp_key")[1]).provisioning_uri(
|
||||
issuer_name="WGDashboard"))
|
||||
@ -1795,11 +1798,11 @@ def API_Welcome_GetTotpLink():
|
||||
@app.route('/api/Welcome_VerifyTotpLink', methods=["POST"])
|
||||
def API_Welcome_VerifyTotpLink():
|
||||
data = request.get_json()
|
||||
if DashboardConfig.GetConfig("Other", "welcome_session")[1]:
|
||||
totp = pyotp.TOTP(DashboardConfig.GetConfig("Account", "totp_key")[1]).now()
|
||||
print(totp)
|
||||
return ResponseObject(totp == data['totp'])
|
||||
return ResponseObject(False)
|
||||
totp = pyotp.TOTP(DashboardConfig.GetConfig("Account", "totp_key")[1]).now()
|
||||
if totp == data['totp']:
|
||||
DashboardConfig.SetConfig("Account", "totp_verified", "true")
|
||||
DashboardConfig.SetConfig("Account", "enable_totp", "true")
|
||||
return ResponseObject(totp == data['totp'])
|
||||
|
||||
|
||||
@app.route('/api/Welcome_Finish', methods=["POST"])
|
||||
@ -1819,10 +1822,10 @@ def API_Welcome_Finish():
|
||||
"repeatNewPassword": data["repeatNewPassword"],
|
||||
"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:
|
||||
return ResponseObject(False, f"{updateUsernameErr},{updatePasswordErr},{updateEnableTotpErr}".strip(","))
|
||||
if not updateUsername or not updatePassword:
|
||||
return ResponseObject(False, f"{updateUsernameErr},{updatePasswordErr}".strip(","))
|
||||
|
||||
DashboardConfig.SetConfig("Other", "welcome_session", False)
|
||||
|
||||
@ -1888,14 +1891,18 @@ _, WG_CONF_PATH = DashboardConfig.GetConfig("Server", "wg_conf_path")
|
||||
|
||||
WireguardConfigurations: dict[str, WireguardConfiguration] = {}
|
||||
WireguardConfigurations = _getConfigurationList()
|
||||
bgThread = threading.Thread(target=backGroundThread)
|
||||
bgThread.daemon = True
|
||||
bgThread.start()
|
||||
|
||||
scheduleJobThread = threading.Thread(target=peerJobScheduleBackgroundThread)
|
||||
scheduleJobThread.daemon = True
|
||||
scheduleJobThread.start()
|
||||
|
||||
def startThreads():
|
||||
bgThread = threading.Thread(target=backGroundThread)
|
||||
bgThread.daemon = True
|
||||
bgThread.start()
|
||||
|
||||
scheduleJobThread = threading.Thread(target=peerJobScheduleBackgroundThread)
|
||||
scheduleJobThread.daemon = True
|
||||
scheduleJobThread.start()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
startThreads()
|
||||
app.run(host=app_ip, debug=False, port=app_port)
|
||||
|
@ -1,10 +1,15 @@
|
||||
import dashboard
|
||||
from datetime import datetime
|
||||
|
||||
global sqldb, cursor, DashboardConfig, WireguardConfigurations, AllPeerJobs, JobLogger
|
||||
app_host, app_port = dashboard.gunicornConfig()
|
||||
date = datetime.today().strftime('%Y_%m_%d_%H_%M_%S')
|
||||
|
||||
|
||||
def post_worker_init(worker):
|
||||
dashboard.startThreads()
|
||||
|
||||
|
||||
worker_class = 'gthread'
|
||||
workers = 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>
|
||||
import {fetchGet, fetchPost} from "@/utilities/fetch.js";
|
||||
import QRCode from "qrcode";
|
||||
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
|
||||
|
||||
export default {
|
||||
name: "totp",
|
||||
async setup(){
|
||||
const store = DashboardConfigurationStore();
|
||||
let l = ""
|
||||
await fetchGet("/api/Welcome_GetTotpLink", {}, (res => {
|
||||
if (res.status) l = res.data;
|
||||
}));
|
||||
return {l}
|
||||
return {l, store}
|
||||
},
|
||||
mounted() {
|
||||
if (this.l) {
|
||||
@ -58,28 +60,58 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mb-3">
|
||||
<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>
|
||||
<div class="p-3 bg-body-secondary rounded-3 border mb-3">
|
||||
<p class="text-muted mb-0"><small>Or you can click the link below:</small>
|
||||
</p><a :href="this.l"><code style="line-break: anywhere">{{this.l}}</code></a>
|
||||
</div>
|
||||
<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">
|
||||
<input class="form-control text-center totp"
|
||||
id="totp" maxlength="6" type="text" inputmode="numeric" autocomplete="one-time-code"
|
||||
v-model="this.totp"
|
||||
:disabled="this.verified"
|
||||
>
|
||||
<div class="invalid-feedback">
|
||||
{{this.totpInvalidMessage}}
|
||||
</div>
|
||||
<div class="valid-feedback">
|
||||
TOTP verified!
|
||||
<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>
|
||||
<canvas id="qrcode" class="rounded-3 mb-2"></canvas>
|
||||
<div class="p-3 bg-body-secondary rounded-3 border mb-3">
|
||||
<p class="text-muted mb-0"><small>Or you can click the link below:</small>
|
||||
</p><a :href="this.l"><code style="line-break: anywhere">{{this.l}}</code></a>
|
||||
</div>
|
||||
<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 mb-2">
|
||||
<input class="form-control text-center totp"
|
||||
id="totp" maxlength="6" type="text" inputmode="numeric" autocomplete="one-time-code"
|
||||
v-model="this.totp"
|
||||
:disabled="this.verified"
|
||||
>
|
||||
<div class="invalid-feedback">
|
||||
{{this.totpInvalidMessage}}
|
||||
</div>
|
||||
<div class="valid-feedback">
|
||||
TOTP verified!
|
||||
</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>
|
||||
<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>
|
||||
|
||||
<style scoped>
|
||||
|
@ -14,6 +14,7 @@ import PeerList from "@/components/configurationComponents/peerList.vue";
|
||||
import PeerCreate from "@/components/configurationComponents/peerCreate.vue";
|
||||
import Ping from "@/views/ping.vue";
|
||||
import Traceroute from "@/views/traceroute.vue";
|
||||
import Totp from "@/components/setupComponent/totp.vue";
|
||||
|
||||
const checkAuth = async () => {
|
||||
let result = false
|
||||
@ -103,6 +104,12 @@ const router = createRouter({
|
||||
meta: {
|
||||
requiresAuth: true
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/2FASetup', component: Totp,
|
||||
meta: {
|
||||
requiresAuth: true
|
||||
},
|
||||
}
|
||||
]
|
||||
});
|
||||
|
@ -11,11 +11,13 @@ import DashboardTheme from "@/components/settingsComponent/dashboardTheme.vue";
|
||||
import DashboardSettingsInputIPAddressAndPort
|
||||
from "@/components/settingsComponent/dashboardSettingsInputIPAddressAndPort.vue";
|
||||
import DashboardAPIKeys from "@/components/settingsComponent/dashboardAPIKeys.vue";
|
||||
import AccountSettingsMFA from "@/components/settingsComponent/accountSettingsMFA.vue";
|
||||
|
||||
export default {
|
||||
name: "settings",
|
||||
methods: {ipV46RegexCheck},
|
||||
components: {
|
||||
AccountSettingsMFA,
|
||||
DashboardAPIKeys,
|
||||
DashboardSettingsInputIPAddressAndPort,
|
||||
DashboardTheme,
|
||||
@ -49,7 +51,7 @@ export default {
|
||||
<PeersDefaultSettingsInput targetData="peer_mtu" title="MTU (Max Transmission Unit)"></PeersDefaultSettingsInput>
|
||||
<PeersDefaultSettingsInput targetData="peer_keep_alive" title="Persistent Keepalive"></PeersDefaultSettingsInput>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
@ -67,14 +69,16 @@ export default {
|
||||
</div>
|
||||
<div class="card mb-4 shadow rounded-3">
|
||||
<p class="card-header">Account Settings</p>
|
||||
<div class="card-body">
|
||||
<div class="card-body d-flex gap-4 flex-column">
|
||||
<AccountSettingsInputUsername targetData="username"
|
||||
title="Username"
|
||||
></AccountSettingsInputUsername>
|
||||
<hr>
|
||||
<hr class="m-0">
|
||||
<AccountSettingsInputPassword
|
||||
targetData="password">
|
||||
</AccountSettingsInputPassword>
|
||||
<hr class="m-0">
|
||||
<AccountSettingsMFA></AccountSettingsMFA>
|
||||
</div>
|
||||
</div>
|
||||
<DashboardAPIKeys></DashboardAPIKeys>
|
||||
|
@ -1,11 +1,9 @@
|
||||
<script>
|
||||
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
|
||||
import QRCode from 'qrcode'
|
||||
import Totp from "@/components/setupComponent/totp.vue";
|
||||
import {fetchPost} from "@/utilities/fetch.js";
|
||||
export default {
|
||||
name: "setup",
|
||||
components: {Totp},
|
||||
components: {},
|
||||
setup(){
|
||||
const store = DashboardConfigurationStore();
|
||||
return {store}
|
||||
@ -16,8 +14,7 @@ export default {
|
||||
username: "",
|
||||
newPassword: "",
|
||||
repeatNewPassword: "",
|
||||
enable_totp: false,
|
||||
verified_totp: false
|
||||
enable_totp: true
|
||||
},
|
||||
loading: false,
|
||||
errorMessage: "",
|
||||
@ -30,7 +27,6 @@ export default {
|
||||
&& this.setup.newPassword.length >= 8
|
||||
&& this.setup.repeatNewPassword.length >= 8
|
||||
&& this.setup.newPassword === this.setup.repeatNewPassword
|
||||
&& ((this.setup.enable_totp && this.setup.verified_totp) || !this.setup.enable_totp)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -39,9 +35,7 @@ export default {
|
||||
fetchPost("/api/Welcome_Finish", this.setup, (res) => {
|
||||
if (res.status){
|
||||
this.done = true;
|
||||
setTimeout(() => {
|
||||
this.$router.push('/')
|
||||
}, 500)
|
||||
this.$router.push('/2FASetup')
|
||||
}else{
|
||||
document.querySelectorAll("#createAccount input").forEach(x => x.classList.add("is-invalid"))
|
||||
this.errorMessage = res.message;
|
||||
@ -62,7 +56,7 @@ export default {
|
||||
<template>
|
||||
<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="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>
|
||||
<p class="mb-5">Please fill in the following fields to finish setup 😊</p>
|
||||
<div>
|
||||
@ -94,26 +88,23 @@ export default {
|
||||
class="form-control" id="confirmPassword" name="confirmPassword" placeholder="and you can remember it :)" required>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="enable_totp"
|
||||
v-model="this.setup.enable_totp">
|
||||
<label class="form-check-label"
|
||||
for="enable_totp">Enable 2 Factor Authentication? <strong>Strongly recommended</strong></label>
|
||||
</div>
|
||||
<Suspense>
|
||||
<Transition name="fade">
|
||||
<Totp v-if="this.setup.enable_totp" @verified="this.setup.verified_totp = true"></Totp>
|
||||
</Transition>
|
||||
</Suspense>
|
||||
<!-- <div class="form-check form-switch">-->
|
||||
<!-- <input class="form-check-input" type="checkbox" role="switch" id="enable_totp" -->
|
||||
<!-- v-model="this.setup.enable_totp">-->
|
||||
<!-- <label class="form-check-label" -->
|
||||
<!-- for="enable_totp">Enable 2 Factor Authentication? <strong>Strongly recommended</strong></label>-->
|
||||
<!-- </div>-->
|
||||
<!-- <Suspense>-->
|
||||
<!-- <Transition name="fade">-->
|
||||
<!-- <Totp v-if="this.setup.enable_totp" @verified="this.setup.verified_totp = true"></Totp>-->
|
||||
<!-- </Transition>-->
|
||||
<!-- </Suspense>-->
|
||||
|
||||
<button class="btn btn-dark btn-lg mb-5 d-flex btn-brand shadow align-items-center"
|
||||
ref="signInBtn"
|
||||
: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">
|
||||
Finish<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>
|
||||
Next<i class="bi bi-chevron-right ms-auto"></i></span>
|
||||
<span class="d-flex align-items-center w-100" v-else>
|
||||
Saving...<span class="spinner-border ms-auto spinner-border-sm" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
|
Loading…
Reference in New Issue
Block a user