Implement password change function
This commit is contained in:
File diff suppressed because one or more lines are too long
9
packages/sshecret-frontend/src/api/validation.ts
Normal file
9
packages/sshecret-frontend/src/api/validation.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import type { Ref } from 'vue'
|
||||||
|
import SlInput from '@shoelace-style/shoelace/dist/components/input/input.js'
|
||||||
|
|
||||||
|
|
||||||
|
export function setFieldValidation(field: Ref<SlInput>, errorMessage: string = '') {
|
||||||
|
// Set validation on a field
|
||||||
|
field.value?.setCustomValidity(errorMessage)
|
||||||
|
field.value?.reportValidity()
|
||||||
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
// This file is auto-generated by @hey-api/openapi-ts
|
// This file is auto-generated by @hey-api/openapi-ts
|
||||||
|
|
||||||
import { type Options as ClientOptions, type TDataShape, type Client, urlSearchParamsBodySerializer } from './client';
|
import { type Options as ClientOptions, type TDataShape, type Client, urlSearchParamsBodySerializer } from './client';
|
||||||
import type { GetHealthHealthGetData, GetHealthHealthGetResponses, GetAuditLogApiV1AuditGetData, GetAuditLogApiV1AuditGetResponses, GetAuditLogApiV1AuditGetErrors, LoginForAccessTokenApiV1TokenPostData, LoginForAccessTokenApiV1TokenPostResponses, LoginForAccessTokenApiV1TokenPostErrors, RefreshTokenApiV1RefreshPostData, RefreshTokenApiV1RefreshPostResponses, RefreshTokenApiV1RefreshPostErrors, GetClientsApiV1ClientsGetData, GetClientsApiV1ClientsGetResponses, CreateClientApiV1ClientsPostData, CreateClientApiV1ClientsPostResponses, CreateClientApiV1ClientsPostErrors, GetClientsTerseApiV1ClientsTerseGetData, GetClientsTerseApiV1ClientsTerseGetResponses, QueryClientsApiV1QueryClientsGetData, QueryClientsApiV1QueryClientsGetResponses, QueryClientsApiV1QueryClientsGetErrors, DeleteClientApiV1ClientsIdDeleteData, DeleteClientApiV1ClientsIdDeleteResponses, DeleteClientApiV1ClientsIdDeleteErrors, GetClientApiV1ClientsIdGetData, GetClientApiV1ClientsIdGetResponses, GetClientApiV1ClientsIdGetErrors, UpdateClientApiV1ClientsIdPutData, UpdateClientApiV1ClientsIdPutResponses, UpdateClientApiV1ClientsIdPutErrors, DeleteSecretFromClientApiV1ClientsIdSecretsSecretNameDeleteData, DeleteSecretFromClientApiV1ClientsIdSecretsSecretNameDeleteResponses, DeleteSecretFromClientApiV1ClientsIdSecretsSecretNameDeleteErrors, AddSecretToClientApiV1ClientsIdSecretsSecretNamePutData, AddSecretToClientApiV1ClientsIdSecretsSecretNamePutResponses, AddSecretToClientApiV1ClientsIdSecretsSecretNamePutErrors, UpdateClientPoliciesApiV1ClientsIdPoliciesPutData, UpdateClientPoliciesApiV1ClientsIdPoliciesPutResponses, UpdateClientPoliciesApiV1ClientsIdPoliciesPutErrors, UpdateClientPublicKeyApiV1ClientsIdPublicKeyPutData, UpdateClientPublicKeyApiV1ClientsIdPublicKeyPutResponses, UpdateClientPublicKeyApiV1ClientsIdPublicKeyPutErrors, GetSystemStatsApiV1StatsGetData, GetSystemStatsApiV1StatsGetResponses, GetSecretNamesApiV1SecretsGetData, GetSecretNamesApiV1SecretsGetResponses, AddSecretApiV1SecretsPostData, AddSecretApiV1SecretsPostResponses, AddSecretApiV1SecretsPostErrors, DeleteSecretApiV1SecretsNameDeleteData, DeleteSecretApiV1SecretsNameDeleteResponses, DeleteSecretApiV1SecretsNameDeleteErrors, GetSecretApiV1SecretsNameGetData, GetSecretApiV1SecretsNameGetResponses, GetSecretApiV1SecretsNameGetErrors, UpdateSecretApiV1SecretsNamePutData, UpdateSecretApiV1SecretsNamePutResponses, UpdateSecretApiV1SecretsNamePutErrors, GetSecretGroupsApiV1SecretsGroupsGetData, GetSecretGroupsApiV1SecretsGroupsGetResponses, GetSecretGroupsApiV1SecretsGroupsGetErrors, AddSecretGroupApiV1SecretsGroupsPostData, AddSecretGroupApiV1SecretsGroupsPostResponses, AddSecretGroupApiV1SecretsGroupsPostErrors, DeleteSecretGroupApiV1SecretsGroupsGroupPathDeleteData, DeleteSecretGroupApiV1SecretsGroupsGroupPathDeleteResponses, DeleteSecretGroupApiV1SecretsGroupsGroupPathDeleteErrors, GetSecretGroupApiV1SecretsGroupsGroupPathGetData, GetSecretGroupApiV1SecretsGroupsGroupPathGetResponses, GetSecretGroupApiV1SecretsGroupsGroupPathGetErrors, UpdateSecretGroupApiV1SecretsGroupsGroupPathPutData, UpdateSecretGroupApiV1SecretsGroupsGroupPathPutResponses, UpdateSecretGroupApiV1SecretsGroupsGroupPathPutErrors, DeleteGroupIdApiV1SecretsGroupIdDeleteData, DeleteGroupIdApiV1SecretsGroupIdDeleteResponses, DeleteGroupIdApiV1SecretsGroupIdDeleteErrors, AssignSecretGroupApiV1SecretsSetGroupPostData, AssignSecretGroupApiV1SecretsSetGroupPostResponses, AssignSecretGroupApiV1SecretsSetGroupPostErrors, MoveGroupApiV1SecretsMoveGroupGroupNamePostData, MoveGroupApiV1SecretsMoveGroupGroupNamePostResponses, MoveGroupApiV1SecretsMoveGroupGroupNamePostErrors } from './types.gen';
|
import type { GetHealthHealthGetData, GetHealthHealthGetResponses, GetAuditLogApiV1AuditGetData, GetAuditLogApiV1AuditGetResponses, GetAuditLogApiV1AuditGetErrors, LoginForAccessTokenApiV1TokenPostData, LoginForAccessTokenApiV1TokenPostResponses, LoginForAccessTokenApiV1TokenPostErrors, RefreshTokenApiV1RefreshPostData, RefreshTokenApiV1RefreshPostResponses, RefreshTokenApiV1RefreshPostErrors, ChangePasswordApiV1PasswordPostData, ChangePasswordApiV1PasswordPostResponses, ChangePasswordApiV1PasswordPostErrors, GetClientsApiV1ClientsGetData, GetClientsApiV1ClientsGetResponses, CreateClientApiV1ClientsPostData, CreateClientApiV1ClientsPostResponses, CreateClientApiV1ClientsPostErrors, GetClientsTerseApiV1ClientsTerseGetData, GetClientsTerseApiV1ClientsTerseGetResponses, QueryClientsApiV1QueryClientsGetData, QueryClientsApiV1QueryClientsGetResponses, QueryClientsApiV1QueryClientsGetErrors, DeleteClientApiV1ClientsIdDeleteData, DeleteClientApiV1ClientsIdDeleteResponses, DeleteClientApiV1ClientsIdDeleteErrors, GetClientApiV1ClientsIdGetData, GetClientApiV1ClientsIdGetResponses, GetClientApiV1ClientsIdGetErrors, UpdateClientApiV1ClientsIdPutData, UpdateClientApiV1ClientsIdPutResponses, UpdateClientApiV1ClientsIdPutErrors, DeleteSecretFromClientApiV1ClientsIdSecretsSecretNameDeleteData, DeleteSecretFromClientApiV1ClientsIdSecretsSecretNameDeleteResponses, DeleteSecretFromClientApiV1ClientsIdSecretsSecretNameDeleteErrors, AddSecretToClientApiV1ClientsIdSecretsSecretNamePutData, AddSecretToClientApiV1ClientsIdSecretsSecretNamePutResponses, AddSecretToClientApiV1ClientsIdSecretsSecretNamePutErrors, UpdateClientPoliciesApiV1ClientsIdPoliciesPutData, UpdateClientPoliciesApiV1ClientsIdPoliciesPutResponses, UpdateClientPoliciesApiV1ClientsIdPoliciesPutErrors, UpdateClientPublicKeyApiV1ClientsIdPublicKeyPutData, UpdateClientPublicKeyApiV1ClientsIdPublicKeyPutResponses, UpdateClientPublicKeyApiV1ClientsIdPublicKeyPutErrors, GetSystemStatsApiV1StatsGetData, GetSystemStatsApiV1StatsGetResponses, GetSecretNamesApiV1SecretsGetData, GetSecretNamesApiV1SecretsGetResponses, AddSecretApiV1SecretsPostData, AddSecretApiV1SecretsPostResponses, AddSecretApiV1SecretsPostErrors, DeleteSecretApiV1SecretsNameDeleteData, DeleteSecretApiV1SecretsNameDeleteResponses, DeleteSecretApiV1SecretsNameDeleteErrors, GetSecretApiV1SecretsNameGetData, GetSecretApiV1SecretsNameGetResponses, GetSecretApiV1SecretsNameGetErrors, UpdateSecretApiV1SecretsNamePutData, UpdateSecretApiV1SecretsNamePutResponses, UpdateSecretApiV1SecretsNamePutErrors, GetSecretGroupsApiV1SecretsGroupsGetData, GetSecretGroupsApiV1SecretsGroupsGetResponses, GetSecretGroupsApiV1SecretsGroupsGetErrors, AddSecretGroupApiV1SecretsGroupsPostData, AddSecretGroupApiV1SecretsGroupsPostResponses, AddSecretGroupApiV1SecretsGroupsPostErrors, DeleteSecretGroupApiV1SecretsGroupsGroupPathDeleteData, DeleteSecretGroupApiV1SecretsGroupsGroupPathDeleteResponses, DeleteSecretGroupApiV1SecretsGroupsGroupPathDeleteErrors, GetSecretGroupApiV1SecretsGroupsGroupPathGetData, GetSecretGroupApiV1SecretsGroupsGroupPathGetResponses, GetSecretGroupApiV1SecretsGroupsGroupPathGetErrors, UpdateSecretGroupApiV1SecretsGroupsGroupPathPutData, UpdateSecretGroupApiV1SecretsGroupsGroupPathPutResponses, UpdateSecretGroupApiV1SecretsGroupsGroupPathPutErrors, DeleteGroupIdApiV1SecretsGroupIdDeleteData, DeleteGroupIdApiV1SecretsGroupIdDeleteResponses, DeleteGroupIdApiV1SecretsGroupIdDeleteErrors, AssignSecretGroupApiV1SecretsSetGroupPostData, AssignSecretGroupApiV1SecretsSetGroupPostResponses, AssignSecretGroupApiV1SecretsSetGroupPostErrors, MoveGroupApiV1SecretsMoveGroupGroupNamePostData, MoveGroupApiV1SecretsMoveGroupGroupNamePostResponses, MoveGroupApiV1SecretsMoveGroupGroupNamePostErrors } from './types.gen';
|
||||||
import { client as _heyApiClient } from './client.gen';
|
import { client as _heyApiClient } from './client.gen';
|
||||||
|
|
||||||
export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = ClientOptions<TData, ThrowOnError> & {
|
export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = ClientOptions<TData, ThrowOnError> & {
|
||||||
@ -83,6 +83,28 @@ export class SshecretAdmin {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change Password
|
||||||
|
* Change user password
|
||||||
|
*/
|
||||||
|
public static changePasswordApiV1PasswordPost<ThrowOnError extends boolean = false>(options: Options<ChangePasswordApiV1PasswordPostData, ThrowOnError>) {
|
||||||
|
return (options.client ?? _heyApiClient).post<ChangePasswordApiV1PasswordPostResponses, ChangePasswordApiV1PasswordPostErrors, ThrowOnError>({
|
||||||
|
responseType: 'json',
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
scheme: 'bearer',
|
||||||
|
type: 'http'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
url: '/api/v1/password',
|
||||||
|
...options,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
...options.headers
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Clients
|
* Get Clients
|
||||||
* Get clients.
|
* Get clients.
|
||||||
|
|||||||
@ -568,6 +568,25 @@ export type UpdatePoliciesRequest = {
|
|||||||
sources: Array<string>;
|
sources: Array<string>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UserPasswordChange
|
||||||
|
* Model for changing the password of a user.
|
||||||
|
*/
|
||||||
|
export type UserPasswordChange = {
|
||||||
|
/**
|
||||||
|
* Current Password
|
||||||
|
*/
|
||||||
|
current_password: string;
|
||||||
|
/**
|
||||||
|
* New Password
|
||||||
|
*/
|
||||||
|
new_password: string;
|
||||||
|
/**
|
||||||
|
* New Password Confirm
|
||||||
|
*/
|
||||||
|
new_password_confirm: string;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ValidationError
|
* ValidationError
|
||||||
*/
|
*/
|
||||||
@ -712,6 +731,29 @@ export type RefreshTokenApiV1RefreshPostResponses = {
|
|||||||
|
|
||||||
export type RefreshTokenApiV1RefreshPostResponse = RefreshTokenApiV1RefreshPostResponses[keyof RefreshTokenApiV1RefreshPostResponses];
|
export type RefreshTokenApiV1RefreshPostResponse = RefreshTokenApiV1RefreshPostResponses[keyof RefreshTokenApiV1RefreshPostResponses];
|
||||||
|
|
||||||
|
export type ChangePasswordApiV1PasswordPostData = {
|
||||||
|
body: UserPasswordChange;
|
||||||
|
path?: never;
|
||||||
|
query?: never;
|
||||||
|
url: '/api/v1/password';
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ChangePasswordApiV1PasswordPostErrors = {
|
||||||
|
/**
|
||||||
|
* Validation Error
|
||||||
|
*/
|
||||||
|
422: HttpValidationError;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ChangePasswordApiV1PasswordPostError = ChangePasswordApiV1PasswordPostErrors[keyof ChangePasswordApiV1PasswordPostErrors];
|
||||||
|
|
||||||
|
export type ChangePasswordApiV1PasswordPostResponses = {
|
||||||
|
/**
|
||||||
|
* Successful Response
|
||||||
|
*/
|
||||||
|
200: unknown;
|
||||||
|
};
|
||||||
|
|
||||||
export type GetClientsApiV1ClientsGetData = {
|
export type GetClientsApiV1ClientsGetData = {
|
||||||
body?: never;
|
body?: never;
|
||||||
path?: never;
|
path?: never;
|
||||||
|
|||||||
@ -0,0 +1,113 @@
|
|||||||
|
<template>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<form @submit.prevent="changePassword" ref="passwordChangeForm">
|
||||||
|
<sl-input
|
||||||
|
label="Current password"
|
||||||
|
type="password"
|
||||||
|
autocomplete="current-password"
|
||||||
|
placeholder="Current Password"
|
||||||
|
required
|
||||||
|
help-text="Enter your current password"
|
||||||
|
:value="currentPassword"
|
||||||
|
@input="checkCurrent"
|
||||||
|
@sl-input="currentPassword = $event.target.value"
|
||||||
|
ref="currentPasswordField"
|
||||||
|
password-toggle
|
||||||
|
></sl-input>
|
||||||
|
<sl-input
|
||||||
|
label="New Password"
|
||||||
|
type="password"
|
||||||
|
required
|
||||||
|
placeholder="New Password"
|
||||||
|
autocomplete="new-password"
|
||||||
|
help-text="Enter your new password"
|
||||||
|
:value="newPassword"
|
||||||
|
@sl-input="newPassword = $event.target.value"
|
||||||
|
ref="newPasswordField"
|
||||||
|
password-toggle
|
||||||
|
></sl-input>
|
||||||
|
<sl-input
|
||||||
|
label="New Password (repeat)"
|
||||||
|
type="password"
|
||||||
|
required
|
||||||
|
placeholder="New Password"
|
||||||
|
autocomplete="new-password"
|
||||||
|
help-text="Confirm your new password by typing it again"
|
||||||
|
:value="newPasswordConfirm"
|
||||||
|
@sl-input="newPasswordConfirm = $event.target.value"
|
||||||
|
@blur="checkPasswords"
|
||||||
|
ref="newPasswordFieldConfirm"
|
||||||
|
password-toggle
|
||||||
|
></sl-input>
|
||||||
|
<sl-button class="mr-4" type="submit" variant="primary">Change Password</sl-button>
|
||||||
|
<sl-button variant="default" @click="cancelChangePassword">Cancel</sl-button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { useAlertsStore } from '@/store/useAlertsStore'
|
||||||
|
import { SshecretAdmin } from '@/client'
|
||||||
|
import type { UserPasswordChange } from '@/client'
|
||||||
|
import { assertSdkResponseOk } from '@/api/assertSdkResponseOk'
|
||||||
|
import { ApiError, ValidationError } from '@/api/errors'
|
||||||
|
import { setFieldValidation } from '@/api/validation'
|
||||||
|
|
||||||
|
const currentPassword = ref<string>('')
|
||||||
|
const newPassword = ref<string>('')
|
||||||
|
const newPasswordConfirm = ref<string>('')
|
||||||
|
|
||||||
|
const passwordChangeForm = ref<HTMLFormElement>()
|
||||||
|
const currentPasswordField = ref<SlInput>()
|
||||||
|
const newPasswordField = ref<SlInput>()
|
||||||
|
const newPasswordFieldConfirm = ref<Slinput>()
|
||||||
|
|
||||||
|
const alerts = useAlertsStore()
|
||||||
|
|
||||||
|
const emit = defineEmits<{ (e: 'changed'): void; (e: 'cancel'): void }>()
|
||||||
|
|
||||||
|
function checkCurrent() {
|
||||||
|
setFieldValidation(currentPasswordField)
|
||||||
|
currentPasswordField.value.reportValidity()
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkPasswords() {
|
||||||
|
if (newPassword.value !== newPasswordConfirm.value) {
|
||||||
|
setFieldValidation(newPasswordFieldConfirm, 'Passwords do not match match')
|
||||||
|
} else {
|
||||||
|
setFieldValidation(newPasswordFieldConfirm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetForm() {
|
||||||
|
passwordChangeForm.value?.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelChangePassword() {
|
||||||
|
resetForm()
|
||||||
|
emit('cancel')
|
||||||
|
}
|
||||||
|
async function changePassword() {
|
||||||
|
const data: UserPasswordChange = {
|
||||||
|
current_password: currentPassword.value,
|
||||||
|
new_password: newPassword.value,
|
||||||
|
new_password_confirm: newPasswordConfirm.value,
|
||||||
|
}
|
||||||
|
const response = await SshecretAdmin.changePasswordApiV1PasswordPost({ body: data })
|
||||||
|
try {
|
||||||
|
assertSdkResponseOk(response)
|
||||||
|
emit('changed')
|
||||||
|
resetForm()
|
||||||
|
} catch (err) {
|
||||||
|
if (err instanceof ValidationError) {
|
||||||
|
// This should be caught in js, but we might as well
|
||||||
|
setFieldValidation(newPasswordFieldConfirm, 'Passwords do not match match')
|
||||||
|
} else if (err instanceof ApiError && err.message.includes('Invalid current password')) {
|
||||||
|
setFieldValidation(currentPasswordField, 'Invalid current password')
|
||||||
|
} else {
|
||||||
|
alerts.showAlert(err.message, 'error', 'Error changing password')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -69,11 +69,8 @@ import type { Ref } from 'vue'
|
|||||||
import { isIP } from 'is-ip'
|
import { isIP } from 'is-ip'
|
||||||
import isCidr from 'is-cidr'
|
import isCidr from 'is-cidr'
|
||||||
|
|
||||||
import '@shoelace-style/shoelace/dist/components/button/button.js'
|
import { setFieldValidation } from '@/api/validation'
|
||||||
import '@shoelace-style/shoelace/dist/components/input/input.js'
|
|
||||||
import '@shoelace-style/shoelace/dist/components/icon-button/icon-button.js'
|
|
||||||
import '@shoelace-style/shoelace/dist/components/tag/tag.js'
|
|
||||||
import '@shoelace-style/shoelace/dist/components/textarea/textarea.js'
|
|
||||||
import type { ClientCreate } from '@/client/types.gen'
|
import type { ClientCreate } from '@/client/types.gen'
|
||||||
|
|
||||||
const name = ref('')
|
const name = ref('')
|
||||||
@ -111,12 +108,6 @@ watch(
|
|||||||
{ immediate: true },
|
{ immediate: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
function setFieldValidation(field: Ref<HTMLSlInputElement>, errorMessage: string = '') {
|
|
||||||
// Set validation on a field
|
|
||||||
field.value?.setCustomValidity(errorMessage)
|
|
||||||
field.value?.reportValidity()
|
|
||||||
}
|
|
||||||
|
|
||||||
function addPolicy() {
|
function addPolicy() {
|
||||||
if (!sourcePrefix.value) {
|
if (!sourcePrefix.value) {
|
||||||
setFieldValidation(sourceField)
|
setFieldValidation(sourceField)
|
||||||
|
|||||||
@ -69,6 +69,7 @@ import isCidr from 'is-cidr'
|
|||||||
import { assertSdkResponseOk } from '@/api/AssertSdkResponseOk'
|
import { assertSdkResponseOk } from '@/api/AssertSdkResponseOk'
|
||||||
import type { ClientCreate } from '@/client/types.gen'
|
import type { ClientCreate } from '@/client/types.gen'
|
||||||
import { SshecretAdmin } from '@/client/sdk.gen'
|
import { SshecretAdmin } from '@/client/sdk.gen'
|
||||||
|
import { setFieldValidation } from '@/api/validation'
|
||||||
|
|
||||||
const name = ref('')
|
const name = ref('')
|
||||||
const description = ref('')
|
const description = ref('')
|
||||||
@ -81,12 +82,6 @@ const sourceField = ref<HTMLSlInputElement>()
|
|||||||
const publicKeyField = ref<HTMLSlInputElement>()
|
const publicKeyField = ref<HTMLSlInputElement>()
|
||||||
const clientCreateForm = ref<HTMLElement>()
|
const clientCreateForm = ref<HTMLElement>()
|
||||||
|
|
||||||
function setFieldValidation(field: Ref<HTMLSlInputElement>, errorMessage: string = '') {
|
|
||||||
// Set validation on a field
|
|
||||||
field.value?.setCustomValidity(errorMessage)
|
|
||||||
field.value?.reportValidity()
|
|
||||||
}
|
|
||||||
|
|
||||||
function addPolicy() {
|
function addPolicy() {
|
||||||
if (!sourcePrefix.value) {
|
if (!sourcePrefix.value) {
|
||||||
setFieldValidation(sourceField)
|
setFieldValidation(sourceField)
|
||||||
|
|||||||
@ -15,44 +15,43 @@
|
|||||||
<sl-button variant="default" size="small" circle slot="trigger">
|
<sl-button variant="default" size="small" circle slot="trigger">
|
||||||
<sl-avatar label="User avatar"></sl-avatar>
|
<sl-avatar label="User avatar"></sl-avatar>
|
||||||
</sl-button>
|
</sl-button>
|
||||||
<sl-menu-item>
|
<sl-menu>
|
||||||
<a
|
<sl-menu-item>{{ auth.username }}</sl-menu-item>
|
||||||
href="#"
|
<sl-divider></sl-divider>
|
||||||
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white"
|
<sl-menu-item @click="showDrawer">Change Password</sl-menu-item>
|
||||||
role="menuitem"
|
<sl-menu-item @click="logout"> Logout </sl-menu-item>
|
||||||
>Change Password</a
|
</sl-menu>
|
||||||
>
|
|
||||||
</sl-menu-item>
|
|
||||||
<sl-menu-item>
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white"
|
|
||||||
role="menuitem"
|
|
||||||
@click="logout"
|
|
||||||
>Logout</a
|
|
||||||
>
|
|
||||||
</sl-menu-item>
|
|
||||||
</sl-dropdown>
|
</sl-dropdown>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
<Drawer label="Change Password" :open="showPasswordDrawer" @hide="showPasswordDrawer = false">
|
||||||
|
<ChangePassword @changed="logout" @cancel="showPasswordDrawer = false" />
|
||||||
|
</Drawer>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import '@shoelace-style/shoelace/dist/components/button/button.js'
|
|
||||||
import '@shoelace-style/shoelace/dist/components/icon/icon.js'
|
|
||||||
import '@shoelace-style/shoelace/dist/components/icon-button/icon-button.js'
|
|
||||||
import '@shoelace-style/shoelace/dist/components/dropdown/dropdown.js'
|
|
||||||
import '@shoelace-style/shoelace/dist/components/avatar/avatar.js'
|
|
||||||
|
|
||||||
import { useAuthTokenStore } from '@/store/auth'
|
import { useAuthTokenStore } from '@/store/auth'
|
||||||
|
import Drawer from '@/components/common/Drawer.vue'
|
||||||
|
import Dialog from '@/components/common/Dialog.vue'
|
||||||
|
import ChangePassword from '@/components/auth/ChangePassword.vue'
|
||||||
|
|
||||||
const auth = useAuthTokenStore()
|
const auth = useAuthTokenStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
|
const showPasswordDrawer = ref<boolean>(false)
|
||||||
|
|
||||||
function logout() {
|
function logout() {
|
||||||
auth.logout()
|
auth.logout()
|
||||||
router.push('/login')
|
router.push('/login')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showDrawer() {
|
||||||
|
showPasswordDrawer.value = true
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@ -63,6 +63,7 @@ import { ref } from 'vue'
|
|||||||
import { generateRandomPassword } from '@/api/password'
|
import { generateRandomPassword } from '@/api/password'
|
||||||
import AddSecretsToClients from '@/components/secrets/AddSecretToClients.vue'
|
import AddSecretsToClients from '@/components/secrets/AddSecretToClients.vue'
|
||||||
import ClientSelectDropdown from '@/components/clients/ClientSelectDropdown.vue'
|
import ClientSelectDropdown from '@/components/clients/ClientSelectDropdown.vue'
|
||||||
|
import { setFieldValidation } from '@/api/validation'
|
||||||
|
|
||||||
const props = defineProps<{ group?: string }>()
|
const props = defineProps<{ group?: string }>()
|
||||||
|
|
||||||
@ -77,12 +78,6 @@ const secretLength = ref(8)
|
|||||||
const autoGenerate = ref(false)
|
const autoGenerate = ref(false)
|
||||||
const selectedClients = ref<string[]>()
|
const selectedClients = ref<string[]>()
|
||||||
|
|
||||||
function setFieldValidation(field: Ref<HTMLSlInputElement>, errorMessage: string = '') {
|
|
||||||
// Set validation on a field
|
|
||||||
field.value?.setCustomValidity(errorMessage)
|
|
||||||
field.value?.reportValidity()
|
|
||||||
}
|
|
||||||
|
|
||||||
function generatePassword() {
|
function generatePassword() {
|
||||||
const password = generateRandomPassword(secretLength.value)
|
const password = generateRandomPassword(secretLength.value)
|
||||||
secretValue.value = password
|
secretValue.value = password
|
||||||
|
|||||||
@ -15,6 +15,7 @@ export const useAuthTokenStore = defineStore('authtoken', {
|
|||||||
accessToken: '' as string,
|
accessToken: '' as string,
|
||||||
refreshToken: '' as string,
|
refreshToken: '' as string,
|
||||||
isLoggedIn: false,
|
isLoggedIn: false,
|
||||||
|
username: '' as string,
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
async login(username: string, password: string): Promise<boolean> {
|
async login(username: string, password: string): Promise<boolean> {
|
||||||
@ -28,6 +29,7 @@ export const useAuthTokenStore = defineStore('authtoken', {
|
|||||||
this.isLoggedIn = true
|
this.isLoggedIn = true
|
||||||
localStorage.setItem('accessToken', accessToken)
|
localStorage.setItem('accessToken', accessToken)
|
||||||
localStorage.setItem('refreshToken', refreshToken)
|
localStorage.setItem('refreshToken', refreshToken)
|
||||||
|
localStorage.setItem('username', username)
|
||||||
setAuthToken(this.accessToken)
|
setAuthToken(this.accessToken)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -59,9 +61,11 @@ export const useAuthTokenStore = defineStore('authtoken', {
|
|||||||
// Load token from user storage.
|
// Load token from user storage.
|
||||||
const accessToken = localStorage.getItem('accessToken')
|
const accessToken = localStorage.getItem('accessToken')
|
||||||
const refreshToken = localStorage.getItem('refreshToken')
|
const refreshToken = localStorage.getItem('refreshToken')
|
||||||
if (accessToken && refreshToken) {
|
const username = localStorage.getItem('username')
|
||||||
|
if (accessToken && refreshToken && username) {
|
||||||
this.accessToken = accessToken
|
this.accessToken = accessToken
|
||||||
this.refreshToken = refreshToken
|
this.refreshToken = refreshToken
|
||||||
|
this.username = username
|
||||||
this.isLoggedIn = true
|
this.isLoggedIn = true
|
||||||
setAuthToken(accessToken)
|
setAuthToken(accessToken)
|
||||||
}
|
}
|
||||||
@ -69,6 +73,7 @@ export const useAuthTokenStore = defineStore('authtoken', {
|
|||||||
logout() {
|
logout() {
|
||||||
this.accessToken = ''
|
this.accessToken = ''
|
||||||
this.refreshToken = ''
|
this.refreshToken = ''
|
||||||
|
this.username = ''
|
||||||
this.isLoggedIn = false
|
this.isLoggedIn = false
|
||||||
localStorage.removeItem('accessToken')
|
localStorage.removeItem('accessToken')
|
||||||
localStorage.removeItem('refreshToken')
|
localStorage.removeItem('refreshToken')
|
||||||
|
|||||||
Reference in New Issue
Block a user