1/**
2 * Controller for Certificate Management
3 *
4 * @module app/access-control
5 * @exports certificateController
6 * @name certificateController
7 */
8
9window.angular && (function(angular) {
10  'use strict';
11
12  angular.module('app.configuration').controller('certificateController', [
13    '$scope', 'APIUtils', '$q', 'Constants', 'toastService', '$timeout',
14    '$uibModal',
15    function(
16        $scope, APIUtils, $q, Constants, toastService, $timeout, $uibModal) {
17      $scope.loading = false;
18      $scope.certificates = [];
19      $scope.availableCertificateTypes = [];
20      $scope.allCertificateTypes = Constants.CERTIFICATE_TYPES;
21      $scope.newCertificate = {};
22      $scope.newCSR = {};
23      $scope.keyBitLength = Constants.CERTIFICATE.KEY_BIT_LENGTH;
24      $scope.keyPairAlgorithm = Constants.CERTIFICATE.KEY_PAIR_ALGORITHM;
25      $scope.keyCurveId = Constants.CERTIFICATE.KEY_CURVE_ID;
26      $scope.countryList = Constants.COUNTRIES;
27
28      $scope.$on('$viewContentLoaded', () => {
29        getBmcTime();
30      })
31
32      $scope.loadCertificates = function() {
33        $scope.certificates = [];
34        $scope.availableCertificateTypes = Constants.CERTIFICATE_TYPES;
35        $scope.loading = true;
36        // Use Certificate Service to get the locations of all the certificates,
37        // then add a promise for fetching each certificate
38        APIUtils.getCertificateLocations().then(
39            function(data) {
40              var promises = [];
41              var locations = data.Links.Certificates;
42              for (var i in locations) {
43                var location = locations[i];
44                promises.push(getCertificatePromise(location['@odata.id']));
45              }
46              $q.all(promises)
47                  .catch(function(error) {
48                    toastService.error('Failed to load certificates.');
49                    console.log(JSON.stringify(error));
50                  })
51                  .finally(function() {
52                    $scope.loading = false;
53                    $scope.certificates.sort(function(a, b) {
54                      if (a.Name > b.Name) {
55                        return 1;
56                      }
57                      if (a.Name < b.Name) {
58                        return -1;
59                      }
60                      if (a.Issuer.CommonName > b.Issuer.CommonName) {
61                        return 1;
62                      }
63                      if (a.Issuer.CommonName < b.Issuer.CommonName) {
64                        return -1;
65                      }
66                      return (Date.parse(a.ValidNotBefore) >
67                              Date.parse(b.ValidNotBefore)) ?
68                          1 :
69                          -1;
70                    });
71                  });
72            },
73            function(error) {
74              $scope.loading = false;
75              $scope.availableCertificateTypes = [];
76              toastService.error('Failed to load certificates.');
77              console.log(JSON.stringify(error));
78            });
79      };
80
81      $scope.uploadCertificate = function() {
82        if ($scope.newCertificate.file.name.split('.').pop() !== 'pem') {
83          toastService.error('Certificate must be a .pem file.');
84          return;
85        }
86        APIUtils
87            .addNewCertificate(
88                $scope.newCertificate.file, $scope.newCertificate.selectedType)
89            .then(
90                function(data) {
91                  toastService.success(
92                      $scope.newCertificate.selectedType.name +
93                      ' was uploaded.');
94                  $scope.newCertificate = {};
95                  $scope.loadCertificates();
96                },
97                function(error) {
98                  toastService.error(
99                      $scope.newCertificate.selectedType.name +
100                      ' failed upload.');
101                  console.log(JSON.stringify(error));
102                });
103      };
104
105      var getCertificatePromise = function(url) {
106        var promise = APIUtils.getCertificate(url).then(function(data) {
107          var certificate = data;
108          isExpiring(certificate);
109          updateAvailableTypes(certificate);
110          $scope.certificates.push(certificate);
111        });
112        return promise;
113      };
114
115      var isExpiring = function(certificate) {
116        // convert certificate time to epoch time
117        // if ValidNotAfter is less than or equal to 30 days from bmc time
118        // (2592000000), isExpiring. If less than or equal to 0, is expired.
119        // dividing bmc time by 1000 converts epoch milliseconds to seconds
120        var difference = (new Date(certificate.ValidNotAfter).getTime()) -
121            ($scope.bmcTime) / 1000;
122        if (difference <= 0) {
123          certificate.isExpired = true;
124        } else if (difference <= 2592000000) {
125          certificate.isExpiring = true;
126        } else {
127          certificate.isExpired = false;
128          certificate.isExpiring = false;
129        }
130      };
131
132      // add optional name
133      $scope.names = [];
134      $scope.addOptionalRow = function() {
135        $scope.names.push({Value: ''})
136      };
137
138      // remove optional name row
139      $scope.deleteOptionalRow = function(index) {
140        $scope.names.splice(index, 1);
141        if ($scope.names.length == 0) {
142          $scope.names = [];
143        }
144      };
145
146      // create a CSR object to send to the backend
147      $scope.getCSRCode = function() {
148        var addCSR = {};
149        let alternativeNames = $scope.names.map(name => name.Value);
150
151        // if user provided a first alternative name then push to alternative
152        // names array
153        $scope.newCSR.firstAlternativeName ?
154            alternativeNames.push($scope.newCSR.firstAlternativeName) :
155            $scope.newCSR.firstAlternativeName = '';
156
157        addCSR.CertificateCollection = {
158          '@odata.id': $scope.newCSR.certificateCollection.location
159        };
160        addCSR.CommonName = $scope.newCSR.commonName;
161        addCSR.ContactPerson = $scope.newCSR.contactPerson || '';
162        addCSR.City = $scope.newCSR.city;
163        addCSR.AlternativeNames = alternativeNames || [];
164        addCSR.ChallengePassword = $scope.newCSR.challengePassword || '';
165        addCSR.Email = $scope.newCSR.emailAddress || '';
166        addCSR.Country = $scope.newCSR.countryCode.code;
167        addCSR.Organization = $scope.newCSR.organization;
168        addCSR.OrganizationalUnit = $scope.newCSR.companyUnit;
169        addCSR.KeyCurveId = $scope.newCSR.keyCurveId || '';
170        addCSR.KeyBitLength = $scope.newCSR.keyBitLength
171        addCSR.KeyPairAlgorithm = $scope.newCSR.keyPairAlgorithm || '';
172        addCSR.State = $scope.newCSR.state;
173
174        APIUtils.createCSRCertificate(addCSR).then(
175            function(data) {
176              $scope.csrCode = data;
177              openDownloadCsrModal();
178            },
179            function(error) {
180              toastService.error('Unable to generate CSR. Try again.');
181              console.log(JSON.stringify(error));
182            })
183      };
184
185      function openDownloadCsrModal() {
186        const modalTemplateCsrDownload =
187            require('./certificate-modal-csr-download.html');
188        $uibModal
189            .open({
190              template: modalTemplateCsrDownload,
191              windowTopClass: 'uib-modal',
192              scope: $scope,
193              ariaLabelledBy: 'modal_label',
194              size: 'lg',
195            })
196            .result.catch(function() {
197              resetCSRModal();
198            });
199      };
200
201      $scope.addCertModal = function() {
202        openAddCertModal();
203      };
204
205      function openAddCertModal() {
206        const modalTemplateAddCert =
207            require('./certificate-modal-add-cert.html');
208        $uibModal
209            .open({
210              template: modalTemplateAddCert,
211              windowTopClass: 'uib-modal',
212              scope: $scope,
213              ariaLabelledBy: 'modal_label',
214            })
215            .result.catch(function() {
216              // do nothing
217            });
218      };
219
220      $scope.addCsrModal = function() {
221        openCsrModal();
222      };
223
224      function openCsrModal() {
225        const modalTemplateCsrGen = require('./certificate-modal-csr-gen.html');
226        $uibModal
227            .open({
228              template: modalTemplateCsrGen,
229              windowTopClass: 'uib-modal',
230              scope: $scope,
231              ariaLabelledBy: 'modal_label',
232              size: 'lg',
233            })
234            .result.catch(function() {
235              resetCSRModal();
236            });
237      };
238
239      // resetting the modal when user clicks cancel/closes the
240      // modal
241      const resetCSRModal = function() {
242        $scope.newCSR.certificateCollection = $scope.selectOption;
243        $scope.newCSR.commonName = '';
244        $scope.newCSR.contactPerson = '';
245        $scope.newCSR.city = '';
246        $scope.names = [];
247        $scope.newCSR.challengePassword = '';
248        $scope.newCSR.emailAddress = '';
249        $scope.newCSR.countryCode = '';
250        $scope.newCSR.keyCurveId = '';
251        $scope.newCSR.firstAlternativeName = '';
252        $scope.newCSR.keyBitLength = $scope.selectOption;
253        $scope.newCSR.keyPairAlgorithm = $scope.selectOption;
254        $scope.newCSR.organization = '';
255        $scope.newCSR.companyUnit = '';
256        $scope.newCSR.state = '';
257      };
258
259      // copies the CSR code
260      $scope.copySuccess = function(event) {
261        $scope.copied = true;
262        $timeout(function() {
263          $scope.copied = false;
264        }, 5000);
265      };
266      $scope.copyFailed = function(err) {
267        console.log(JSON.stringify(err));
268      };
269
270
271      var getBmcTime = function() {
272        APIUtils.getBMCTime().then(function(data) {
273          $scope.bmcTime = data.data.Elapsed;
274        });
275
276        return $scope.bmcTime;
277      };
278
279      var updateAvailableTypes = function(certificate) {
280        $scope.availableCertificateTypes =
281            $scope.availableCertificateTypes.filter(function(type) {
282              if (type.Description == 'TrustStore Certificate') {
283                return true;
284              }
285              return type.Description !== certificate.Description;
286            });
287      };
288
289      $scope.getDays = function(endDate) {
290        // finds number of days until certificate expiration
291        // dividing bmc time by 1000 converts milliseconds to seconds
292        var ms = (new Date(endDate).getTime()) - ($scope.bmcTime) / 1000;
293        return Math.floor(ms / (24 * 60 * 60 * 1000));
294      };
295
296      $scope.loadCertificates();
297    }
298  ]);
299})(angular);
300