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.accessControl').controller('certificateController', [
13    '$scope', 'APIUtils', '$q', 'Constants', 'toastService',
14    function($scope, APIUtils, $q, Constants, toastService) {
15      $scope.loading = false;
16      $scope.certificates = [];
17      $scope.availableCertificateTypes = [];
18      $scope.allCertificateTypes = Constants.CERTIFICATE_TYPES;
19      $scope.addCertificateModal = false;
20      $scope.addCSRModal = false;
21      $scope.newCertificate = {};
22      $scope.newCSR = {};
23      $scope.submitted = false;
24      $scope.csrSubmitted = false;
25      $scope.csrCode = '';
26      $scope.displayCSRCode = false;
27      $scope.keyBitLength = Constants.CERTIFICATE.KEY_BIT_LENGTH;
28      $scope.keyPairAlgorithm = Constants.CERTIFICATE.KEY_PAIR_ALGORITHM;
29      $scope.keyCurveId = Constants.CERTIFICATE.KEY_CURVE_ID;
30      $scope.countryList = Constants.COUNTRIES;
31
32
33      $scope.$on('$viewContentLoaded', () => {
34        getBmcTime();
35      })
36
37      $scope.loadCertificates = function() {
38        $scope.certificates = [];
39        $scope.availableCertificateTypes = Constants.CERTIFICATE_TYPES;
40        $scope.loading = true;
41        // Use Certificate Service to get the locations of all the certificates,
42        // then add a promise for fetching each certificate
43        APIUtils.getCertificateLocations().then(
44            function(data) {
45              var promises = [];
46              var locations = data.Links.Certificates;
47              for (var i in locations) {
48                var location = locations[i];
49                promises.push(getCertificatePromise(location['@odata.id']));
50              }
51              $q.all(promises)
52                  .catch(function(error) {
53                    toastService.error('Failed to load certificates.');
54                    console.log(JSON.stringify(error));
55                  })
56                  .finally(function() {
57                    $scope.loading = false;
58                  });
59            },
60            function(error) {
61              $scope.loading = false;
62              $scope.availableCertificateTypes = [];
63              toastService.error('Failed to load certificates.');
64              console.log(JSON.stringify(error));
65            });
66      };
67
68      $scope.uploadCertificate = function() {
69        if ($scope.newCertificate.file.name.split('.').pop() !== 'pem') {
70          toastService.error('Certificate must be a .pem file.');
71          return;
72        }
73        $scope.addCertificateModal = false;
74        APIUtils
75            .addNewCertificate(
76                $scope.newCertificate.file, $scope.newCertificate.selectedType)
77            .then(
78                function(data) {
79                  toastService.success(
80                      $scope.newCertificate.selectedType.name +
81                      ' was uploaded.');
82                  $scope.newCertificate = {};
83                  $scope.loadCertificates();
84                },
85                function(error) {
86                  toastService.error(
87                      $scope.newCertificate.selectedType.name +
88                      ' failed upload.');
89                  console.log(JSON.stringify(error));
90                });
91      };
92
93      var getCertificatePromise = function(url) {
94        var promise = APIUtils.getCertificate(url).then(function(data) {
95          var certificate = data;
96          isExpiring(certificate);
97          updateAvailableTypes(certificate);
98          $scope.certificates.push(certificate);
99        });
100        return promise;
101      };
102
103      var isExpiring = function(certificate) {
104        // convert certificate time to epoch time
105        // if ValidNotAfter is less than or equal to 30 days from bmc time
106        // (2592000000), isExpiring. If less than or equal to 0, is expired.
107        // dividing bmc time by 1000 converts epoch milliseconds to seconds
108        var difference = (new Date(certificate.ValidNotAfter).getTime()) -
109            ($scope.bmcTime) / 1000;
110        if (difference <= 0) {
111          certificate.isExpired = true;
112        } else if (difference <= 2592000000) {
113          certificate.isExpiring = true;
114        } else {
115          certificate.isExpired = false;
116          certificate.isExpiring = false;
117        }
118      };
119
120      // add optional name
121      $scope.names = [];
122      $scope.addOptionalRow = function() {
123        $scope.names.push({Value: ''})
124      };
125
126      // remove optional name row
127      $scope.deleteOptionalRow = function(index) {
128        $scope.names.splice(index, 1);
129        if ($scope.names.length == 0) {
130          $scope.names = [];
131        }
132      };
133
134
135      // create a CSR object to send to the backend
136      $scope.getCSRCode = function() {
137        var addCSR = {};
138        let alternativeNames = $scope.names.map(name => name.Value);
139
140        // if user provided a first alternative name then push to alternative
141        // names array
142        $scope.newCSR.firstAlternativeName ?
143            alternativeNames.push($scope.newCSR.firstAlternativeName) :
144            $scope.newCSR.firstAlternativeName = '';
145
146
147        addCSR.CertificateCollection = {
148          '@odata.id': $scope.newCSR.certificateCollection.location
149        };
150        addCSR.CommonName = $scope.newCSR.commonName;
151        addCSR.ContactPerson = $scope.newCSR.contactPerson || '';
152        addCSR.City = $scope.newCSR.city;
153        addCSR.AlternativeNames = alternativeNames || [];
154        addCSR.ChallengePassword = $scope.newCSR.challengePassword || '';
155        addCSR.Email = $scope.newCSR.emailAddress || '';
156        addCSR.Country = $scope.newCSR.countryCode.code;
157        addCSR.Organization = $scope.newCSR.organization;
158        addCSR.OrganizationalUnit = $scope.newCSR.companyUnit;
159        addCSR.KeyCurveId = $scope.newCSR.keyCurveId || '';
160        addCSR.KeyBitLength = $scope.newCSR.keyBitLength
161        addCSR.KeyPairAlgorithm = $scope.newCSR.keyPairAlgorithm || '';
162        addCSR.State = $scope.newCSR.state;
163
164        APIUtils.createCSRCertificate(addCSR).then(
165            function(data) {
166              $scope.displayCSRCode = true;
167              $scope.csrCode = data;
168            },
169            function(error) {
170              $scope.addCSRModal = false;
171              toastService.error('Unable to generate CSR. Try again.');
172              console.log(JSON.stringify(error));
173            })
174      };
175
176      // resetting the modal when user clicks cancel/closes the
177      // modal
178      $scope.resetCSRModal = function() {
179        $scope.addCSRModal = false;
180        $scope.displayCSRCode = false;
181        $scope.newCSR.certificateCollection = $scope.selectOption;
182        $scope.newCSR.commonName = '';
183        $scope.newCSR.contactPerson = '';
184        $scope.newCSR.city = '';
185        $scope.names = [];
186        $scope.newCSR.challengePassword = '';
187        $scope.newCSR.emailAddress = '';
188        $scope.newCSR.countryCode = '';
189        $scope.newCSR.keyCurveId = '';
190        $scope.newCSR.firstAlternativeName = '';
191        $scope.newCSR.keyBitLength = $scope.selectOption;
192        $scope.newCSR.keyPairAlgorithm = $scope.selectOption;
193        $scope.newCSR.organization = '';
194        $scope.newCSR.companyUnit = '';
195        $scope.newCSR.state = '';
196      };
197
198      // copies the CSR code
199      $scope.copySuccess = function(event) {
200        $scope.copied = true;
201        $timeout(function() {
202          $scope.copied = false;
203        }, 5000);
204      };
205      $scope.copyFailed = function(err) {
206        console.log(JSON.stringify(err));
207      };
208
209
210      var getBmcTime = function() {
211        APIUtils.getBMCTime().then(function(data) {
212          $scope.bmcTime = data.data.Elapsed;
213        });
214
215        return $scope.bmcTime;
216      };
217
218      var updateAvailableTypes = function(certificate) {
219        // TODO: at this time only one of each type of certificate is allowed.
220        // When this changes, this will need to be updated.
221        // Removes certificate type from available types to be added.
222        $scope.availableCertificateTypes =
223            $scope.availableCertificateTypes.filter(function(type) {
224              return type.Description !== certificate.Description;
225            });
226      };
227
228      $scope.getDays = function(endDate) {
229        // finds number of days until certificate expiration
230        // dividing bmc time by 1000 converts milliseconds to seconds
231        var ms = (new Date(endDate).getTime()) - ($scope.bmcTime) / 1000;
232        return Math.floor(ms / (24 * 60 * 60 * 1000));
233      };
234
235      $scope.loadCertificates();
236    }
237  ]);
238})(angular);
239