1
0
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:
Donald Zou 2024-08-05 15:39:11 -04:00
parent bd71b6bad8
commit 0fdef6a0a2
8 changed files with 195 additions and 86 deletions

View File

@ -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)

View File

@ -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

File diff suppressed because one or more lines are too long

View File

@ -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>

View File

@ -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>

View File

@ -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
},
}
]
});

View File

@ -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>

View File

@ -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>