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