horizon/openstack_dashboard/static/app/core/openstack-service-api/keypair-download.service.js

154 lines
5.5 KiB
JavaScript

/*
* (c) Copyright 2015 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
(function () {
'use strict';
/**
* @ngdoc overview
* @name horizon.dashboard.project.workflow.keypair.create-keypair-service
*
* @description
* Service to handle creating keypairs and downloading their private keys.
* Please note, the implementation has quirks due to what features are
* available in which browsers. As a result, the implementation involves
* using iframes to specify downloads. Since the API does not allow the
* full retrieval of the key pair after creation, and the URL retrieved in
* an iframe must be a GET method, and the fact that we shouldn't pass
* data as part of the URL (because it is potentially logged and contains
* private key data), we have to make the actual API call when performing
* the GET. This also means that if the user misses the download for some
* reason, we need to provide the ability to regenerate the key pair,
* although that is not a feature of this service.
*/
angular
.module('horizon.app.core.openstack-service-api')
.factory('horizon.app.core.openstack-service-api.keypair-download-service',
keypairDownloadService);
keypairDownloadService.$inject = [
'$document',
'horizon.app.core.openstack-service-api.nova',
'$q',
'$timeout'
];
function keypairDownloadService($document, novaAPI, $q, $timeout) {
var service = {
createAndDownloadKeypair: createAndDownloadKeypair
};
return service;
/**
* @ngdoc function
* @name createAndDownloadKeypair
*
* @description
* This function performs the actions necessary to begin a download
* of a newly created key pair. The given name will be used as the
* logical name of the key pair and will be used to make a file-system-
* friendly filename.
* In this implementation, for browser compatibility reasons, the
* download is achieved by creating an iframe with the given path for
* the create API call given, so the results are streamed directly to the
* client. This is not ideal but is due to lack of support in IE for
* features like the data: protocol. The iframes require that an element
* with the class of 'download-iframes' is present.
*
* @param {string} name The desired name for the key pair
* @returns {promise} A promise resolving if true, rejecting with error
*/
function createAndDownloadKeypair(name) {
addDOMResource(name);
return verifyCreatedPromise(name);
}
/**
* @ngdoc function
* @name addDOMResource
*
* @description
* This adds an iframe to the body of the current document, using
* the appropriate URL for the API to create/download the new key pair.
*
* @param {string} keypairName The desired name for the key pair
* @returns {undefined} Returns nothing
*/
function addDOMResource(keypairName) {
var url = novaAPI.getCreateKeypairUrl(keypairName);
var iframe = angular.element("<iframe></iframe>");
iframe.attr('id', keypairName);
iframe.attr('src', url);
iframe.attr('style', 'display: none;');
if ($document.find('.download-iframes').size() === 0) {
var iframeContainer = angular.element('<div class="download-iframes"></div>');
$document.find('body').append(iframeContainer);
}
$document.find('.download-iframes').append(iframe);
}
/**
* @ngdoc function
* @name verifyCreatedPromise
*
* @description
* This function returns a promise that tries ten times to see if a
* key pair of the given name exists in the key pair listing. These
* tries are one second apart. Once it has been found, the promise
* is resolved with the key pair data. If it is not found within the
* period, the promise is rejected.
*
* @param {string} name The name for the key pair
* @returns {promise} A promise resolving if true, rejecting with error
*/
function verifyCreatedPromise(name) {
return $q(function doesKeypairExistPromise(resolve, reject) {
doesKeypairExist(10);
function doesKeypairExist(timesToCheck) {
$timeout(function doesKeypairExistTimeout() {
novaAPI.getKeypairs().then(function isKeypairInResponse(response) {
var foundKeypairs = response.data.items.filter(function sameName(item) {
return item.keypair.name === name;
});
if (foundKeypairs.length === 1) {
resolve(foundKeypairs[0].keypair);
angular.element('.download-iframes #' + name).remove();
} else if (timesToCheck > 1) {
doesKeypairExist(timesToCheck - 1);
} else {
reject();
angular.element('.download-iframes #' + name).remove();
}
});
},
1000);
}
});
}
}
})();