mirror of
https://github.com/donaldzou/WGDashboard.git
synced 2025-06-28 17:26:56 +00:00
Added update password in settings
This commit is contained in:
parent
d80eb03707
commit
6f848e3df8
@ -106,4 +106,12 @@ def createClientBlueprint(wireguardConfigurations: dict[WireguardConfiguration],
|
|||||||
def ClientAPI_Settings_GetClientProfile():
|
def ClientAPI_Settings_GetClientProfile():
|
||||||
return ResponseObject(data=DashboardClients.GetClientProfile(session['ClientID']))
|
return ResponseObject(data=DashboardClients.GetClientProfile(session['ClientID']))
|
||||||
|
|
||||||
|
@client.post(f'{prefix}/api/settings/updatePassword')
|
||||||
|
@login_required
|
||||||
|
def ClientAPI_Settings_UpdatePassword():
|
||||||
|
data = request.json
|
||||||
|
status, message = DashboardClients.UpdateClientPassword(session['Email'], **data)
|
||||||
|
|
||||||
|
return ResponseObject(status, message)
|
||||||
|
|
||||||
return client
|
return client
|
@ -10,7 +10,6 @@ from .DashboardClientsPeerAssignment import DashboardClientsPeerAssignment
|
|||||||
from .DashboardClientsTOTP import DashboardClientsTOTP
|
from .DashboardClientsTOTP import DashboardClientsTOTP
|
||||||
from .Utilities import ValidatePasswordStrength
|
from .Utilities import ValidatePasswordStrength
|
||||||
from .DashboardLogger import DashboardLogger
|
from .DashboardLogger import DashboardLogger
|
||||||
|
|
||||||
from flask import session
|
from flask import session
|
||||||
|
|
||||||
|
|
||||||
@ -70,20 +69,33 @@ class DashboardClients:
|
|||||||
)
|
)
|
||||||
).mappings().fetchone())
|
).mappings().fetchone())
|
||||||
|
|
||||||
def SignIn(self, Email, Password) -> tuple[bool, str]:
|
def SignIn_ValidatePassword(self, Email, Password) -> bool:
|
||||||
if not all([Email, Password]):
|
if not all([Email, Password]):
|
||||||
return False, "Please fill in all fields"
|
return False
|
||||||
|
existingClient = self.SignIn_UserExistence(Email)
|
||||||
|
if existingClient:
|
||||||
|
return bcrypt.checkpw(Password.encode("utf-8"), existingClient.get("Password").encode("utf-8"))
|
||||||
|
return False
|
||||||
|
|
||||||
|
def SignIn_UserExistence(self, Email):
|
||||||
with self.engine.connect() as conn:
|
with self.engine.connect() as conn:
|
||||||
existingClient = conn.execute(
|
existingClient = conn.execute(
|
||||||
self.dashboardClientsTable.select().where(
|
self.dashboardClientsTable.select().where(
|
||||||
self.dashboardClientsTable.c.Email == Email
|
self.dashboardClientsTable.c.Email == Email
|
||||||
)
|
)
|
||||||
).mappings().fetchone()
|
).mappings().fetchone()
|
||||||
if existingClient:
|
return existingClient
|
||||||
checkPwd = bcrypt.checkpw(Password.encode("utf-8"), existingClient.get("Password").encode("utf-8"))
|
|
||||||
if checkPwd:
|
def SignIn(self, Email, Password) -> tuple[bool, str]:
|
||||||
session['ClientID'] = existingClient.get("ClientID")
|
if not all([Email, Password]):
|
||||||
return True, self.DashboardClientsTOTP.GenerateToken(existingClient.get("ClientID"))
|
return False, "Please fill in all fields"
|
||||||
|
existingClient = self.SignIn_UserExistence(Email)
|
||||||
|
if existingClient:
|
||||||
|
checkPwd = self.SignIn_ValidatePassword(Email, Password)
|
||||||
|
if checkPwd:
|
||||||
|
session['Email'] = Email
|
||||||
|
session['ClientID'] = existingClient.get("ClientID")
|
||||||
|
return True, self.DashboardClientsTOTP.GenerateToken(existingClient.get("ClientID"))
|
||||||
return False, "Email or Password is incorrect"
|
return False, "Email or Password is incorrect"
|
||||||
|
|
||||||
def SignIn_GetTotp(self, Token: str, UserProvidedTotp: str = None) -> tuple[bool, str] or tuple[bool, None, str]:
|
def SignIn_GetTotp(self, Token: str, UserProvidedTotp: str = None) -> tuple[bool, str] or tuple[bool, None, str]:
|
||||||
@ -120,14 +132,9 @@ class DashboardClients:
|
|||||||
if Password != ConfirmPassword:
|
if Password != ConfirmPassword:
|
||||||
return False, "Passwords does not match"
|
return False, "Passwords does not match"
|
||||||
|
|
||||||
with self.engine.connect() as conn:
|
existingClient = self.SignIn_UserExistence(Email)
|
||||||
existingClient = conn.execute(
|
if existingClient:
|
||||||
self.dashboardClientsTable.select().where(
|
return False, "Email already signed up"
|
||||||
self.dashboardClientsTable.c.Email == Email
|
|
||||||
)
|
|
||||||
).mappings().fetchone()
|
|
||||||
if existingClient:
|
|
||||||
return False, "Email already signed up"
|
|
||||||
|
|
||||||
pwStrength, msg = ValidatePasswordStrength(Password)
|
pwStrength, msg = ValidatePasswordStrength(Password)
|
||||||
if not pwStrength:
|
if not pwStrength:
|
||||||
@ -150,6 +157,7 @@ class DashboardClients:
|
|||||||
"ClientID": newClientUUID
|
"ClientID": newClientUUID
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
self.logger.log(Message=f"User {Email} signed up")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.log(Status="false", Message=f"Signed up failed, reason: {str(e)}")
|
self.logger.log(Status="false", Message=f"Signed up failed, reason: {str(e)}")
|
||||||
return False, "Signed up failed."
|
return False, "Signed up failed."
|
||||||
@ -159,5 +167,30 @@ class DashboardClients:
|
|||||||
def GetClientAssignedPeers(self, ClientID):
|
def GetClientAssignedPeers(self, ClientID):
|
||||||
return self.DashboardClientsPeerAssignment.GetAssignedPeers(ClientID)
|
return self.DashboardClientsPeerAssignment.GetAssignedPeers(ClientID)
|
||||||
|
|
||||||
def UpdatePassword(self, CurrentPassword, NewPassword, ConfirmNewPassword):
|
def UpdateClientPassword(self, Email, CurrentPassword, NewPassword, ConfirmNewPassword):
|
||||||
pass
|
if not all([CurrentPassword, NewPassword, ConfirmNewPassword]):
|
||||||
|
return False, "Please fill in all fields"
|
||||||
|
|
||||||
|
if not self.SignIn_ValidatePassword(Email, CurrentPassword):
|
||||||
|
return False, "Current password does not match"
|
||||||
|
|
||||||
|
if NewPassword != ConfirmNewPassword:
|
||||||
|
return False, "New passwords does not match"
|
||||||
|
|
||||||
|
pwStrength, msg = ValidatePasswordStrength(NewPassword)
|
||||||
|
if not pwStrength:
|
||||||
|
return pwStrength, msg
|
||||||
|
try:
|
||||||
|
with self.engine.begin() as conn:
|
||||||
|
conn.execute(
|
||||||
|
self.dashboardClientsTable.update().values({
|
||||||
|
"Password": bcrypt.hashpw(NewPassword.encode('utf-8'), bcrypt.gensalt()).decode("utf-8"),
|
||||||
|
}).where(
|
||||||
|
self.dashboardClientsTable.c.Email == Email
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.logger.log(Message=f"User {Email} updated password")
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.log(Status="false", Message=f"Signed up failed, reason: {str(e)}")
|
||||||
|
return False, "Signed up failed."
|
||||||
|
return True, None
|
@ -9,7 +9,6 @@ import { createPinia } from 'pinia'
|
|||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import router from './router/router.js'
|
import router from './router/router.js'
|
||||||
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
|
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
|
||||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
|
||||||
let Locale;
|
let Locale;
|
||||||
await fetch("/api/locale")
|
await fetch("/api/locale")
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
|
@ -1,69 +1,26 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {clientStore} from "@/stores/clientStore.js";
|
import {clientStore} from "@/stores/clientStore.js";
|
||||||
import {reactive} from "vue";
|
|
||||||
const store = clientStore()
|
const store = clientStore()
|
||||||
const ProfileLabels = {
|
const ProfileLabels = {
|
||||||
Firstname: "First Name",
|
Firstname: "First Name",
|
||||||
Lastname: "Last Name"
|
Lastname: "Last Name"
|
||||||
}
|
}
|
||||||
const Password = reactive({
|
|
||||||
CurrentPassword: "",
|
|
||||||
NewPassword: "",
|
|
||||||
RepeatNewPassword: ""
|
|
||||||
})
|
|
||||||
|
|
||||||
const ResetPasswordFields = () => {
|
|
||||||
Password.CurrentPassword = ""
|
|
||||||
Password.NewPassword = ""
|
|
||||||
Password.RepeatNewPassword = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="d-flex flex-column gap-4 p-3">
|
<div class="p-3">
|
||||||
<div>
|
<h5>
|
||||||
<h5>
|
Profile
|
||||||
Profile
|
</h5>
|
||||||
</h5>
|
<div class="row g-2">
|
||||||
<div class="row g-2">
|
<div class="col-sm-6" v-for="(val, key) in store.clientProfile.Profile">
|
||||||
<div class="col-sm-6" v-for="(val, key) in store.clientProfile.Profile">
|
<label :for="key" class="text-muted form-label">
|
||||||
<label :for="key" class="text-muted form-label">
|
<small>{{ ProfileLabels[key] }}</small>
|
||||||
<small>{{ ProfileLabels[key] }}</small>
|
</label>
|
||||||
</label>
|
<input :id="key" class="form-control rounded-3" v-model="store.clientProfile.Profile[key]">
|
||||||
<input :id="key" class="form-control rounded-3" v-model="store.clientProfile.Profile[key]">
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form @submit="undefined" @reset="ResetPasswordFields()">
|
|
||||||
<h5>
|
|
||||||
Update Password
|
|
||||||
</h5>
|
|
||||||
<div class="row g-2 mb-3">
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<label class="text-muted form-label" for="CurrentPassword">
|
|
||||||
<small>Current Password</small>
|
|
||||||
</label>
|
|
||||||
<input class="form-control rounded-3" type="password" autocomplete="current-password" id="CurrentPassword" v-model="Password.CurrentPassword">
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<label class="text-muted form-label" for="NewPassword">
|
|
||||||
<small>New Password</small>
|
|
||||||
</label>
|
|
||||||
<input class="form-control rounded-3" type="password" id="NewPassword" autocomplete="new-password" v-model="Password.NewPassword">
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<label class="text-muted form-label" for="RepeatNewPassword">
|
|
||||||
<small>Repeat New Password</small>
|
|
||||||
</label>
|
|
||||||
<input class="form-control rounded-3" type="password" id="RepeatNewPassword" autocomplete="new-password" v-model="Password.RepeatNewPassword">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex gap-2">
|
|
||||||
<button class="btn btn-sm btn-secondary rounded-3 ms-auto" type="reset">Clear</button>
|
|
||||||
<button class="btn btn-sm btn-danger rounded-3" type="submit">Update</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
102
src/static/client/src/components/Settings/updatePassword.vue
Normal file
102
src/static/client/src/components/Settings/updatePassword.vue
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
<script setup>
|
||||||
|
import {reactive, ref} from "vue";
|
||||||
|
import {axiosPost} from "@/utilities/request.js";
|
||||||
|
import {clientStore} from "@/stores/clientStore.js";
|
||||||
|
|
||||||
|
const Password = reactive({
|
||||||
|
CurrentPassword: "",
|
||||||
|
NewPassword: "",
|
||||||
|
ConfirmNewPassword: ""
|
||||||
|
})
|
||||||
|
|
||||||
|
const ResetPasswordFields = () => {
|
||||||
|
Password.CurrentPassword = ""
|
||||||
|
Password.NewPassword = ""
|
||||||
|
Password.ConfirmNewPassword = ""
|
||||||
|
}
|
||||||
|
const store = clientStore()
|
||||||
|
const UpdatePassword = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
document.querySelectorAll("#updatePasswordForm input").forEach(x => x.blur())
|
||||||
|
const data = await axiosPost('/api/settings/updatePassword', Password)
|
||||||
|
if(data){
|
||||||
|
if (!data.status){
|
||||||
|
formInvalid.value = true;
|
||||||
|
formInvalidMessage.value = data.message;
|
||||||
|
}else{
|
||||||
|
formInvalid.value = false
|
||||||
|
store.newNotification("Password updated!", "success")
|
||||||
|
ResetPasswordFields()
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
formInvalid.value = true;
|
||||||
|
formInvalidMessage.value = "Error occurred"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const showPassword = ref(false)
|
||||||
|
const formInvalid = ref(false)
|
||||||
|
const formInvalidMessage = ref("")
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form @submit="(e) => UpdatePassword(e)"
|
||||||
|
id="updatePasswordForm"
|
||||||
|
@reset="ResetPasswordFields()" class="p-3">
|
||||||
|
<div class="d-flex align-items-start">
|
||||||
|
<h5>
|
||||||
|
Update Password
|
||||||
|
</h5>
|
||||||
|
<a role="button"
|
||||||
|
@click="showPassword = !showPassword"
|
||||||
|
class="text-muted ms-auto text-decoration-none">
|
||||||
|
<small>
|
||||||
|
<i
|
||||||
|
:class="[showPassword ? 'bi-eye-slash-fill':'bi-eye-fill']"
|
||||||
|
class="bi me-2"></i>{{ showPassword ? 'Hide':'Show'}} Password
|
||||||
|
</small>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="alert alert-danger rounded-3 mt-3" v-if="formInvalid">
|
||||||
|
{{ formInvalidMessage }}
|
||||||
|
</div>
|
||||||
|
<div class="row g-2 mb-3">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<label
|
||||||
|
class="text-muted form-label" for="CurrentPassword">
|
||||||
|
<small>Current Password</small>
|
||||||
|
</label>
|
||||||
|
<input class="form-control rounded-3" :class="{'is-invalid': formInvalid}" required
|
||||||
|
:type="showPassword ? 'text':'password'" autocomplete="current-password" id="CurrentPassword" v-model="Password.CurrentPassword">
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<label class="text-muted form-label" for="NewPassword">
|
||||||
|
<small>New Password</small>
|
||||||
|
</label>
|
||||||
|
<input class="form-control rounded-3"
|
||||||
|
required
|
||||||
|
:class="{'is-invalid': formInvalid}"
|
||||||
|
:type="showPassword ? 'text':'password'"
|
||||||
|
id="NewPassword" autocomplete="new-password" v-model="Password.NewPassword">
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<label class="text-muted form-label" for="ConfirmNewPassword">
|
||||||
|
<small>Confirm New Password</small>
|
||||||
|
</label>
|
||||||
|
<input class="form-control rounded-3"
|
||||||
|
required
|
||||||
|
:class="{'is-invalid': formInvalid}"
|
||||||
|
:type="showPassword ? 'text':'password'"
|
||||||
|
id="ConfirmNewPassword" autocomplete="new-password" v-model="Password.ConfirmNewPassword">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex gap-2">
|
||||||
|
<button class="btn btn-sm btn-secondary rounded-3 ms-auto" type="reset">Clear</button>
|
||||||
|
<button class="btn btn-sm btn-danger rounded-3" type="submit">Update</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -6,18 +6,12 @@ import Configuration from "@/components/Configuration/configuration.vue";
|
|||||||
const store = clientStore()
|
const store = clientStore()
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
|
|
||||||
const loadConfigurations = async () => {
|
|
||||||
|
|
||||||
await store.getConfigurations()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const configurations = computed(() => {
|
const configurations = computed(() => {
|
||||||
return store.configurations
|
return store.configurations
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await loadConfigurations();
|
await store.getConfigurations()
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<script setup async>
|
<script setup async>
|
||||||
import {clientStore} from "@/stores/clientStore.js";
|
import {clientStore} from "@/stores/clientStore.js";
|
||||||
import Profile from "@/components/Settings/profile.vue";
|
import Profile from "@/components/Settings/profile.vue";
|
||||||
|
import UpdatePassword from "@/components/Settings/updatePassword.vue";
|
||||||
const store = clientStore()
|
const store = clientStore()
|
||||||
|
|
||||||
await store.getClientProfile();
|
await store.getClientProfile();
|
||||||
@ -16,6 +17,7 @@ await store.getClientProfile();
|
|||||||
<strong class="ms-auto">Settings</strong>
|
<strong class="ms-auto">Settings</strong>
|
||||||
</div>
|
</div>
|
||||||
<Profile></Profile>
|
<Profile></Profile>
|
||||||
|
<UpdatePassword></UpdatePassword>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user