blob: 0dc1d5e1fcd72bcef04a261e7a1371c0e4acc8fe [file] [log] [blame]
<template>
<b-container fluid="xl">
<page-title />
<b-row>
<b-col xl="11">
<!-- Expired certificates banner -->
<alert :show="expiredCertificateTypes.length > 0" variant="danger">
<template v-if="expiredCertificateTypes.length > 1">
{{ $t('pageCertificates.alert.certificatesExpiredMessage') }}
</template>
<template v-else>
{{
$t('pageCertificates.alert.certificateExpiredMessage', {
certificate: expiredCertificateTypes[0],
})
}}
</template>
</alert>
<!-- Expiring certificates banner -->
<alert :show="expiringCertificateTypes.length > 0" variant="warning">
<template v-if="expiringCertificateTypes.length > 1">
{{ $t('pageCertificates.alert.certificatesExpiringMessage') }}
</template>
<template v-else>
{{
$t('pageCertificates.alert.certificateExpiringMessage', {
certificate: expiringCertificateTypes[0],
})
}}
</template>
</alert>
</b-col>
</b-row>
<b-row>
<b-col xl="11" class="text-right">
<b-button
v-b-modal.generate-csr
data-test-id="certificates-button-generateCsr"
variant="link"
>
<icon-add />
{{ $t('pageCertificates.generateCsr') }}
</b-button>
<b-button
variant="primary"
:disabled="certificatesForUpload.length === 0"
@click="initModalUploadCertificate(null)"
>
<icon-add />
{{ $t('pageCertificates.addNewCertificate') }}
</b-button>
</b-col>
</b-row>
<b-row>
<b-col xl="11">
<b-table
responsive="md"
show-empty
hover
:busy="isBusy"
:fields="fields"
:items="tableItems"
:empty-text="$t('global.table.emptyMessage')"
>
<template #cell(validFrom)="{ value }">
{{ value | formatDate }}
</template>
<template #cell(validUntil)="{ value }">
<status-icon
v-if="getDaysUntilExpired(value) < 31"
:status="getIconStatus(value)"
/>
{{ value | formatDate }}
</template>
<template #cell(actions)="{ value, item }">
<table-row-action
v-for="(action, index) in value"
:key="index"
:value="action.value"
:title="action.title"
:enabled="action.enabled"
@click-table-action="onTableRowAction($event, item)"
>
<template #icon>
<icon-replace v-if="action.value === 'replace'" />
<icon-trashcan v-if="action.value === 'delete'" />
</template>
</table-row-action>
</template>
</b-table>
</b-col>
</b-row>
<!-- Modals -->
<modal-upload-certificate :certificate="modalCertificate" @ok="onModalOk" />
<modal-generate-csr />
</b-container>
</template>
<script>
import IconAdd from '@carbon/icons-vue/es/add--alt/20';
import IconReplace from '@carbon/icons-vue/es/renew/20';
import IconTrashcan from '@carbon/icons-vue/es/trash-can/20';
import ModalGenerateCsr from './ModalGenerateCsr';
import ModalUploadCertificate from './ModalUploadCertificate';
import PageTitle from '@/components/Global/PageTitle';
import TableRowAction from '@/components/Global/TableRowAction';
import StatusIcon from '@/components/Global/StatusIcon';
import Alert from '@/components/Global/Alert';
import BVToastMixin from '@/components/Mixins/BVToastMixin';
import LoadingBarMixin from '@/components/Mixins/LoadingBarMixin';
export default {
name: 'Certificates',
components: {
Alert,
IconAdd,
IconReplace,
IconTrashcan,
ModalGenerateCsr,
ModalUploadCertificate,
PageTitle,
StatusIcon,
TableRowAction,
},
mixins: [BVToastMixin, LoadingBarMixin],
beforeRouteLeave(to, from, next) {
this.hideLoader();
next();
},
data() {
return {
isBusy: true,
modalCertificate: null,
fileTypeCorrect: undefined,
fields: [
{
key: 'certificate',
label: this.$t('pageCertificates.table.certificate'),
},
{
key: 'issuedBy',
label: this.$t('pageCertificates.table.issuedBy'),
},
{
key: 'issuedTo',
label: this.$t('pageCertificates.table.issuedTo'),
},
{
key: 'validFrom',
label: this.$t('pageCertificates.table.validFrom'),
},
{
key: 'validUntil',
label: this.$t('pageCertificates.table.validUntil'),
},
{
key: 'actions',
label: '',
tdClass: 'text-right text-nowrap',
},
],
};
},
computed: {
certificates() {
return this.$store.getters['certificates/allCertificates'];
},
tableItems() {
return this.certificates.map((certificate) => {
return {
...certificate,
actions: [
{
value: 'replace',
title: this.$t('pageCertificates.replaceCertificate'),
},
{
value: 'delete',
title: this.$t('pageCertificates.deleteCertificate'),
enabled:
certificate.type === 'TrustStore Certificate' ? true : false,
},
],
};
});
},
certificatesForUpload() {
return this.$store.getters['certificates/availableUploadTypes'];
},
bmcTime() {
return this.$store.getters['global/bmcTime'];
},
expiredCertificateTypes() {
return this.certificates.reduce((acc, val) => {
const daysUntilExpired = this.getDaysUntilExpired(val.validUntil);
if (daysUntilExpired < 1) {
acc.push(val.certificate);
}
return acc;
}, []);
},
expiringCertificateTypes() {
return this.certificates.reduce((acc, val) => {
const daysUntilExpired = this.getDaysUntilExpired(val.validUntil);
if (daysUntilExpired < 31 && daysUntilExpired > 0) {
acc.push(val.certificate);
}
return acc;
}, []);
},
},
async created() {
this.startLoader();
await this.$store.dispatch('global/getBmcTime');
this.$store.dispatch('certificates/getCertificates').finally(() => {
this.endLoader();
this.isBusy = false;
});
},
methods: {
onTableRowAction(event, rowItem) {
switch (event) {
case 'replace':
this.initModalUploadCertificate(rowItem);
break;
case 'delete':
this.initModalDeleteCertificate(rowItem);
break;
default:
break;
}
},
initModalUploadCertificate(certificate = null) {
this.modalCertificate = certificate;
this.$bvModal.show('upload-certificate');
},
initModalDeleteCertificate(certificate) {
this.$bvModal
.msgBoxConfirm(
this.$t('pageCertificates.modal.deleteConfirmMessage', {
issuedBy: certificate.issuedBy,
certificate: certificate.certificate,
}),
{
title: this.$t('pageCertificates.deleteCertificate'),
okTitle: this.$t('global.action.delete'),
cancelTitle: this.$t('global.action.cancel'),
},
)
.then((deleteConfirmed) => {
if (deleteConfirmed) this.deleteCertificate(certificate);
});
},
onModalOk({ addNew, file, type, location }) {
if (addNew) {
// Upload a new certificate
this.fileTypeCorrect = this.getIsFileTypeCorrect(file);
if (this.fileTypeCorrect) {
this.addNewCertificate(file, type);
} else {
this.errorToast(
this.$t('pageCertificates.alert.incorrectCertificateFileType'),
{
title: this.$t('pageCertificates.toast.errorAddCertificate'),
},
);
}
} else {
// Replace an existing certificate
this.replaceCertificate(file, type, location);
}
},
addNewCertificate(file, type) {
if (this.fileTypeCorrect === true) {
this.startLoader();
this.$store
.dispatch('certificates/addNewCertificate', { file, type })
.then((success) => this.successToast(success))
.catch(({ message }) => this.errorToast(message))
.finally(() => this.endLoader());
}
},
replaceCertificate(file, type, location) {
this.startLoader();
const reader = new FileReader();
reader.readAsBinaryString(file);
reader.onloadend = (event) => {
const certificateString = event.target.result;
this.$store
.dispatch('certificates/replaceCertificate', {
certificateString,
type,
location,
})
.then((success) => this.successToast(success))
.catch(({ message }) => this.errorToast(message))
.finally(() => this.endLoader());
};
},
deleteCertificate({ type, location }) {
this.startLoader();
this.$store
.dispatch('certificates/deleteCertificate', {
type,
location,
})
.then((success) => this.successToast(success))
.catch(({ message }) => this.errorToast(message))
.finally(() => this.endLoader());
},
getDaysUntilExpired(date) {
if (this.bmcTime) {
const validUntilMs = date.getTime();
const currentBmcTimeMs = this.bmcTime.getTime();
const oneDayInMs = 24 * 60 * 60 * 1000;
return Math.round((validUntilMs - currentBmcTimeMs) / oneDayInMs);
}
return new Date();
},
getIconStatus(date) {
const daysUntilExpired = this.getDaysUntilExpired(date);
if (daysUntilExpired < 1) {
return 'danger';
} else if (daysUntilExpired < 31) {
return 'warning';
}
},
getIsFileTypeCorrect(file) {
const fileTypeExtension = file.name.split('.').pop();
return fileTypeExtension === 'pem';
},
},
};
</script>