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