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