| <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'), |
| autoFocusButton: 'ok', |
| }, |
| ) |
| .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> |