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.global.t('pageCertificates.httpsCertificate'),
43        },
44        {
45          type: 'LDAP Certificate',
46          location: '/redfish/v1/AccountService/LDAP/Certificates/',
47          label: i18n.global.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.global.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.global.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(
136            i18n.global.t('pageCertificates.toast.errorAddCertificate'),
137          );
138        });
139    },
140    async replaceCertificate(
141      { dispatch, getters },
142      { certificateString, location, type },
143    ) {
144      const data = {};
145      data.CertificateString = certificateString;
146      data.CertificateType = 'PEM';
147      data.CertificateUri = { '@odata.id': location };
148
149      return await api
150        .post(
151          '/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate',
152          data,
153        )
154        .then(() => dispatch('getCertificates'))
155        .then(() =>
156          i18n.global.t('pageCertificates.toast.successReplaceCertificate', {
157            certificate: getCertificateProp(
158              getters['certificateTypes'],
159              type,
160              'label',
161            ),
162          }),
163        )
164        .catch((error) => {
165          console.log(error);
166          throw new Error(
167            i18n.global.t('pageCertificates.toast.errorReplaceCertificate'),
168          );
169        });
170    },
171    async deleteCertificate({ dispatch, getters }, { type, location }) {
172      return await api
173        .delete(location)
174        .then(() => dispatch('getCertificates'))
175        .then(() =>
176          i18n.global.t('pageCertificates.toast.successDeleteCertificate', {
177            certificate: getCertificateProp(
178              getters['certificateTypes'],
179              type,
180              'label',
181            ),
182          }),
183        )
184        .catch((error) => {
185          console.log(error);
186          throw new Error(
187            i18n.global.t('pageCertificates.toast.errorDeleteCertificate'),
188          );
189        });
190    },
191    async generateCsr({ getters }, userData) {
192      const {
193        certificateType,
194        country,
195        state,
196        city,
197        companyName,
198        companyUnit,
199        commonName,
200        keyPairAlgorithm,
201        keyBitLength,
202        keyCurveId,
203        contactPerson,
204        emailAddress,
205        alternateName,
206      } = userData;
207      const data = {};
208
209      data.CertificateCollection = {
210        '@odata.id': getCertificateProp(
211          getters['certificateTypes'],
212          certificateType,
213          'location',
214        ),
215      };
216      data.Country = country;
217      data.State = state;
218      data.City = city;
219      data.Organization = companyName;
220      data.OrganizationalUnit = companyUnit;
221      data.CommonName = commonName;
222      data.KeyPairAlgorithm = keyPairAlgorithm;
223      data.AlternativeNames = alternateName;
224
225      if (keyCurveId) data.KeyCurveId = keyCurveId;
226      if (keyBitLength) data.KeyBitLength = keyBitLength;
227      if (contactPerson) data.ContactPerson = contactPerson;
228      if (emailAddress) data.Email = emailAddress;
229
230      return await api
231        .post(
232          '/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR',
233          data,
234        )
235        //TODO: Success response also throws error so
236        // can't accurately show legitimate error in UI
237        .catch((error) => console.log(error));
238    },
239  },
240};
241
242export default CertificatesStore;
243