Skip to content

Commit

Permalink
Merge pull request #1881 from nordic-institute/XRDDEV-2531
Browse files Browse the repository at this point in the history
fix: Security server edit token view crashes when refreshing page
  • Loading branch information
mikkbachmann authored Dec 8, 2023
2 parents 95fd4a6 + 9e5580c commit 4fb1d38
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 60 deletions.
8 changes: 6 additions & 2 deletions src/security-server/admin-service/ui/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,16 @@ import '@fontsource/open-sans';
import '@niis/shared-ui/dist/style.css';
import i18n from './plugins/i18n';
import { createPinia } from 'pinia';
import piniaPluginPersistedState from 'pinia-plugin-persistedstate';
import { createPersistedState } from 'pinia-plugin-persistedstate';
import { createFilters } from '@/filters';
import { createValidators } from '@/plugins/vee-validate';

const pinia = createPinia();
pinia.use(piniaPluginPersistedState);
pinia.use(
createPersistedState({
storage: sessionStorage,
}),
);

axios.defaults.baseURL = import.meta.env.VITE_VUE_APP_BASE_URL;
axios.defaults.headers.get.Accepts = 'application/json';
Expand Down
64 changes: 54 additions & 10 deletions src/security-server/admin-service/ui/src/store/modules/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ export const useServices = defineStore('services', {
serviceDescriptions: [],
};
},
persist: {
paths: ['service', 'serviceClients', 'serviceDescriptions'],
},
getters: {
descExpanded: (state) => (id: string) => {
return state.expandedServiceDescriptions.includes(id);
Expand Down Expand Up @@ -94,16 +97,7 @@ export const useServices = defineStore('services', {
},

setService(service: Service) {
service.endpoints = service.endpoints?.sort(
(a: Endpoint, b: Endpoint) => {
const sortByGenerated =
a.generated === b.generated ? 0 : a.generated ? -1 : 1;
const sortByPathSlashCount =
a.path.split('/').length - b.path.split('/').length;
const sortByPathLength = a.path.length - b.path.length;
return sortByGenerated || sortByPathSlashCount || sortByPathLength;
},
);
service.endpoints = sortEndpoints(service.endpoints);
this.service = service;
},

Expand All @@ -126,5 +120,55 @@ export const useServices = defineStore('services', {
throw error;
});
},
deleteEndpoint(id: string) {
return api
.remove(`/endpoints/${encodePathParameter(id)}`)
.then((res) => {
this.service.endpoints?.forEach((item, index) => {
if (item.id === id) {
this.service.endpoints?.splice(index, 1);
}
});
})
.catch((error) => {
throw error;
});
},
updateEndpoint(endpoint: Endpoint) {
if (!endpoint.id) {
throw new Error('Unable to save endpoint: Endpoint id not defined!');
}
return api
.patch<Endpoint>(
`/endpoints/${encodePathParameter(endpoint.id)}`,
endpoint,
)
.then((res) => {
if (this.service.endpoints) {
const endpointIndex = this.service.endpoints.findIndex(
(e) => e.id === endpoint.id,
);
if (endpointIndex) {
const endpoints = [...this.service.endpoints];
endpoints[endpointIndex] = res.data;
this.service.endpoints = sortEndpoints(endpoints);
}
}
})
.catch((error) => {
throw error;
});
},
},
});

function sortEndpoints(endpoints: Endpoint[] | undefined) {
return endpoints?.sort((a: Endpoint, b: Endpoint) => {
const sortByGenerated =
a.generated === b.generated ? 0 : a.generated ? -1 : 1;
const sortByPathSlashCount =
a.path.split('/').length - b.path.split('/').length;
const sortByPathLength = a.path.length - b.path.length;
return sortByGenerated || sortByPathSlashCount || sortByPathLength;
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ export const useSystem = defineStore('system', {
securityServerNodeType: undefined as undefined | NodeType,
};
},
persist: true, // This store is saved into browser local storage (pinia-plugin-persistedstate)
persist: {
storage: localStorage,
},
getters: {
isSecondaryNode(state) {
return state.securityServerNodeType === NodeType.SECONDARY;
Expand Down
27 changes: 26 additions & 1 deletion src/security-server/admin-service/ui/src/store/modules/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
* THE SOFTWARE.
*/

import { Key, Token, TokenCertificate } from '@/openapi-types';
import { Key, Token, TokenCertificate, TokenPinUpdate } from '@/openapi-types';
import * as api from '@/util/api';
import { deepClone } from '@/util/helpers';
import { encodePathParameter } from '@/util/api';
Expand Down Expand Up @@ -56,6 +56,9 @@ export const useTokens = defineStore('tokens', {
selectedToken: undefined as Token | undefined,
};
},
persist: {
paths: ['tokens', 'selectedToken'],
},
getters: {
filteredTokens: (state) => (search: string) => {
// Filter term is applied to token name key name and certificate owner id
Expand Down Expand Up @@ -188,5 +191,27 @@ export const useTokens = defineStore('tokens', {
throw error;
});
},
updatePin(tokenId: string, oldPin: string, newPin: string) {
const tokenPinUpdate: TokenPinUpdate = {
old_pin: oldPin,
new_pin: newPin,
};
return api
.put(`/tokens/${encodePathParameter(tokenId)}/pin`, tokenPinUpdate)
.catch((error) => {
throw error;
});
},
updateToken(token: Token) {
return api
.patch<Token>(`/tokens/${encodePathParameter(token.id)}`, token)
.then((res) => {
const tokenIndex = this.tokens.findIndex((t) => t.id === token.id);
this.tokens[tokenIndex] = res.data;
})
.catch((error) => {
throw error;
});
},
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ export const useUser = defineStore('user', {
bannedRoutes: [] as RouteRecordName[], // Array for routes the user doesn't have permission to access.
};
},
persist: true, // This store is saved into browser local storage (pinia-plugin-persistedstate)
persist: {
storage: localStorage,
},
getters: {
hasPermission: (state) => (perm: string) => {
return state.permissions.includes(perm);
Expand Down Expand Up @@ -227,6 +229,8 @@ export const useUser = defineStore('user', {
const system = useSystem();
system.clearSystemStore();

sessionStorage.clear();

// Call backend for logout
return axiosAuth
.post('/logout')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,6 @@ export default defineComponent({
required: true,
},
},
emits: ['backk'],
data() {
return {
confirmGroup: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
class="save-button"
:loading="saving"
:disabled="!meta.touched || !meta.valid"
@click="saveEndpoint()"
@click="save()"
>{{ $t('action.save') }}
</xrd-button>
</div>
Expand All @@ -92,16 +92,14 @@
title="endpoints.deleteTitle"
text="endpoints.deleteEndpointText"
@cancel="confirmDelete = false"
@accept="deleteEndpoint(id)"
@accept="remove(id)"
/>
</div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import * as api from '@/util/api';
import { Permissions } from '@/global';
import { encodePathParameter } from '@/util/api';
import { mapActions, mapState } from 'pinia';
import { useUser } from '@/store/modules/user';
import { useNotifications } from '@/store/modules/notifications';
Expand Down Expand Up @@ -163,15 +161,15 @@ export default defineComponent({
},
methods: {
...mapActions(useNotifications, ['showError', 'showSuccess']),
...mapActions(useServices, ['deleteEndpoint', 'updateEndpoint']),
close(): void {
this.$router.back();
},
showDeletePopup(): void {
this.confirmDelete = true;
},
deleteEndpoint(id: string): void {
api
.remove(`/endpoints/${encodePathParameter(id)}`)
remove(id: string): void {
this.deleteEndpoint(id)
.then(() => {
this.showSuccess(this.$t('endpoints.deleteSuccess'));
this.$router.back();
Expand All @@ -181,18 +179,13 @@ export default defineComponent({
this.confirmDelete = false;
});
},
saveEndpoint(): void {
if (!this.endpoint.id) {
throw new Error('Unable to save endpoint: Endpoint id not defined!');
}
save(): void {
this.saving = true;
this.endpoint.method = this.values.method;
this.endpoint.path = this.values.path;
api
.patch(
`/endpoints/${encodePathParameter(this.endpoint.id)}`,
this.endpoint,
)
this.updateEndpoint({
...this.endpoint,
method: this.values.method,
path: this.values.path,
})
.then(async () => {
this.showSuccess(this.$t('endpoints.editSuccess'));
this.$router.back();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<template>
<div class="xrd-tab-max-width detail-view-outer">
<div class="detail-view-content">
<xrd-sub-view-title :title="$t('keys.tokenDetails')" @close="close"/>
<xrd-sub-view-title :title="$t('keys.tokenDetails')" @close="close" />
<v-row>
<v-col>
<h3>{{ $t('keys.tokenInfo') }}</h3>
Expand Down Expand Up @@ -140,7 +140,7 @@
:disabled="isSaveDisabled"
data-test="token-details-save"
@click="save()"
>{{ $t('action.save') }}
>{{ $t('action.save') }}
</xrd-button>
</div>
</div>
Expand All @@ -150,17 +150,15 @@
/***
* Component for showing the details of a token.
*/
import {computed, defineComponent, ref} from 'vue';
import * as api from '@/util/api';
import {encodePathParameter} from '@/util/api';
import {Permissions} from '@/global';
import {PossibleAction, Token, TokenPinUpdate, TokenType,} from '@/openapi-types';
import {mapActions, mapState} from 'pinia';
import {useUser} from '@/store/modules/user';
import {useNotifications} from '@/store/modules/notifications';
import {AxiosError} from 'axios';
import {PublicPathState, useForm} from 'vee-validate';
import {useTokens} from '@/store/modules/tokens';
import { computed, defineComponent, ref } from 'vue';
import { Permissions } from '@/global';
import { PossibleAction, Token, TokenType } from '@/openapi-types';
import { mapActions, mapState } from 'pinia';
import { useUser } from '@/store/modules/user';
import { useNotifications } from '@/store/modules/notifications';
import { AxiosError } from 'axios';
import { PublicPathState, useForm } from 'vee-validate';
import { useTokens } from '@/store/modules/tokens';

export default defineComponent({
props: {
Expand All @@ -170,7 +168,7 @@ export default defineComponent({
},
},
setup(props) {
const {tokens} = useTokens();
const { tokens } = useTokens();
const isChangePinOpen = ref(false);
const token: Token = tokens.find((token) => token.id === props.id)!;
const validationSchema = computed(() => {
Expand Down Expand Up @@ -268,6 +266,7 @@ export default defineComponent({
methods: {
...mapActions(useNotifications, ['showError', 'showSuccess']),
...mapActions(useUser, ['fetchInitializationStatus']),
...mapActions(useTokens, ['updatePin', 'updateToken']),
close(): void {
this.$router.back();
},
Expand All @@ -278,22 +277,18 @@ export default defineComponent({
try {
let successMsg = this.$t('keys.tokenSaved') as string;
if (this.isChangePinOpen) {
const tokenPinUpdate: TokenPinUpdate = {
old_pin: this.values.token.oldPin,
new_pin: this.values.token.newPin,
};
await api.put(
`/tokens/${encodePathParameter(this.id)}/pin`,
tokenPinUpdate,
this.updatePin(
this.id,
this.values.token.oldPin,
this.values.token.newPin,
);
successMsg = this.$t('token.pinChanged') as string;
}
if (this.isFieldDirty('token.friendlyName')) {
this.token.name = this.values.token.friendlyName;
await api.patch(
`/tokens/${encodePathParameter(this.id)}`,
this.token,
);
this.updateToken({
...this.token,
name: this.values.token.friendlyName,
});
}
this.showSuccess(successMsg);
this.$router.back();
Expand Down

0 comments on commit 4fb1d38

Please sign in to comment.