1import api from '@/store/api'; 2import i18n from '@/i18n'; 3 4const getCertificateProp = (certificateTypes, type, prop) => { 5 const certificate = certificateTypes.find( 6 (certificate) => certificate.type === type, 7 ); 8 return certificate ? certificate[prop] : null; 9}; 10 11const CertificatesStore = { 12 namespaced: true, 13 state: { 14 allCertificates: [], 15 availableUploadTypes: [], 16 certificateTypes: [], 17 }, 18 getters: { 19 allCertificates: (state) => state.allCertificates, 20 availableUploadTypes: (state) => state.availableUploadTypes, 21 certificateTypes: (state) => state.certificateTypes, 22 }, 23 mutations: { 24 setCertificates(state, certificates) { 25 state.allCertificates = certificates; 26 }, 27 setAvailableUploadTypes(state, availableUploadTypes) { 28 state.availableUploadTypes = availableUploadTypes; 29 }, 30 setCertificateTypes(state, certificateTypes) { 31 state.certificateTypes = certificateTypes; 32 }, 33 }, 34 actions: { 35 async getCertificateTypes({ commit }) { 36 const certificateTypes = [ 37 { 38 type: 'HTTPS Certificate', 39 location: `${await this.dispatch( 40 'global/getBmcPath', 41 )}/NetworkProtocol/HTTPS/Certificates/`, 42 label: i18n.t('pageCertificates.httpsCertificate'), 43 }, 44 { 45 type: 'LDAP Certificate', 46 location: '/redfish/v1/AccountService/LDAP/Certificates/', 47 label: i18n.t('pageCertificates.ldapCertificate'), 48 }, 49 { 50 type: 'TrustStore Certificate', 51 location: `${await this.dispatch( 52 'global/getBmcPath', 53 )}/Truststore/Certificates/`, 54 // Web UI will show 'CA Certificate' instead of 55 // 'TrustStore Certificate' after user testing revealed 56 // the term 'TrustStore Certificate' wasn't recognized/was unfamilar 57 label: i18n.t('pageCertificates.caCertificate'), 58 }, 59 ]; 60 await commit('setCertificateTypes', certificateTypes); 61 }, 62 async getCertificates({ dispatch, getters, commit }) { 63 await dispatch('getCertificateTypes'); 64 return await api 65 .get('/redfish/v1/CertificateService/CertificateLocations') 66 .then( 67 ({ 68 data: { 69 Links: { Certificates }, 70 }, 71 }) => Certificates.map((certificate) => certificate['@odata.id']), 72 ) 73 .then((certificateLocations) => { 74 const promises = certificateLocations.map((location) => 75 api.get(location), 76 ); 77 api.all(promises).then( 78 api.spread((...responses) => { 79 const certificates = responses.map(({ data }) => { 80 const { 81 Name, 82 ValidNotAfter, 83 ValidNotBefore, 84 Issuer = {}, 85 Subject = {}, 86 } = data; 87 return { 88 type: Name, 89 location: data['@odata.id'], 90 certificate: getCertificateProp( 91 getters['certificateTypes'], 92 Name, 93 'label', 94 ), 95 issuedBy: Issuer.CommonName, 96 issuedTo: Subject.CommonName, 97 validFrom: new Date(ValidNotBefore), 98 validUntil: new Date(ValidNotAfter), 99 }; 100 }); 101 const availableUploadTypes = getters['certificateTypes'].filter( 102 ({ type }) => 103 !certificates 104 .map((certificate) => certificate.type) 105 .includes(type), 106 ); 107 108 commit('setCertificates', certificates); 109 commit('setAvailableUploadTypes', availableUploadTypes); 110 }), 111 ); 112 }); 113 }, 114 async addNewCertificate({ dispatch, getters }, { file, type }) { 115 return await api 116 .post( 117 getCertificateProp(getters['certificateTypes'], type, 'location'), 118 file, 119 { 120 headers: { 'Content-Type': 'application/x-pem-file' }, 121 }, 122 ) 123 .then(() => dispatch('getCertificates')) 124 .then(() => 125 i18n.t('pageCertificates.toast.successAddCertificate', { 126 certificate: getCertificateProp( 127 getters['certificateTypes'], 128 type, 129 'label', 130 ), 131 }), 132 ) 133 .catch((error) => { 134 console.log(error); 135 throw new Error(i18n.t('pageCertificates.toast.errorAddCertificate')); 136 }); 137 }, 138 async replaceCertificate( 139 { dispatch, getters }, 140 { certificateString, location, type }, 141 ) { 142 const data = {}; 143 data.CertificateString = certificateString; 144 data.CertificateType = 'PEM'; 145 data.CertificateUri = { '@odata.id': location }; 146 147 return await api 148 .post( 149 '/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate', 150 data, 151 ) 152 .then(() => dispatch('getCertificates')) 153 .then(() => 154 i18n.t('pageCertificates.toast.successReplaceCertificate', { 155 certificate: getCertificateProp( 156 getters['certificateTypes'], 157 type, 158 'label', 159 ), 160 }), 161 ) 162 .catch((error) => { 163 console.log(error); 164 throw new Error( 165 i18n.t('pageCertificates.toast.errorReplaceCertificate'), 166 ); 167 }); 168 }, 169 async deleteCertificate({ dispatch, getters }, { type, location }) { 170 return await api 171 .delete(location) 172 .then(() => dispatch('getCertificates')) 173 .then(() => 174 i18n.t('pageCertificates.toast.successDeleteCertificate', { 175 certificate: getCertificateProp( 176 getters['certificateTypes'], 177 type, 178 'label', 179 ), 180 }), 181 ) 182 .catch((error) => { 183 console.log(error); 184 throw new Error( 185 i18n.t('pageCertificates.toast.errorDeleteCertificate'), 186 ); 187 }); 188 }, 189 async generateCsr({ getters }, userData) { 190 const { 191 certificateType, 192 country, 193 state, 194 city, 195 companyName, 196 companyUnit, 197 commonName, 198 keyPairAlgorithm, 199 keyBitLength, 200 keyCurveId, 201 contactPerson, 202 emailAddress, 203 alternateName, 204 } = userData; 205 const data = {}; 206 207 data.CertificateCollection = { 208 '@odata.id': getCertificateProp( 209 getters['certificateTypes'], 210 certificateType, 211 'location', 212 ), 213 }; 214 data.Country = country; 215 data.State = state; 216 data.City = city; 217 data.Organization = companyName; 218 data.OrganizationalUnit = companyUnit; 219 data.CommonName = commonName; 220 data.KeyPairAlgorithm = keyPairAlgorithm; 221 data.AlternativeNames = alternateName; 222 223 if (keyCurveId) data.KeyCurveId = keyCurveId; 224 if (keyBitLength) data.KeyBitLength = keyBitLength; 225 if (contactPerson) data.ContactPerson = contactPerson; 226 if (emailAddress) data.Email = emailAddress; 227 228 return await api 229 .post( 230 '/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR', 231 data, 232 ) 233 //TODO: Success response also throws error so 234 // can't accurately show legitimate error in UI 235 .catch((error) => console.log(error)); 236 }, 237 }, 238}; 239 240export default CertificatesStore; 241