Viewing File: /usr/local/cpanel/whostmgr/docroot/templates/backup_configuration/views/destinations.js

/*
# backup_configuration/views/destinations.js       Copyright 2022 cPanel, L.L.C.
#                                                           All rights reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited
*/

/* global define */

define(
    [
        "angular",
        "lodash",
        "cjt/util/locale",
        "cjt/util/table",
        "cjt/services/alertService",
        "cjt/directives/alertList",
        "cjt/directives/toggleSortDirective",
        "cjt/directives/actionButtonDirective",
        "cjt/directives/validationContainerDirective",
        "cjt/directives/validationItemDirective",
        "cjt/validator/datatype-validators",
        "cjt/validator/username-validators",
        "cjt/validator/compare-validators",
        "app/services/backupConfigurationServices",
        "app/services/validationLog"
    ],
    function(angular, _, LOCALE, Table) {
        "use strict";

        var app = angular.module("whm.backupConfiguration");

        var table = new Table();

        var controller = app.controller(
            "destinations", [
                "$scope",
                "$location",
                "$q",
                "$window",
                "backupConfigurationServices",
                "alertService",
                "$timeout",
                "validationLog",

                function(
                    $scope,
                    $location,
                    $q,
                    $window,
                    backupConfigurationServices,
                    alertService,
                    $timeout,
                    validationLog) {

                    /**
                     * Sets delete confirmation callout element to show and assigns
                     * destination properties to the $scope to be used when deleting destination
                     *
                     * @scope
                     * @method setupDeleteConfirmation
                     * @param {String} name - name of specific destination
                     * @param {String} id - unique identification string
                     */
                    $scope.setupDeleteConfirmation = function(name, id, index) {
                        $scope.index = index;
                        $scope.showDeleteConfirmation = !$scope.showDeleteConfirmation;
                        $scope.updating = !$scope.updating;
                        $scope.destinationName = name;
                        $scope.destinationId = id;
                    };

                    /**
                     * Handles backup enable toggle and sets scope property to remove
                     * focus from all inputs if backup is not enabled
                     *
                     * @scope
                     * @method enableBackupConfig
                     */
                    $scope.enableBackupConfig = function() {
                        if (!$scope.formData.backupenable) {
                            $scope.formEnabled = false;
                        } else {
                            $scope.formEnabled = true;
                        }
                    };

                    /**
                     * Is validation in progress for given destination.
                     *
                     * @scope
                     * @method isValidationInProgressFor
                     * @param {String} id - id of specific destination to test
                     * @returns {Boolean} is destination being validated
                     */
                    $scope.isValidationInProgressFor = function(destination) {
                        return validationLog.isValidationInProgressFor(destination);
                    };

                    /**
                     * Determine whether a validation process is current running.
                     *
                     * @scope
                     * @method isValidationRunning
                     * @returns {Boolean} is validation (multiple or single) process running
                     */
                    $scope.isValidationRunning = function() {
                        return validationLog.isValidationRunning();
                    };

                    /**
                     * Validates destination via API
                     *
                     * @scope
                     * @method validateDestination
                     * @param {String} id - id of specific destination to send to API
                     * @param {String} name - name of specific destination
                     * @param {Object} opts - options
                     * @param {Boolean} opts.all - if true dont clear the alert list since we are validating each destination.
                     * @returns {Promise<String>} - string indicating success
                     * @throws {Promise<String>} - string indicating error
                     */
                    $scope.validateDestination = function(id, name, opts) {
                        if (!opts) {
                            opts = {};
                        }

                        if (!opts.all) {
                            $scope.clearAlerts();
                        }

                        $scope.destinationState.validatingDestination = true;
                        $scope.displayAlertRows = [];
                        $scope.displayAlertRows.push(id);

                        var theDestination = _.find($scope.destinationState.destinationList, function(item) {
                            return item.id === id;
                        });

                        validationLog.add(theDestination);

                        $scope.currentlyValidating = validationLog.getLogEntries();

                        return backupConfigurationServices.validateDestination(id)
                            .then(function(success) {
                                var alertOptions = {
                                    type: "success",
                                    id: "validate-destination-succeeded-" + id,
                                    message: LOCALE.maketext("The validation for the “[_1]” destination succeeded.", _.escape(name)),
                                    closeable: true,
                                    autoClose: 10000,
                                };
                                if (opts.all) {
                                    alertOptions.replace = false;
                                }
                                validationLog.markAsComplete(id, alertOptions);
                                if (!$scope.destinationState.validatingAllDestinations) {
                                    alertService.add(alertOptions);
                                }
                            })
                            .catch(function(error) {
                                var alertOptions = {
                                    type: "danger",
                                    message: _.escape(error),
                                    closeable: true,
                                    replace: false,
                                    id: "validate-destination-failed-" + id,
                                };
                                if (opts.all) {
                                    alertOptions.replace = false;
                                }

                                // validation has failed, so mark existing entry in
                                // destinations list as disabled
                                theDestination.disabled = true;

                                validationLog.markAsComplete(id, alertOptions);
                                if (!$scope.destinationState.validatingAllDestinations) {
                                    alertService.add(alertOptions);
                                }
                            })
                            .finally(function() {
                                $scope.destinationState.validatingDestination = $scope.isValidationRunning();
                                $scope.destinationState.showValidationIconHint = true;
                            });
                    };

                    /**
                     * Retrieves all current destinations via API
                     *
                     * @scope
                     * @method getDestinations
                     */
                    $scope.getDestinations = function() {
                        $scope.destinationState.destinationListLoaded = false;
                        return backupConfigurationServices.getDestinationList()
                            .then(function(destinationsData) {
                                $scope.destinationState.destinationList = destinationsData;
                                $scope.destinationState.destinationListLoaded = true;
                                $scope.updating = false;
                                $scope.currentlyValidating = validationLog.getLogEntries();
                                $scope.setPagination(destinationsData);
                            }, function(error) {
                                $scope.destinationState.destinationListLoaded = true;
                                $scope.updating = false;
                                alertService.add({
                                    type: "danger",
                                    closeable: true,
                                    message: error,
                                    id: "fetch-destinations-failed"
                                });
                            });
                    };

                    /**
                     * Load data and get metadata for table of transports
                     *
                     * @scope
                     * @method setPagination
                     * @param  {Array.<TransportType>} transportData - array of transport objects
                     */
                    $scope.setPagination = function(transportData) {
                        if (transportData) {
                            table.load(transportData);
                            table.setSort("name,type", "asc");

                            // the next two lines should be removed if
                            // pagination for the table is implemented
                            table.meta.limit = transportData.length;
                            table.meta.pageSize = transportData.length;
                        }

                        table.update();
                        $scope.meta = table.getMetadata();
                        $scope.filteredDestinationList = table.getList();
                    };

                    $scope.updateTable = function() {
                        $scope.setPagination();
                    };

                    /**
                     * Sets path of destination template to retrieve
                     *
                     * @scope
                     * @method setTemplatePath
                     * @param {String} type - string indicating destination type selected
                     */
                    $scope.setTemplatePath = function(type) {
                        if (type === "Custom") {
                            $scope.templatePath = "views/customTransport.ptt";
                        } else if (type === "FTP") {
                            $scope.templatePath = "views/FTPTransport.ptt";
                        } else if (type === "GoogleDrive") {
                            $scope.templatePath = "views/GoogleTransport.ptt";
                        } else if (type === "Local" || type === "Additional Local Directory") {
                            $scope.templatePath = "views/LocalTransport.ptt";
                        } else if (type === "SFTP") {
                            $scope.templatePath = "views/SFTPTransport.ptt";
                        } else if (type === "Amazon S3" || type === "AmazonS3") {
                            $scope.templatePath = "views/AmazonS3Transport.ptt";
                        } else if (type === "Rsync") {
                            $scope.templatePath = "views/RsyncTransport.ptt";
                        } else if (type === "WebDAV") {
                            $scope.templatePath = "views/WebDAVTransport.ptt";
                        } else if (type === "S3Compatible") {
                            $scope.templatePath = "views/S3CompatibleTransport.ptt";
                        } else if (type === "Backblaze") {
                            $scope.templatePath = "views/B2.ptt";
                        }
                    };

                    /**
                     * Returns custom transport type where required.
                     *
                     * @scope
                     * @method getTransportType
                     * @param {String} type - string indicating destination type
                     * @returns {String} - type formatted for display
                     */
                    $scope.formattedTransportType = function(type) {
                        if (type === "Backblaze") {
                            return "Backblaze B2";
                        } else if (type === "GoogleDrive") {
                            return "Google Drive™";
                        }

                        return type;
                    };

                    /**
                     * Retrieves selected destination via API
                     *
                     * @scope
                     * @method getDestination
                     * @param {String} id - id of selected destination
                     * @param {String} type - type of selected destination
                     */
                    $scope.getDestination = function(id, type) {
                        $scope.destinationState.fetchingDestination = true;
                        $scope.destinationState.newMode = false;
                        $scope.setTemplatePath(type);

                        return backupConfigurationServices.getDestination(id)
                            .then(function(destinationData) {
                                $scope.destinationState.destination = destinationData;
                                $scope.destinationState.destinationMode = true;
                                $scope.destinationState.fetchingDestination = false;
                                $scope.destinationState.editMode = true;

                                if (type === "SFTP" || type === "Rsync") {
                                    $scope.getSSHKeyList();
                                }

                                if (type === "GoogleDrive") {
                                    $scope.checkCredentials(destinationData.googledrive.client_id, destinationData.googledrive.client_secret);
                                }
                            }, function(error) {
                                $scope.destinationState.fetchingDestination = false;
                                alertService.add({
                                    type: "danger",
                                    closeable: true,
                                    message: error,
                                    id: "fetch-destination-error"
                                });
                            });
                    };

                    /**
                     * Sets template path and creates new destination object
                     *
                     * @scope
                     * @method createNewDestination
                     * @param  {String} type - destination type
                     */
                    $scope.createNewDestination = function(type) {
                        $scope.destinationState.destination = {};
                        $scope.destinationState.editMode = false;
                        $scope.destinationState.newMode = true;
                        $scope.setTemplatePath(type);

                        /**
                         * New destination object created with default values per
                         * https://confluence0.cpanel.net/display/public/SDK/WHM+API+1+Functions+-+backup_destination_add
                         */

                        if (type === "Custom") {
                            $scope.destinationState.destination.custom = {
                                type: type,
                                timeout: 30
                            };
                        } else if (type === "FTP") {
                            $scope.destinationState.destination.ftp = {
                                type: type,
                                port: 21,
                                passive: true,
                                timeout: 30
                            };
                        } else if (type === "GoogleDrive") {
                            $scope.destinationState.destination.googledrive = {
                                type: type,
                                timeout: 30
                            };
                        } else if (type === "Local" || type === "Additional Local Directory") {
                            $scope.destinationState.destination.local = {
                                type: "Local",
                                mount: false
                            };
                        } else if (type === "SFTP") {
                            $scope.destinationState.destination.sftp = {
                                type: type,
                                authtype: "key",
                                port: 22,
                                timeout: 30
                            };
                            $scope.getSSHKeyList();
                        } else if (type === "AmazonS3") {
                            $scope.destinationState.destination.amazons3 = {
                                type: "AmazonS3",
                                timeout: 30
                            };
                        } else if (type === "S3Compatible") {
                            $scope.destinationState.destination.s3compatible = {
                                type: "S3Compatible",
                                timeout: 30
                            };
                        } else if (type === "Rsync") {
                            $scope.destinationState.destination.rsync = {
                                type: type,
                                authtype: "key",
                                timeout: 30,
                                port: 22
                            };
                            $scope.getSSHKeyList();
                        } else if (type === "WebDAV") {
                            $scope.destinationState.destination.webdav = {
                                type: type
                            };
                        } else if (type === "Backblaze") {
                            $scope.destinationState.destination.backblaze = {
                                type: type,
                                timeout: 180
                            };
                        }
                        $scope.destinationState.destinationMode = true;
                    };

                    /**
                     * Saves new destination via API
                     *
                     * @scope
                     * @param {<CustomTransportType | FTPTransportType | GoogleTransportType | LocalTransportType | SFTPTransportType | AmazonS3TransportType | RsyncTransportType | WebDAVTransportType | S3CompatibleTransportType>} destination - object representing destination config
                     * @param {Boolean} [shouldValidate] - whether the destination should also be validated as well as saved
                     * @method saveDestination
                     * @returns {Promise<String>} - id indicating success in case destination also needs to be validated
                     * @throws {Promise<String>} - string indicating error
                     */
                    $scope.saveDestination = function(destination, shouldValidate) {
                        $scope.clearAlerts();
                        $scope.destinationState.savingDestination = true;
                        var property = Object.keys(destination);
                        var destinationName = destination[property[0]]["name"];
                        if ($scope.destinationState.newMode) {
                            return backupConfigurationServices.setNewDestination(destination)
                                .then(function(response) {
                                    $scope.destinationId = response.id;
                                    $scope.destinationState.googleCredentialsGenerated = false;
                                    $scope.destinationState.destinationMode = false;
                                    $scope.destinationState.newMode = false;
                                    alertService.add({
                                        type: "success",
                                        autoClose: 5000,
                                        message: LOCALE.maketext("The system successfully saved the “[_1]” destination.", _.escape(destinationName)),
                                        id: "save-new-destination-success"
                                    });

                                    if (destination[property[0]]["type"] === "GoogleDrive") {
                                        $scope.destinationState.checkCredentialsOnSave = true;
                                        $scope.checkCredentials(destination[property[0]]["client_id"], destination[property[0]]["client_secret"], $scope.destinationState.checkCredentialsOnSave);
                                    }

                                    return $scope.getDestinations();
                                })
                                .then(function() {
                                    if (shouldValidate) {

                                        // pass all=true for options so save message not overwritten by validate message
                                        $scope.validateDestination($scope.destinationId, _.escape(destinationName), { all: true });
                                    }
                                })
                                .catch(function(error) {
                                    alertService.add({
                                        type: "danger",
                                        closeable: true,
                                        message: _.escape(error),
                                        id: "save-new-destination-error"
                                    });
                                })
                                .finally(function() {
                                    $scope.destinationState.savingDestination = false;
                                });
                        } else if ($scope.destinationState.editMode) {
                            return backupConfigurationServices.updateCurrentDestination(destination)
                                .then(function(response) {
                                    $scope.destinationState.editMode = false;
                                    alertService.add({
                                        type: "success",
                                        autoClose: 5000,
                                        message: LOCALE.maketext("The system successfully saved the “[_1]” destination.", _.escape(destinationName)),
                                        id: "edit-destination-success"
                                    });

                                    if (destination[property[0]]["type"] === "GoogleDrive") {
                                        $scope.destinationState.checkCredentialsOnSave = true;
                                        $scope.checkCredentials(destination[property[0]]["client_id"], destination[property[0]]["client_secret"], $scope.destinationState.checkCredentialsOnSave);
                                    }

                                    $scope.destinationState.destinationMode = false;
                                    return $scope.getDestinations();
                                })
                                .then(function() {

                                    // update any existing entry in validation results table to reflect
                                    // potential edits to the name

                                    var editedId = destination[property[0]]["id"];

                                    validationLog.updateValidationInfo(editedId, _.escape(destinationName));

                                    if (shouldValidate) {

                                        // pass all=true for options so save message not overwritten by validate message
                                        $scope.validateDestination(destination[property[0]]["id"], _.escape(destinationName), { all: true });
                                    }
                                })
                                .catch(function(error) {
                                    alertService.add({
                                        type: "danger",
                                        closeable: true,
                                        message: error,
                                        id: "edit-destination-error"
                                    });
                                })
                                .finally(function() {
                                    $scope.destinationState.savingDestination = false;
                                });
                        }

                    };

                    /**
                     * Saves and validates destination, saveDestination resolves
                     * into destination id
                     *
                     * @scope
                     * @method saveAndValiidateDestination
                     * @param {<CustomTransportType | FTPTransportType | GoogleTransportType | LocalTransportType | SFTPTransportType | AmazonS3TransportType | RsyncTransportType | WebDAVTransportType | S3CompatibleTransportType>} destination - object representing destination config
                     */
                    $scope.saveAndValidateDestination = function(destination) {
                        var shouldValidate = true;
                        return $scope.saveDestination(destination, shouldValidate);
                    };

                    /**
                     * Cancels current destination configuration by clearing alerts
                     * and hiding destination view
                     *
                     * @scope
                     * @method cancelDestination
                     */
                    $scope.cancelDestination = function(skipScrolling) {
                        $scope.clearAlerts();

                        $scope.destinationState.destinationMode = false;
                        $scope.destinationState.editMode = false;
                        $scope.destinationState.newMode = false;
                        $scope.destinationState.googleCredentialsGenerated = false;
                        if (!skipScrolling) {
                            document.getElementById("additional_destinations_label").scrollIntoView();
                        }
                    };

                    /**
                     * Delete specific destination and then call getDestinations
                     * to display current list
                     *
                     * @scope
                     * @method deleteDestination
                     */
                    $scope.deleteDestination = function(id) {
                        $scope.deleting = true;
                        $scope.showDeleteConfirmation = false;
                        $scope.displayAlertRows = [];
                        $scope.displayAlertRows.push(id);

                        backupConfigurationServices.deleteDestination(id)
                            .then(function(success) {
                                $scope.deleting = false;

                                // delete existing entry from validation results if one exists
                                validationLog.remove(id);
                                $scope.currentlyValidating = validationLog.getLogEntries();
                                alertService.add({
                                    type: "success",
                                    autoClose: 5000,
                                    id: "delete-destination-success",
                                    message: LOCALE.maketext("The system successfully deleted the “[_1]” destination.", _.escape($scope.destinationName))
                                });
                                $scope.getDestinations();
                            }, function(error) {
                                $scope.deleting = false;
                                $scope.updating = false;
                                alertService.add({
                                    type: "danger",
                                    id: "delete-destination-failed",
                                    closeable: true,
                                    message: error
                                });
                            });
                    };

                    /**
                     * Toggle status of destination then call getDestinations to show current status
                     *
                     * @scope
                     * @method toggleStatus
                     * @param  {<CustomTransportType | FTPTransportType | GoogleTransportType | LocalTransportType | SFTPTransportType | AmazonS3TransportType | RsyncTransportType | WebDAVTransportType>} destination - object representing destination config
                     */
                    $scope.toggleStatus = function(destination) {
                        $scope.toggled = false;
                        $scope.updating = true;

                        $scope.displayAlertRows = [];
                        $scope.displayAlertRows.push(destination.id);

                        var disable,
                            message;
                        if (!destination.disabled) {
                            message = LOCALE.maketext("You disabled the destination “[_1]”.", _.escape(destination.name));
                            disable = true;
                        } else if (destination.disabled) {
                            message = LOCALE.maketext("You enabled the destination “[_1]”.", _.escape(destination.name));
                            disable = false;
                        }

                        return backupConfigurationServices.toggleStatus(destination.id, disable)
                            .then(function(success) {
                                alertService.add({
                                    type: "success",
                                    autoClose: 5000,
                                    id: "toggle-destination-success",
                                    message: message
                                });
                                destination.disabled = !destination.disabled;
                            }, function(error) {
                                alertService.add({
                                    type: "danger",
                                    closeable: true,
                                    id: "toggle-destination-failed",
                                    message: error
                                });
                            })
                            .finally(function() {

                                // toggled set to true so that "in process" message
                                // disappears, error message still visible
                                $scope.toggled = true;
                                $scope.updating = false;
                            });
                    };

                    /**
                     * Validate all current destinations via API
                     *
                     * @scope
                     * @method validateAllDestinations
                     */
                    $scope.validateAllDestinations = function() {
                        $scope.currentlyValidating = [];
                        $scope.destinationState.validatingAllDestinations = true;
                        var promises = [];

                        angular.forEach($scope.destinationState.destinationList, function(destination) {
                            promises.push($scope.validateDestination(destination.id, _.escape(destination.name), {
                                all: true
                            }));
                        });
                        return $q.all(promises).finally(function() {
                            $scope.destinationState.validatingAllDestinations = false;
                            $scope.destinationState.validatingDestination = $scope.isValidationRunning();
                        });
                    };

                    /**
                    * Checks whether the validation process for a particular
                    * destination succeeded.
                    *
                    * @scope
                    * @method validateAllSuccessFor
                    * @param {String} id - unique identification string
                    */
                    $scope.validateAllSuccessFor = function(id) {
                        return validationLog.validateAllSuccessFor(id);
                    };

                    /**
                     * Checks whether the validation process for a particular
                     * destination failed.
                     *
                     * @scope
                     * @method validateAllFailureFor
                     * @param {String} id - unique identification string
                     */
                    $scope.validateAllFailureFor = function(id) {
                        return validationLog.validateAllFailureFor(id);
                    };

                    /**
                    * Displays alert message for validation result
                    *
                    * @scope
                    * @method showValidationMessageFor
                    * @param {String} id - unique identification string
                    */
                    $scope.showValidationMessageFor = function(id) {
                        validationLog.showValidationMessageFor(id);
                    };

                    /**
                     * Generates Google user credentials
                     *
                     * @scope
                     * @method generateCredentials
                     * @param {String} clientId - unique identifying string of user from Google Drive API
                     * @param {String} clientSecret - unique secret string from Google Drive API
                     */
                    $scope.generateCredentials = function(clientId, clientSecret) {

                        $scope.destinationState.generatingCredentials = true;
                        return backupConfigurationServices.generateGoogleCredentials(clientId, clientSecret)
                            .then(function(response) {
                                $scope.destinationState.generatingCredentials = false;
                                alertService.add({
                                    type: "info",
                                    closeable: true,
                                    replace: false,
                                    message: LOCALE.maketext("A new window will appear that will allow you to generate Google® credentials."),
                                    id: "check-google-credentials-popup-" + clientId.substring(0, 6)
                                });
                                $timeout(function() {
                                    $window.open(response.uri, "generate_google_credentials");
                                }, 2000);
                            }, function(error) {
                                $scope.destinationState.generatingCredentials = false;
                                alertService.add({
                                    type: "danger",
                                    closeable: true,
                                    message: error,
                                    replace: false,
                                    id: "generate-google-credentials-failed-" + clientId.substring(0, 6)
                                });
                            });
                    };

                    /**
                     * Checks is Google user credentials are generated
                     *
                     * @scope
                     * @method checkCredentials
                     * @param  {String}  clientId - unique identifying string of user from Google Drive API
                     * @param  {String}  clientSecret - unique secret string from Google Drive API
                     * @param  {Boolean} checkOnSave - if the credentials should be checked from a save event
                     * @returns {Boolean} - returns false if credentials do not exist to alert user on save event
                     */
                    $scope.checkCredentials = function(clientId, clientSecret, checkOnSave) {
                        return backupConfigurationServices.checkForGoogleCredentials(clientId)
                            .then(function(exists) {
                                if (exists) {
                                    $scope.destinationState.googleCredentialsGenerated = true;
                                } else if (checkOnSave && !exists) {
                                    $scope.destinationState.googleCredentialsGenerated = false;
                                    alertService.add({
                                        type: "warning",
                                        closeable: true,
                                        replace: false,
                                        message: LOCALE.maketext("No [asis,Google Drive™] credentials have been generated for client id, “[_1]” ….", _.escape(clientId.substring(0, 5))) + LOCALE.maketext("You must generate new credentials to access destinations that require this client [asis,ID]."),
                                        id: "no-google-credentials-generated-warning-" + clientId.substring(0, 6)
                                    });
                                } else if (!checkOnSave) {
                                    $scope.generateCredentials(clientId, clientSecret);
                                }
                            }, function(error) {
                                $scope.destinationState.googleCredentialsGenerated = false;
                                alertService.add({
                                    type: "danger",
                                    closeable: true,
                                    message: error,
                                    group: "failed-during-check-google-credentials-error"
                                });
                            });
                    };

                    /**
                     * Toggles between showing and hiding key generation form
                     *
                     * @scope
                     * @method toggleKeyGenerationForm
                     */
                    $scope.toggleKeyGenerationForm = function() {
                        $scope.destinationState.showKeyGenerationForm = !$scope.destinationState.showKeyGenerationForm;
                    };

                    /**
                     * Creates new SSH key for SFTP transport
                     *
                     * @scope
                     * @method generateKey
                     * @param  {SSHKeyConfigType} keyConfig - object representing key configuration
                     */
                    $scope.generateKey = function(keyConfig) {
                        $scope.destinationState.generatingKey = true;
                        var username;
                        if ($scope.destinationState.destination.sftp) {
                            username = $scope.destinationState.destination.sftp.username;
                        } else if ($scope.destinationState.destination.rsync) {
                            username = $scope.destinationState.destination.rsync.username;
                        }
                        backupConfigurationServices.generateSSHKeyPair(keyConfig, username)
                            .then(function() {
                                $scope.destinationState.generatingKey = false;
                                alertService.add({
                                    type: "success",
                                    autoClose: 5000,
                                    id: "ssh-key-generation-succeeded",
                                    message: LOCALE.maketext("The system generated the key successfully.")
                                });

                                if ($scope.destinationState.destination.sftp) {
                                    $scope.destinationState.destination.sftp.privatekey = $scope.setPrivateKey(keyConfig.name);
                                } else if ($scope.destinationState.destination.rsync) {
                                    $scope.destinationState.destination.rsync.privatekey = $scope.setPrivateKey(keyConfig.name);
                                }

                                $scope.toggleKeyGenerationForm();
                                $scope.getSSHKeyList();
                            }, function(error) {
                                $scope.destinationState.generatingKey = false;
                                alertService.add({
                                    type: "danger",
                                    closeable: true,
                                    message: error,
                                    id: "ssh-key-generation-failed"
                                });
                            });
                    };

                    /**
                     * Gets list of all private SSH keys for root user
                     *
                     * @scope
                     * @method getSSHKeyList
                     */
                    $scope.getSSHKeyList = function() {
                        $scope.destinationState.sshKeyListLoaded = false;
                        backupConfigurationServices.listSSHKeys()
                            .then(function(response) {
                                $scope.destinationState.sshKeyListLoaded = true;
                                $scope.destinationState.sshKeyList = response;
                            }, function(error) {
                                $scope.destinationState.sshKeyListLoaded = true;
                                alertService.add({
                                    type: "danger",
                                    message: error,
                                    closeable: true,
                                    id: "ssh-keys-fetch-failed"
                                });

                            });
                    };

                    /**
                     * Sets private key path when key is chosen from list of keys that currently exist
                     *
                     * @scope
                     * @method setPrivateKey
                     * @param {String} key - name of private key file
                     */
                    $scope.setPrivateKey = function(key) {
                        var keyName = "/root/.ssh/" + key;
                        if ($scope.destinationState.destination.sftp) {
                            $scope.destinationState.destination.sftp.privatekey = keyName;
                        } else if ($scope.destinationState.destination.rsync) {
                            $scope.destinationState.destination.rsync.privatekey = keyName;
                        }

                        var privateKeyField = $window.document.getElementById("private_key");
                        if (typeof privateKeyField !== "undefined") {
                            privateKeyField.select();
                            privateKeyField.focus();
                        }

                        return keyName;
                    };

                    /**
                     * Locks key size at 1024 if algorithm chosen is DSA
                     *
                     * @scope
                     * @method toggleKeyType
                     * @param  {String} algorithm - string indicating what algorithm to use for key generation
                     */
                    $scope.toggleKeyType = function(algorithm) {
                        if (algorithm === "DSA") {
                            this.newSSHKey.bits = "1024";
                            this.destinationState.keyBitsSet = true;

                            if (!this.newSSHKey.name || this.newSSHKey.name === "") {
                                this.newSSHKey.name = "id_dsa";
                            }
                        } else if (algorithm === "RSA") {
                            this.newSSHKey.bits = "4096";
                            this.destinationState.keyBitsSet = false;

                            if (!this.newSSHKey.name || this.newSSHKey.name === "") {
                                this.newSSHKey.name = "id_rsa";
                            }
                        }
                    };

                    /**
                     * Clears alerts from all groups
                     *
                     * @scope
                     * @method clearAlerts
                     */
                    $scope.clearAlerts = function() {
                        alertService.clear();
                    };

                    /**
                     * Toggle SSL activation in WebDAV
                     *
                     * @scope
                     * @method toggleSSLWebDAV
                     */
                    $scope.toggleSSLWebDAV = function() {
                        $scope.destinationState.destination.webdav.ssl = !$scope.destinationState.destination.webdav.ssl;
                    };

                    /**
                     * Checks to make sure remote host does not loop back
                     *
                     * @scope
                     * @method checkForLoopBack
                     * @param  {String} host - name of remote host
                     */
                    $scope.checkForLoopBack = function(host) {
                        if (host === $scope.remoteHostLoopbackValue) {
                            $scope.destinationState.isLoopback = true;
                        } else {
                            $scope.destinationState.isLoopback = false;
                        }
                    };

                    /**
                     * Checks backup directory path for invalid characters
                     *
                     * @scope
                     * @method checkForDisallowedChars
                     * @param  {String} path - path to backup directory
                     * @param  {String} chars -string indicating disallowed characters
                     */
                    $scope.checkForDisallowedChars = function(path, chars) {

                        // test will always start at beginning of string
                        chars.lastIndex = 1;
                        var result = chars.test(path);
                        $scope.destinationState.isDisallowedChar = result;
                    };

                    /**
                     * Prevent typing of decimal points (periods) in field
                     *
                     * @scope
                     * @method noDecimalPoints
                     * @param {keyEvent} key event associated with key down
                     */

                    $scope.noDecimalPoints = function(keyEvent) {

                        // keyEvent is jQuery wrapper for KeyboardEvent
                        // better to look at properties in wrapped event
                        var actualEvent = keyEvent.originalEvent;

                        // future proofing: "key" is better property to use
                        // but is not completely supported
                        if ((actualEvent.hasOwnProperty("key") && actualEvent.key === ".") ||
                            (actualEvent.keyCode === 190)) {
                            keyEvent.preventDefault();
                        }
                    };

                    /**
                     * Prevent pasting of non-numbers in field
                     *
                     * @scope
                     * @method onlyNumbers
                     * @param {clipboardEvent} clipboard event associated with paste
                     */

                    $scope.onlyNumbers = function(pasteEvent) {
                        var pastedData = pasteEvent.originalEvent.clipboardData.getData("text");

                        if (!pastedData.match(/[0-9]+/)) {
                            pasteEvent.preventDefault();
                        }
                    };

                    /**
                     * Initialize page with default values
                     *
                     * @scope
                     * @method init
                     */
                    $scope.init = function() {
                        $scope.absolutePathRegEx = /^\/./;
                        $scope.relativePathRegEx = /^\w./;
                        $scope.remoteHostValidation = /^[a-z0-9.-]{1,}$/i;
                        $scope.remoteHostLoopbackValue = /^(127(\.\d+){1,3}|[0:]+1|localhost)$/i;
                        $scope.disallowedPathChars = /[\\?%*:|"<>]/g;

                        $scope.validating = false;
                        $scope.toggled = true;
                        $scope.saving = false;
                        $scope.deleting = false;
                        $scope.updating = false;
                        $scope.showDeleteConfirmation = false;
                        $scope.destinationName = "";
                        $scope.destinationId = "";
                        $scope.activeTab = 1;
                        $scope.currentlyValidating = validationLog.getLogEntries();

                        $scope.destinationState = {
                            destinationSelected: "Custom",
                            destinationMode: false,
                            savingDestination: false,
                            validatingDestination: $scope.isValidationRunning(),
                            fetchingDestination: false,
                            destinationListLoaded: false,
                            validatingAllDestinations: false,
                            destinationList: [],
                            newMode: false,
                            editMode: false,
                            generatingCredentials: false,
                            googleCredentialsGenerated: false,
                            showKeyGenerationForm: false,
                            generatingKey: false,
                            keyBitsSet: false,
                            sshKeyListLoaded: false,
                            isLoopback: false,
                            isDisallowedChar: false,
                            checkCredentialsOnSave: false,
                            showValidationIconHint: false
                        };

                        if (validationLog.hasLogEntries()) {
                            $scope.destinationState.showValidationIconHint = true;
                        }

                        $scope.meta = {};

                        $scope.displayAlertRows = [];
                        $scope.getDestinations();
                    };
                    $scope.init();
                }
            ]
        );

        return controller;
    }
);
Back to Directory File Manager