/*
# templates/mod_security/views/commonController.js Copyright(c) 2020 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 */
/* ------------------------------------------------------------------------------
* DEVELOPER NOTES:
* 1) Put all common application functionality here, maybe
*-----------------------------------------------------------------------------*/
define(
'app/views/commonController',[
"angular",
"cjt/filters/wrapFilter",
"cjt/services/alertService",
"cjt/directives/alertList",
"uiBootstrap"
],
function(angular) {
var app;
try {
app = angular.module("App");
} catch (e) {
app = angular.module("App", ["ui.bootstrap", "ngSanitize"]);
}
var controller = app.controller(
"commonController",
["$scope", "$location", "$rootScope", "alertService", "PAGE",
function($scope, $location, $rootScope, alertService, PAGE) {
// Setup the installed bit...
$scope.isInstalled = PAGE.installed;
// Bind the alerts service to the local scope
$scope.alerts = alertService.getAlerts();
$scope.route = null;
/**
* Closes an alert and removes it from the alerts service
*
* @method closeAlert
* @param {String} index The array index of the alert to remove
*/
$scope.closeAlert = function(id) {
alertService.remove(id);
};
/**
* Determines if the current view matches the supplied pattern
*
* @method isCurrentView
* @param {String} view The path to the view to match
*/
$scope.isCurrentView = function(view) {
if ( $scope.route && $scope.route.$$route ) {
return $scope.route.$$route.originalPath === view;
}
return false;
};
// register listener to watch route changes
$rootScope.$on( "$routeChangeStart", function(event, next, current) {
$scope.route = next;
});
}
]);
return controller;
}
);
/*
# templates/mod_security/services/vendorService.js Copyright(c) 2020 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: false */
define(
'app/services/vendorService',[
// Libraries
"angular",
// CJT
"cjt/util/locale",
"cjt/util/parse",
"cjt/io/api",
"cjt/io/whm-v1-request",
"cjt/io/whm-v1", // IMPORTANT: Load the driver so its ready
// Angular components
"cjt/services/APIService"
],
function(angular, LOCALE, PARSE, API, APIREQUEST, APIDRIVER) {
// Constants
var NO_MODULE = "";
// Fetch the current application
var app = angular.module("App");
/**
* Normalize the vendor to account for any missing data, type conversion, etc.
*
* @method _normalizeVendor
* @private
* @param {Object} vendor Vendor returned from the server.
* @return {Object} Vendor with all the fields normalized and patched.
*/
function _normalizeVendor(vendor) {
vendor.cpanel_provided = PARSE.parsePerlBoolean(vendor.cpanel_provided);
vendor.enabled = PARSE.parsePerlBoolean(vendor.enabled);
vendor.update = PARSE.parsePerlBoolean(vendor.update);
vendor.installed = PARSE.parsePerlBoolean(vendor.installed);
vendor.totalEnabled = 0;
vendor.totalDisabled = 0;
if (vendor.configs) {
for (var i = 0, l = vendor.configs.length; i < l; i++) {
var config = vendor.configs[i];
config.enabled = PARSE.parsePerlBoolean(config.active);
delete config.active;
if (config.enabled) {
vendor.totalEnabled++;
} else {
vendor.totalDisabled++;
}
}
// Sort initially by config
vendor.configs.sort(function(configA, configB) {
return configA.config.localeCompare(configB.config);
});
}
return vendor;
}
/**
* Converts the response to our application data structure
* @method _convertResponseToList
* @private
* @param {Object} response
* @return {Object} Sanitized data structure.
*/
function _convertResponseToList(response) {
var items = [];
if (response.status) {
var data = response.data;
for (var i = 0, length = data.length; i < length; i++) {
var vendor = data[i];
// Mark the record as unchanged
vendor.changed = false;
items.push(
_normalizeVendor(vendor)
);
}
var meta = response.meta;
var totalItems = meta.paginate.total_records || data.length;
var totalPages = meta.paginate.total_pages || 1;
return {
items: items,
totalItems: totalItems,
totalPages: totalPages
};
} else {
return {
items: [],
totalItems: 0,
totalPages: 0
};
}
}
/**
* Normalize the outcome for an enable/disable config operation for
* missing data, type conversion, etc.
*
* @method _normalizeOutcome
* @private
* @param {Object} outcome Outcome returned from the server.
* @param {Boolean} enableCalled true if we are trying to enable, false otherwise
* @return {Object} Outcome with all the fields normalized and patched.
*/
function _normalizeOutcome(outcome, enableCalled) {
var ok = PARSE.parsePerlBoolean(outcome.ok);
outcome.ok = ok;
outcome.enabled = enableCalled ? ok : !ok;
return outcome;
}
/**
* Cleans up the response for outcomes
*
* @method _convertOutcomeResponseToList
* @private
* @param {Array} outcomes
* @param {Boolean} enableCalled true if we are trying to enable, false otherwise
* @return {Array} Sanitized data structure.
*/
function _convertOutcomeResponseToList(data, enableCalled) {
var configs = [];
var totalEnabled = 0;
var totalDisabled = 0;
if (data) {
for (var i = 0, length = data.length; i < length; i++) {
var config = data[i];
configs.push(
_normalizeOutcome(config, enableCalled)
);
if (config.enabled) {
totalEnabled++;
} else {
totalDisabled++;
}
}
}
return {
configs: configs,
totalEnabled: totalEnabled,
totalDisabled: totalDisabled
};
}
/**
* Returns a promise with vendor information that optionally adds the vendor to the list
*
* @method _returnVendor
* @private
* @param {Deferred} deferred
* @param {String} method The API method to call.
* @param {Object} parameters Parameters for the add and preview methods
* @param {String} url Vendor URL for the YAML file describing the vendor configuration.
* @return {Promise}
*/
var _returnVendor = function(deferred, method, parameters) {
var apiCall = new APIREQUEST.Class();
apiCall.initialize(NO_MODULE, method);
apiCall.addArgument("url", parameters.url);
this.deferred(apiCall, {
transformAPISuccess: function(response) {
return response.data;
}
}, deferred);
// pass the promise back to the controller
return deferred.promise;
};
/**
* Setup the configuration models API service
*/
app.factory("vendorService", ["$q", "APIService", function($q, APIService) {
// Set up the service's constructor and parent
var VendorService = function() {};
VendorService.prototype = new APIService();
// Extend the prototype with any class-specific functionality
angular.extend(VendorService.prototype, {
/**
* Get a single vendor by its id from the backend.
*
* @method fetchVendorById
* @param {number} vendorId Id of the vendor to fetch.
* @return {Promise} Promise that will fulfill the request.
*/
fetchVendorById: function(vendorId) {
var apiCall = new APIREQUEST.Class();
apiCall.initialize(NO_MODULE, "modsec_get_vendors");
apiCall.addArgument("show_uninstalled", 1);
apiCall.addFilter("vendor_id", "eq", vendorId);
var deferred = this.deferred(apiCall, {
apiSuccess: function(response, deferred) {
var results = _convertResponseToList(response);
if (results.items.length === 1) {
deferred.resolve(results.items[0]);
} else if (results.items.length > 1) {
deferred.reject(LOCALE.maketext("You have multiple vendors with the same [asis,vendor_id]."));
} else {
deferred.reject(LOCALE.maketext("The system could not find the specified [asis,vendor_id].", vendorId));
}
}
});
// pass the promise back to the controller
return deferred.promise;
},
/**
* Get a list of vendors
* * @param {object} meta Optional meta data to control sorting, filtering and paging
* @param {string} meta.sortBy Name of the field to sort by
* @param {string} meta.sordDirection asc or desc
* @param {string} meta.sortType Optional name of the sort rule to apply to the sorting
* @param {string} meta.filterBy Name of the field to filter by
* @param {string} meta.filterCompare Optional comparator to use when comparing for filter.
* @param {string} meta.filterValue Expression/argument to pass to the compare method.
* @param {string} meta.pageNumber Page number to fetch.
* @param {string} meta.pageSize Size of a page, will default to 10 if not provided.
* @return {Promise} Promise that will fulfill the request.
*/
fetchList: function(meta) {
var apiCall = new APIREQUEST.Class();
apiCall.initialize(NO_MODULE, "modsec_get_vendors");
apiCall.addArgument("show_uninstalled", 1);
if (meta) {
if (meta.sortBy && meta.sortDirection) {
apiCall.addSorting(meta.sortBy, meta.sortDirection, meta.sortType);
}
if (meta.pageNumber) {
apiCall.addPaging(meta.pageNumber, meta.pageSize || 10);
}
if (meta.filterBy && meta.filterValue) {
apiCall.addFilter(meta.filterBy, meta.filterCompare, meta.filterValue);
}
}
return this.deferred(apiCall, {
transformAPISuccess: _convertResponseToList
}).promise;
},
/**
* Disable a vendor by id
*
* @method disableVendor
* @param {Number} id Vendor id.
* @return {Promise}
*/
disableVendor: function(id) {
var apiCall = new APIREQUEST.Class();
apiCall.initialize(NO_MODULE, "modsec_disable_vendor");
apiCall.addArgument("vendor_id", id);
return this.deferred(apiCall).promise;
},
/**
* Enable a vendor by id
*
* @method enableRule
* @param {Number} id Vendor id.
* @return {Promise}
*/
enableVendor: function(id) {
var apiCall = new APIREQUEST.Class();
apiCall.initialize(NO_MODULE, "modsec_enable_vendor");
apiCall.addArgument("vendor_id", id);
return this.deferred(apiCall).promise;
},
/**
* Disable a config file by path
*
* @method disableConfig
* @param {String} config Path to the specific config file.
* @return {Promise}
*/
disableConfig: function(config) {
var apiCall = new APIREQUEST.Class();
apiCall.initialize(NO_MODULE, "modsec_make_config_inactive");
apiCall.addArgument("config", config);
return this.deferred(apiCall).promise;
},
/**
* Enable a config file by path
*
* @method disableConfig
* @param {String} config Path to the specific config file.
* @return {Promise}
*/
enableConfig: function(config) {
var apiCall = new APIREQUEST.Class();
apiCall.initialize(NO_MODULE, "modsec_make_config_active");
apiCall.addArgument("config", config);
return this.deferred(apiCall).promise;
},
/**
* Enable all the config files for a vendor
*
* @method enableAllConfigs
* @param {String} id Vendor id.
* @return {Promise}
*/
enableAllConfigs: function(id) {
var apiCall = new APIREQUEST.Class();
apiCall.initialize(NO_MODULE, "modsec_enable_vendor_configs");
apiCall.addArgument("vendor_id", id);
var deferred = this.deferred(apiCall, {
transformAPISuccess: function(response) {
return _convertOutcomeResponseToList(response.data, true);
},
transformAPIFailure: function(response) {
return _convertOutcomeResponseToList(response.data, true);
}
});
return deferred.promise;
},
/**
* Disable all the config files for a vendor
*
* @method disableAllConfigs
* @param {String} id Vendor id.
* @return {Promise}
*/
disableAllConfigs: function(id) {
// make a promise
var apiCall = new APIREQUEST.Class();
apiCall.initialize(NO_MODULE, "modsec_disable_vendor_configs");
apiCall.addArgument("vendor_id", id);
var deferred = this.deferred(apiCall, {
transformAPISuccess: function(response) {
return _convertOutcomeResponseToList(response.data, false);
},
transformAPIFailure: function(response) {
return _convertOutcomeResponseToList(response.data, false);
}
});
// pass the promise back to the controller
return deferred.promise;
},
/**
* Enable automatic updates for a vendor
*
* @method enableVendorUpdates
* @param {String} id Vendor id.
* @return {Promise}
*/
enableVendorUpdates: function(id) {
var apiCall = new APIREQUEST.Class();
apiCall.initialize(NO_MODULE, "modsec_enable_vendor_updates");
apiCall.addArgument("vendor_id", id);
var deferred = this.deferred(apiCall);
return deferred.promise;
},
/**
* Disable automatic updates for a vendor
*
* @method disableVendorUpdates
* @param {String} id Vendor id.
* @return {Promise}
*/
disableVendorUpdates: function(id) {
var apiCall = new APIREQUEST.Class();
apiCall.initialize(NO_MODULE, "modsec_disable_vendor_updates");
apiCall.addArgument("vendor_id", id);
var deferred = this.deferred(apiCall);
return deferred.promise;
},
/**
* Remove a vendor from the system by its id
*
* @method deleteVendor
* @param {Number} id Vendor id for the vendor to delete.
* @return {Promise} Promise that will fulfill the request.
*/
deleteVendor: function(id) {
var apiCall = new APIREQUEST.Class();
apiCall.initialize(NO_MODULE, "modsec_remove_vendor");
apiCall.addArgument("vendor_id", id);
var deferred = this.deferred(apiCall);
return deferred.promise;
},
/**
* Retrieves vendor information from a remote URL containing configuration information
* stored in a YAML format.
*
* @method loadVendor
* @param {String} url Vendor URL for the YAML file describing the vendor configuration.
* @return {Promise} Promise that will fulfill the request.
*/
loadVendor: function(url) {
// make a promise
var deferred = $q.defer(),
parameters = {
url: url
};
// pass the promise back to the controller
return _returnVendor.call(this, deferred, "modsec_preview_vendor", parameters);
},
/**
* Adds a vendor configuration to the list of vendors
*
* @method saveVendor
* @param {String} url Vendor URL for the YAML file describing the vendor configuration.
* @return {Promise} Promise that will fulfill the request.
*/
saveVendor: function(url) {
// make a promise
var deferred = $q.defer(),
parameters = {
url: url,
};
// pass the promise back to the controller
return _returnVendor.call(this, deferred, "modsec_add_vendor", parameters);
},
/**
* Helper method that calls _convertResponseToList to prepare the data structure
*
* @method prepareList
* @param {Object} response
* @return {Object} Sanitized data structure.
*/
prepareList: function(response) {
// Since this is coming from the backend, but not through the api.js layer,
// we need to parse it to the frontend format.
response = APIDRIVER.parse_response(response).parsedResponse;
return _convertResponseToList(response);
}
});
return new VendorService();
}]);
}
);
/*
# templates/mod_security/views/vendorListController.js Copyright(c) 2020 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(
'app/views/vendorListController',[
"angular",
"cjt/util/locale",
"uiBootstrap",
"cjt/directives/actionButtonDirective",
"cjt/directives/responsiveSortDirective",
"cjt/decorators/paginationDecorator",
"cjt/directives/autoFocus",
"cjt/directives/spinnerDirective",
"cjt/services/alertService",
"app/services/vendorService",
"cjt/io/whm-v1-querystring-service"
],
function(angular, LOCALE) {
// Retrieve the current application
var app = angular.module("App");
var controller = app.controller(
"vendorListController", [
"$scope",
"$location",
"$anchorScroll",
"$routeParams",
"$timeout",
"vendorService",
"alertService",
"spinnerAPI",
"queryService",
"PAGE",
function(
$scope,
$location,
$anchorScroll,
$routeParams,
$timeout,
vendorService,
alertService,
spinnerAPI,
queryService,
PAGE) {
/**
* Load the edit vendor view with the requested vendor.
*
* @method loadEditVendorView
* @param {Object} vendor
* @param {Boolean} force if true, will show the special warning.
*/
$scope.loadEditVendorView = function(vendor, force) {
var args = { id: vendor.vendor_id };
if (typeof (force) !== "undefined" && force === true) {
args["force"] = true.toString();
}
$scope.loadView("vendors/edit", args);
};
/**
* Clear the search query
*
* @method clearFilter
* @return {Promise}
*/
$scope.clearFilter = function() {
$scope.meta.filterValue = "";
$scope.activeSearch = false;
$scope.filteredData = false;
// Leave history so refresh works
queryService.query.clearSearch();
// select the first page of search results
return $scope.selectPage(1);
};
/**
* Start a search query
*
* @method startFilter
* @return {Promise}
*/
$scope.startFilter = function() {
$scope.activeSearch = true;
$scope.filteredData = false;
// Leave history so refresh works
queryService.query.clearSearch();
queryService.query.addSearchField("*", "contains", $scope.meta.filterValue);
return $scope.selectPage(1)
.then(function() {
$scope.filteredData = true;
});
};
/**
* Select a specific page of vendors
*
* @method selectPage
* @param {Number} [page] Optional page number, if not provided will use the current
* page provided by the scope.meta.pageNumber.
* @return {Promise}
*/
$scope.selectPage = function(page) {
// set the page if requested
if (page && angular.isNumber(page)) {
$scope.meta.pageNumber = page;
}
// Leave history so refresh works
queryService.query.updatePagination($scope.meta.pageNumber, $scope.meta.pageSize);
return $scope.fetch();
};
/**
* Sort the list of rules
*
* @param {Object} meta The sort model.
* @param {Boolean} defaultSort If true, the sort was not not initiated by the user
*/
$scope.sortList = function(meta, defaultSort) {
queryService.query.clearSort();
queryService.query.addSortField(meta.sortBy, meta.sortType, meta.sortDirection);
if (!defaultSort) {
$scope.fetch();
}
};
/**
* Handles the keybinding for the clearing and searching.
* Esc clears the search field.
* Enter performs a search.
*
* @method triggerToggleSearch
* @param {Event} event - The event object
*/
$scope.triggerToggleSearch = function(event) {
// clear on Esc
if (event.keyCode === 27) {
$scope.toggleSearch(true);
}
// filter on Enter
if (event.keyCode === 13) {
$scope.toggleSearch();
}
};
/**
* Toggles the clear button and conditionally performs a search.
* The expected behavior is if the user clicks the button or focuses the button and hits enter the button state rules.
*
* @method toggleSearch
* @param {Boolean} isClick Toggle button clicked.
* @return {Promise}
*/
$scope.toggleSearch = function(isClick) {
var filter = $scope.meta.filterValue;
if ( !filter && ($scope.activeSearch || $scope.filteredData)) {
// no query in box, but we prevously filtered or there is an active search
return $scope.clearFilter();
} else if (isClick && $scope.activeSearch ) {
// User clicks clear
return $scope.clearFilter();
} else if (filter) {
return $scope.startFilter();
}
};
/**
* Fetch the list of hits from the server
*
* @method fetch
* @return {Promise} Promise that when fulfilled will result in the list being loaded with the new criteria.
*/
$scope.fetch = function() {
spinnerAPI.start("loadingSpinner");
return vendorService
.fetchList($scope.meta)
.then(function(results) {
$scope.vendors = results.items;
$scope.totalItems = results.totalItems;
$scope.totalPages = results.totalPages;
}, function(error) {
// failure
alertService.add({
type: "danger",
message: error,
id: "errorFetch"
});
})
.then(function() {
$scope.loading = false;
spinnerAPI.stop("loadingSpinner");
});
};
/**
* Set status of a specific vendor.
*
* @method setVenderStatus
* @param {Object} vendor
* @return {Promise} Promise that when fulfilled will result in the vendor status being saved.
*/
$scope.setVenderStatus = function(vendor) {
spinnerAPI.start("loadingSpinner");
if ( vendor.enabled ) {
return vendorService
.enableVendor(vendor.vendor_id)
.then(function(result) {
vendor.enabled = true;
if (vendor.in_use === 0) {
$scope.loadEditVendorView(vendor, true);
} else {
// success
alertService.add({
type: "success",
message: LOCALE.maketext("You have successfully enabled the vendor: [_1]", vendor.name),
id: "enableSuccess"
});
}
}, function(error) {
// failure
alertService.add({
type: "danger",
message: error,
id: "enableFailed"
});
vendor.enabled = false;
})
.then(function() {
spinnerAPI.stop("loadingSpinner");
});
} else {
return vendorService
.disableVendor(vendor.vendor_id)
.then(function(result) {
vendor.enabled = false;
// success
alertService.add({
type: "success",
message: LOCALE.maketext("You have successfully disabled the vendor: [_1]", vendor.name),
id: "disableSuccess"
});
}, function(error) {
// failure
alertService.add( {
type: "danger",
message: error,
id: "disableFailed"
});
})
.then(function() {
spinnerAPI.stop("loadingSpinner");
});
}
};
/**
* Sets automatic updates for a vendor.
*
* @method setVenderUpdate
* @param {Object} vendor
* @return {Promise} Promise that, when fulfilled, will result in the update status of a vender being saved.
*/
$scope.setVenderUpdate = function(vendor) {
spinnerAPI.start("loadingSpinner");
if ( vendor.update ) {
return vendorService
.enableVendorUpdates(vendor.vendor_id)
.then(function(result) {
vendor.update = true;
alertService.add( {
type: "success",
message: LOCALE.maketext("You have successfully enabled automatic updates for the vendor: [_1]", vendor.name),
id: "enableUpdatesSuccess"
} );
}, function(error) {
alertService.add( {
type: "danger",
message: error,
id: "enableUpdatesFailed"
} );
})
.then(function() {
spinnerAPI.stop("loadingSpinner");
});
} else {
return vendorService
.disableVendorUpdates(vendor.vendor_id)
.then(function(result) {
vendor.update = false;
alertService.add( {
type: "success",
message: LOCALE.maketext("You have successfully disabled automatic updates for the vendor: [_1]", vendor.name),
id: "disableUpdatesSuccess"
} );
}, function(error) {
alertService.add( {
type: "danger",
message: error,
id: "disableUpdatesFailed"
} );
})
.then(function() {
spinnerAPI.stop("loadingSpinner");
});
}
};
/**
* Install the vendor on your system.
*
* @method install
* @param {Object} vendor
* @return {Promise} Promise that when fulfilled will result in the vendor being installed on your system.
*/
$scope.install = function(vendor) {
vendor.installing = true;
return vendorService
.saveVendor(vendor.installed_from)
.then(function() {
vendor.installed = true;
// Report success
alertService.add({
type: "success",
message: LOCALE.maketext("You have successfully installed the vendor: [_1]", vendor.name),
id: "installSuccess"
});
spinnerAPI.stop("loadingSpinner");
return $scope.fetch();
}, function(error) {
// failure
alertService.add( {
type: "danger",
message: LOCALE.maketext("The system experienced the following error when it attempted to install the “[_1]” vendor: [_2]", vendor.name, error),
id: "installFailed"
});
throw error;
}).finally(function() {
// remove the process flag even if the process failed
delete vendor.installing;
});
};
/**
* Remove the vendor from your system.
*
* @method delete
* @param {Object} vendor
* @return {Promise} Promise that when fulfilled will result in the vendor being removed from your system.
*/
$scope.delete = function(vendor) {
vendor.deleting = true;
return vendorService
.deleteVendor(vendor.vendor_id)
.then(function() {
// Report success
alertService.add({
type: "success",
message: LOCALE.maketext("You have successfully removed the vendor: [_1]", vendor.name),
id: "deleteSuccess"
});
return $scope.fetch();
}, function(error) {
// We are done deleting so remove
// the signaling flag.
delete vendor.deleting;
// failure
alertService.add( {
type: "danger",
message: LOCALE.maketext("The system experienced the following error when it attempted to remove the vendor [_1]: [_2]", vendor.name, error),
id: "deleteFailed"
});
throw error;
});
};
/**
* Test if the current vendor is being deleted.
*
* @method isDeleting
* @param {Ojbect} vendor
* @return {Boolean} true if the current vendor being deleted, false otherwise.
*/
$scope.isDeleting = function(vendor) {
return vendor.deleting;
};
/**
* Show the delete confirm dialog for the vendor. Will close any other open confirms first.
*
* @method showDeleteConfirm
* @param {Object} vendor
*/
$scope.showDeleteConfirm = function(vendor) {
if (vendor.is_pkg) {
window.location.assign("../../scripts7/EasyApache4/review?uninstall=" + vendor.is_pkg);
return true;
}
if ($scope.lastConfirm) {
// Close the last one
delete $scope.lastConfirm.deleteConfirm;
delete $scope.lastConfirm.installConfirm;
}
vendor.deleteConfirm = true;
$scope.lastConfirm = vendor;
};
/**
* Hide the delete confirm dialog for the vendor
*
* @method hideDeleteConfirm
* @param {Object} vendor
*/
$scope.hideDeleteConfirm = function(vendor) {
delete vendor.deleteConfirm;
};
/**
* Test if the delete confirm dialog for a vendor should be shown.
*
* @method canShowDeleteConfirm
* @param {Object} vendor
* @return {Boolean} true if the current vendor should show the confirmation, false otherwise.
*/
$scope.canShowDeleteConfirm = function(vendor) {
// cast the value since it can be undefined
return !!vendor.deleteConfirm;
};
/**
* Test whether the vendor is installed.
*
* @method isVendorInstalled
* @param {Object} vendor
* @return {Booelan} true if the vendor is installed, false otherwise.
*/
$scope.isVendorInstalled = function(vendor) {
return vendor.installed;
};
/**
* Test if the current vendor is being installed.
* dialog.
*
* @method isInstalling
* @param {Ojbect} vendor
* @return {Boolean} true if the current vendor being installed, false otherwise.
*/
$scope.isInstalling = function(vendor) {
return vendor.installing;
};
/**
* Show the install confirm dialog for the vendor. Will close any other open confirms first.
*
* @method showInstallConfirm
* @param {Object} vendor
*/
$scope.showInstallConfirm = function(vendor) {
if ($scope.lastConfirm) {
// Close the last one
delete $scope.lastConfirm.deleteConfirm;
delete $scope.lastConfirm.installConfirm;
}
vendor.installConfirm = true;
$scope.lastConfirm = vendor;
};
/**
* Hide the install confirm dialog for the vendor
*
* @method hideInstallConfirm
* @param {Object} vendor
*/
$scope.hideInstallConfirm = function(vendor) {
delete vendor.installConfirm;
};
/**
* Test if the install confirm dialog for a vendor should be shown.
*
* @method canShowInstallConfirm
* @param {Object} vendor
* @return {Boolean} true if the current vendor should show the confirmation, false otherwise.
*/
$scope.canShowInstallConfirm = function(vendor) {
// cast the value since it can be undefined
return !!vendor.installConfirm;
};
/**
* Test if the row dialog for a vendor should be shown.
*
* @method shouldShowDialog
* @param {Object} vendor
* @return {Boolean} true if the vendor is being deleted or is not installed, false otherwise.
*/
$scope.shouldShowDialog = function(vendor) {
return $scope.canShowDeleteConfirm(vendor) || $scope.canShowInstallConfirm(vendor);
};
// setup data structures for the view
$scope.loading = true;
// Items accounting
$scope.vendors = [];
$scope.totalPages = 0;
$scope.totalItems = 0;
// Filter related flags
$scope.activeSearch = false;
$scope.filteredData = false;
$scope.lastConfirm = null;
// Meta-data for lister filter, sort and pagination
var hasPaging = queryService.route.hasPaging();
var pageSize = queryService.DEFAULT_PAGE_SIZE;
var page = 1;
if (hasPaging) {
pageSize = queryService.route.getPageSize();
page = queryService.route.getPage();
}
var sorting = queryService.route.getSortProperties("enabled", "", "asc");
var hasFilter = queryService.route.hasSearch();
var filterRules = queryService.route.getSearch();
$scope.meta = {
filterBy: hasFilter ? filterRules[0].field : "*",
filterCompare: hasFilter ? filterRules[0].type : "contains",
filterValue: hasFilter ? filterRules[0].value : "",
pageSize: hasPaging ? pageSize : queryService.DEFAULT_PAGE_SIZE,
pageNumber: hasPaging ? page : 1,
sortDirection: sorting.direction,
sortBy: sorting.field,
sortType: sorting.type,
pageSizes: queryService.DEFAULT_PAGE_SIZES
};
// if the user types something else in the search box, we change the button icon so they can search again.
$scope.$watch("meta.filterValue", function(oldValue, newValue) {
if (oldValue === newValue) {
return;
}
$scope.activeSearch = false;
});
// watch the page size and and load the first page if it changes
$scope.$watch("meta.pageSize", function(oldValue, newValue) {
if (oldValue === newValue) {
return;
}
$scope.selectPage(1);
});
// Determine if we have an active search on load
$scope.activeSearch = $scope.filteredData = $scope.meta.filterValue ? true : false;
// Setup the installed bit...
$scope.isInstalled = PAGE.installed;
// Expose any backend exceptions
$scope.exception = queryService.prefetch.failed(PAGE.vendors) ? queryService.prefetch.getMetaMessage(PAGE.vendors) : "";
// check for page data in the template if this is a first load
if (app.firstLoad.vendors && PAGE.vendors) {
app.firstLoad.vendors = false;
$scope.loading = false;
var results = vendorService.prepareList(PAGE.vendors);
$scope.vendors = results.items;
$scope.totalItems = results.totalItems;
$scope.totalPages = results.totalPages;
} else {
// Otherwise, retrieve it via ajax
$timeout(function() {
// NOTE: Without this delay the spinners are not created on inter-view navigation.
$scope.selectPage(1);
});
}
}
]
);
return controller;
}
);
/*
# ruleVendorUrlValidator.js Copyright(c) 2020 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
*/
/* --------------------------*/
/* DEFINE GLOBALS FOR LINT
/*--------------------------*/
/* global define: false */
/* --------------------------*/
/**
* This module has validators for the rule vendor url format.
*
* @module ruleVendorUrlValidator
* @requires angular, validator-utils, validate, locale
*/
define('app/directives/ruleVendorUrlValidator',[
"angular",
"lodash",
"cjt/validator/validator-utils",
"cjt/util/locale",
"cjt/validator/domain-validators",
"cjt/validator/validateDirectiveFactory"
],
function(angular, _, UTILS, LOCALE, DOMAIN_VALIDATORS) {
/**
* Expand the protocol with the colon.
*
* @private
* @method _expandProtocol
* @param {String} value
* @return {String}
*/
var _expandProtocol = function(value) {
return value + ":";
};
var VALID_PROTOCOLS = [ "http", "https" ];
var VALID_PROTOCOLS_PATTERN = new RegExp("^(?:" + _.map(VALID_PROTOCOLS, _expandProtocol).join("|") + ")$", "i");
var VALID_FILE_NAME_PATTERN = /^meta_[a-zA-Z0-9_-]+\.yaml$/;
var VALID_FILE_PREFIX = /^meta_/;
var VALID_FILE_EXTENSION = /\.yaml$/;
var validators = {
/**
* Checks if the string is valid vendor url. To be valid, it must meet the following rules:
* 1) It must be a valid url
* 2) It must only use the http protocol.
* 3) It must point to a file name with the following parts:
* a) Starts with meta_
* b) Followed by a vendor name
* c) With a .yaml extension.
*
* Obviously it must conform to other requirements such as pointing to a valid YAML file in the
* correct format for a vendor meta data file. These final aspects are validated on the server
* during load process, not on the client.
* @param {String} value
* @return {Object} Returns the extended validation object to the validator.
*/
isModsecVendorUrl: function(value) {
var result = UTILS.initializeValidationResult();
if (value) {
var parts = value.split(/\//);
var length = parts.length;
var last = length - 1;
// 0) Must have at least 3 forward slashes, indicating that the URL has a protocol, domain and filename
if (length < 4) {
result.isValid = false;
result.add("isModsecVendorUrl", LOCALE.maketext("The URL must contain a protocol, domain, and file name in the correct format. (Example: [asis,https://example.com/example/meta_example.yaml])"));
return result;
}
// 1) Part 0 should be a protocol: http:
if (!VALID_PROTOCOLS_PATTERN.test(parts[0])) {
result.isValid = false;
result.add("isModsecVendorUrl", LOCALE.maketext("The URL must use one of the following recognized protocols: [join,~, ,_1]", VALID_PROTOCOLS));
return result;
}
// 2) Part 1 should be empty from between the //
// Note: This test doesn't account for the colon directly, but the error message mentions it because it provides an easy spatial reference
// for the user. If we reach this test, we will have passed the protocol test and that one already includes testing for the colon.
if (parts[1] !== "") {
result.isValid = false;
result.add("isModsecVendorUrl", LOCALE.maketext("The protocol should be followed by a colon and two forward slashes. (Example: [asis,https://])"));
return result;
}
// 3) Part 2 should be a domain
var domainResults = DOMAIN_VALIDATORS.methods.fqdn(parts[2]);
if (!domainResults.isValid) {
result.isValid = false;
result.add("isModsecVendorUrl", domainResults.messages[0].message);
return result;
}
// 4) An optional path, we are just going to ignore it.
// 5) Part n should be a file name and is not required
if (last < 3) {
result.add("isModsecVendorUrl", LOCALE.maketext("The file name must start with meta_, followed by the vendor name and have the .yaml extension. (Example: [asis,meta_example.yaml])"));
} else {
var fileName = parts[last];
if (!VALID_FILE_NAME_PATTERN.test(fileName)) {
result.isValid = false;
var failedPrefixTest = !VALID_FILE_PREFIX.test(fileName);
var failedExtensionTest = !VALID_FILE_EXTENSION.test(fileName);
var numFailed = failedPrefixTest + failedExtensionTest; // Implicit coersion to a number
// If several conditions fail, give them the whole spiel, otherwise just give them their specific error.
if (numFailed > 1) {
result.add("isModsecVendorUrl", LOCALE.maketext("The file name must use the meta_ prefix, followed by the vendor name and a .yaml extension. The vendor name must only contain characters in the following set: [join,~, ,_1] (Example: [asis,meta_example.yaml])", ["a-z", "A-Z", "0-9", "-", "_"]));
} else if (failedPrefixTest) {
result.add("isModsecVendorUrl", LOCALE.maketext("The file name must use the meta_ prefix. (Example: [asis,meta_example.yaml])"));
} else if (failedExtensionTest) {
result.add("isModsecVendorUrl", LOCALE.maketext("The file name must have the .yaml extension. (Example: [asis,meta_example.yaml])"));
} else { // By the process of elimination, the only part left of the filename that could be wrong is the vendor_id
result.add("isModsecVendorUrl", LOCALE.maketext("The vendor name part of the file name must only contain characters in the following set: [join,~, ,_1] (Example: [asis,meta_example.yaml])", ["a-z", "A-Z", "0-9", "-", "_"] ));
}
return result;
}
}
}
return result;
}
};
var validatorModule = angular.module("cjt2.validate");
validatorModule.run(["validatorFactory",
function(validatorFactory) {
validatorFactory.generate(validators);
}
]);
return {
methods: validators,
name: "ruleVendorUrlValidator",
description: "Validation directives for rule vendor urls.",
version: 11.48,
};
});
/*
# templates/mod_security/views/addVendorController.js Copyright(c) 2020 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: false */
define(
'app/views/addVendorController',[
"angular",
"lodash",
"cjt/util/locale",
"uiBootstrap",
"cjt/directives/autoFocus",
"cjt/directives/spinnerDirective",
"cjt/directives/validationItemDirective",
"cjt/directives/validationContainerDirective",
"cjt/services/alertService",
"app/services/vendorService",
"app/directives/ruleVendorUrlValidator",
"cjt/filters/notApplicableFilter",
],
function(angular, _, LOCALE) {
"use strict";
// Retrieve the current application
var app = angular.module("App");
var controller = app.controller(
"addVendorController", [
"$scope",
"$filter",
"spinnerAPI",
"alertService",
"vendorService",
function(
$scope,
$filter,
spinnerAPI,
alertService,
vendorService) {
/**
* Disable buttons based on form state
*
* @method disableForm
* @param {FormController} form
* @return {Boolean}
*/
$scope.disableForm = function(form) {
return form.$pristine || (form.$dirty && form.$invalid) || $scope.loading;
};
/**
* Load the form with vendor configuration from a specified URL
*
* @method load
* @param {String} url Address of the YAML configuration file
* @return {Promise}
*/
$scope.load = function(url) {
alertService.clear();
spinnerAPI.start("loadingSpinner");
$scope.loading = true;
return vendorService
.loadVendor(url)
.then(function(vendor) {
angular.extend($scope.vendor, vendor);
$scope.vendor.isLoaded = true;
$scope.vendor.report_url = $filter("na")($scope.vendor.report_url);
}, function(error) {
// failure
alertService.add({
type: "danger",
message: _.escape(error),
id: "errorLoadVendorConfig",
});
$scope.vendor.isLoaded = false;
})
.finally(function() {
spinnerAPI.stop("loadingSpinner");
$scope.loading = false;
});
};
/**
* Save the form
*
* @method save
* @param {String} url Address of the YAML configuration file
* @return {Promise}
*/
$scope.save = function(url) {
alertService.clear();
spinnerAPI.start("savingSpinner");
return vendorService
.saveVendor(url)
.then(function(vendor) {
// success
alertService.add({
type: "success",
message: LOCALE.maketext("You have successfully added “[_1]” to the vendor configuration list.", vendor.name),
id: "successSaveVendorConfig",
});
$scope.loadView("/vendors");
}, function(error) {
// failure
alertService.add({
type: "danger",
message: _.escape(error),
id: "errorSaveVendorConfig",
});
$scope.scrollTo("top");
})
.finally(function() {
spinnerAPI.stop("savingSpinner");
});
};
/**
* Navigate to the previous view.
*
* @method cancel
*/
$scope.cancel = function() {
alertService.clear();
$scope.loadView("vendors");
};
/**
* Clear alerts and restore form defaults
*
* @method clearForm
*/
$scope.clearForm = function() {
$scope.vendor = {
enabled: true,
isLoaded: false,
};
alertService.clear();
};
// Use SSL for YAML URL recommendation warning
$scope.showSSLwarning = false;
$scope.vendorURLchange = function(url) {
var show = false;
var matches = /^(https?):\/\//.exec(url);
if (matches && ( matches[1] === "http" ) ) {
show = true;
}
$scope.showSSLwarning = show;
};
// Initialize the form on first load.
$scope.isEditor = false;
$scope.clearForm();
},
]
);
return controller;
}
);
/*
# mod_security/views/enableDisableConfigController.js Copyright(c) 2020 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: false */
define(
'app/views/enableDisableConfigController',[
"angular",
"lodash",
"cjt/util/locale",
"cjt/util/parse",
"uiBootstrap",
"cjt/directives/toggleSortDirective",
"cjt/directives/spinnerDirective",
"cjt/directives/autoFocus",
"cjt/filters/wrapFilter",
"cjt/filters/breakFilter",
"cjt/filters/replaceFilter",
"cjt/directives/actionButtonDirective",
"cjt/directives/validationItemDirective",
"cjt/services/alertService",
"app/services/vendorService"
],
function(angular, _, LOCALE, PARSE) {
// Retrieve the current application
var app = angular.module("App");
app.controller("enableDisableConfigController", [
"$scope",
"$q",
"$location",
"$timeout",
"vendorService",
"alertService",
"spinnerAPI",
function(
$scope,
$q,
$location,
$timeout,
vendorService,
alertService,
spinnerAPI) {
/**
* Initialize the view
*
* @private
* @method _initializeView
*/
var _initializeView = function() {
$scope.filter = "";
$scope.filterExpression = null;
$scope.hasIssues = false;
$scope.meta = {
sortBy: "config",
sortDirection: "asc"
};
_clearIssues();
$scope.configs = [];
};
/**
* Load the view data
*
* @private
* @method _loadVendor
*/
var _loadVendor = function() {
// This control is designed to be used both independently and
// embedded in another controller.
if (!$scope.vendor) {
_loadVendorFromServer();
} else if (!$scope.vendor.configs) {
_loadVendorFromParent();
}
};
/**
* Load the force flag if it exists. This flags is used to indicate the user just enabled
* a vendor that did not have any enabled configuration sets.
*
* @private
* @method _loadForceFlag
*/
var _loadForceFlag = function() {
var value = $location.search().force;
if (value) {
$scope.force = PARSE.parseBoolean(value);
} else {
$scope.force = false;
}
};
/**
* Load the vendor from the server
*
* @private
* @method _loadVendorFromServer
*/
var _loadVendorFromServer = function() {
_loadForceFlag();
// Not passed from a parent controller, so do it ourselves
var id = $location.search().id;
if (id) {
$scope.fetch(id);
} else {
// failure
alertService.add({
type: "danger",
message: LOCALE.maketext("The system failed to pass the ID query string parameter."),
id: "errorInvalidParameterId"
});
}
};
/**
* Load the vendor from the parent passed data
*
* @private
* @method _loadVendorFromParent
*/
var _loadVendorFromParent = function() {
$scope.serverRequest = true;
_loadForceFlag();
if ($scope.$parent.vendor &&
$scope.$parent.vendor.configs) {
$scope.configs = $scope.$parent.vendor.configs;
$scope.serverRequest = false;
_updateTotals();
}
};
/**
* Updates the totalEnabled/totalDisabled counts.
*
* @method _updateTotals
*/
var _updateTotals = function() {
var totalEnabled = 0;
$scope.configs.forEach(function(config) {
if (config.enabled) {
totalEnabled++;
}
});
$scope.totalEnabled = totalEnabled;
$scope.totalDisabled = $scope.configs.length - totalEnabled;
};
// Setup a watch to recreate the filter expression if the user changes it.
$scope.$watch("filter", function(newValue, oldValue) {
if (newValue) {
newValue = newValue.replace(/([.*+?^${}()|\[\]\/\\])/g, "\\$1"); // Escape any regex special chars (from MDN)
$scope.filterExpression = new RegExp(newValue, "i");
} else {
$scope.filterExpression = null;
}
});
/**
* Sync. filter the configs by the optional filer expression built from the filter field.
*
* @method filterConfigs
* @param {String} value
* @return {Boolean}
*/
$scope.filterConfigs = function(value) {
return $scope.filterExpression ?
$scope.filterExpression.test(value.config) ||
(value.exception && $scope.filterExpression.test(value.exception)) :
true;
};
/**
* Clears the filter when the Esc key
* is pressed.
*
* @scope
* @method triggerClearFilter
* @param {Event} event - The event object
*/
$scope.triggerClearFilter = function(event) {
if (event.keyCode === 27) {
$scope.clearFilter();
}
};
/**
* Clear the filter.
*
* @method clearFilter
*/
$scope.clearFilter = function() {
$scope.filter = "";
};
/**
* Clear the filter only if there is one defined.
*
* @method toggleFilter
*/
$scope.toggleFilter = function() {
if ($scope.filter) {
$scope.clearFilter();
}
};
/**
* Fetch a vendor by its vendor id.
*
* @method fetch
* @param {String} id Vendor id.
* @return {Promise} Promise that when fulfilled will have loaded the vendor
*/
if (!$scope.vendor) {
// Only installed if not passed from the parent controller.
$scope.fetch = function(id) {
$scope.serverRequest = true;
spinnerAPI.start("loadingSpinner2");
return vendorService
.fetchVendorById(id)
.then(function(vendor) {
$scope.vendor = vendor;
$scope.configs = vendor.configs;
}, function(error) {
// failure
alertService.add({
type: "danger",
message: error,
id: "errorFetchRulesList"
});
}).finally(function() {
$scope.serverRequest = false;
_updateTotals();
spinnerAPI.stop("loadingSpinner2");
});
};
}
/**
* Enable or disable a specific config by its path stored in the config.config property.
*
* @method setConfig
* @private
* @param {Object} config Configuration object
* @return {Promise} Promise that when fulfilled will disable/enable the requested config.
*/
$scope.setConfig = function(config) {
var operation = config.enabled ? "enable" : "disable";
// Get a boolean to set config.enabled later
var enabling = operation === "enable";
// Full strings are provided here to aid localization
var message = enabling ?
LOCALE.maketext("You have successfully enabled the configuration file: [_1]", config.config) :
LOCALE.maketext("You have successfully disabled the configuration file: [_1]", config.config);
spinnerAPI.start("loadingSpinner2");
config.serverRequest = true;
return vendorService
[operation + "Config"](config.config) // e.g. enableConfig or disableConfig
.then(function() {
_clearIssues();
config.enabled = enabling;
if (config.exception) {
delete config.exception;
}
// Report success
alertService.add({
type: "success",
message: message,
id: operation + "OneSuccess"
});
}, function(error) {
config.enabled = !enabling;
config.exception = error;
}).finally(function() {
_updateIssues();
_updateTotals();
delete config.serverRequest;
spinnerAPI.stop("loadingSpinner2");
});
};
/**
* Update the configs from the outcomes. When this is done processing, the configs collection
* state is updated to reflect the current state on the server. Also, if any config outcome fails,
* the property .exception property on the specific config is filled in with the issue related to that
* failure so the UI can report it directly.
*
* @private
* @method _updateConfigs
* @param {Array} configs Collection of configs for this vendor
* @param {Array} outcomes Collection of outcome for an enable/disable all action.
*/
var _updateConfigs = function(configs, outcomes) {
angular.forEach(outcomes, function(outcome) {
var match = _.find(configs, function(config) {
return config.config === outcome.config;
});
match.enabled = outcome.enabled;
if (!outcome.ok) {
match.exception = outcome.exception;
} else if (match.exception) {
delete match.exception;
}
});
};
/**
* Update the issues flag
*
* @private
* @method _updateIssues
*/
var _updateIssues = function() {
var match = _.find($scope.configs, function(config) {
return !!config.exception;
});
$scope.hasIssues = typeof (match) !== "undefined";
};
/**
* Test if the config has a related issue meaning something went wrong.
*
* @method hasIssue
* @return {Boolean} true if there are any issues, false otherwise.
*/
$scope.hasIssue = function(config) {
return !!config.exception;
};
/**
* Clear the issues property in preparation for an api run.
*
* @private
* @method _clearIssues
*/
var _clearIssues = function() {
delete $scope.hasIssues;
};
/**
* Attempt to enabled all the configs for this vendor.
*
* @method enableAllConfigs
* @return {Promise} A promise that when fulfilled will enable all the configs that can be successfully
* enabled. The actual outcome are passed to the success handler.
*/
$scope.enableAllConfigs = function() {
return _modifyAllConfigs("enable");
};
/**
* Attempt to disabled all the configs for this vendor.
*
* @method disableAllConfigs
* @return {Promise} A promise that when fulfilled will disable all the configs that can be successfully
* enabled. The actual outcome are passed to the success handler.
*/
$scope.disableAllConfigs = function() {
return _modifyAllConfigs("disable");
};
/**
* Attempts to enable/disable all of the configs for this vendor.
*
* @method _modifyAllConfigs
* @private
* @param {String} operation The operation being performed on all configs, i.e. "enable" or "disable"
* @return {Promise} Upon success all configs will have been modified appropriately.
* Outcomes are passed to both the success and failure handlers.
*/
function _modifyAllConfigs(operation) {
// Short circuit if no operation is necessary
if ((operation === "enable" && $scope.totalDisabled === 0) ||
(operation === "disable" && $scope.totalEnabled === 0)) {
return;
}
// Full strings are provided here to aid localization
var messages = {
disable: {
success: LOCALE.maketext("You have successfully disabled all of the configuration files."),
partial: LOCALE.maketext("You have successfully disabled some of the configuration files. The files that the system failed to disable are marked below."),
failure: LOCALE.maketext("The system could not disable the configuration files.")
},
enable: {
success: LOCALE.maketext("You have successfully enabled all of the configuration files."),
partial: LOCALE.maketext("You have successfully enabled some of the configuration files. The files that the system failed to enable are marked below."),
failure: LOCALE.maketext("The system could not enable the configuration files.")
}
};
// Begin working with the promise
spinnerAPI.start("loadingSpinner2");
$scope.serverRequest = true;
return vendorService
[operation + "AllConfigs"]($scope.vendor.vendor_id) // e.g. enableAllConfigs or disableAllConfigs
.then(function(outcomes) {
_clearIssues();
_updateConfigs($scope.configs, outcomes.configs);
// Report success
alertService.add({
type: "success",
message: messages[operation].success,
id: operation + "AllSuccess"
});
}, function(outcomes) {
_clearIssues();
if (outcomes.configs.length) {
_updateConfigs($scope.configs, outcomes.configs);
alertService.add({
type: "warning",
message: messages[operation].partial,
id: operation + "AllWarning"
});
} else {
alertService.add({
type: "danger",
message: messages[operation].failure,
id: operation + "AllError"
});
}
}).finally(function() {
_updateIssues();
_updateTotals();
$scope.serverRequest = false;
spinnerAPI.stop("loadingSpinner2");
});
}
/**
* Determines if a button should be disabled.
*
* @param {String} type The button type
* @param {Boolean} loading Generic loading flag
* @return {Boolean} Should the button be disabled?
*/
$scope.buttonDisabled = function(type, loading) {
if ($scope.serverRequest) {
return true;
}
switch (type) {
case "enableAll":
return $scope.totalDisabled === 0;
case "disableAll":
return $scope.totalEnabled === 0;
case "configToggle":
return loading;
}
};
if ($scope.$parent.vendor) {
// we are embedded
$scope.$parent.$watch("vendor.configs", function() {
_loadVendorFromParent();
});
}
$scope.$on("$viewContentLoaded", function() {
_loadVendor();
});
_initializeView();
}
]);
}
);
/*
# templates/mod_security/views/addVendorController.js Copyright(c) 2020 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: false */
define(
'app/views/editVendorController',[
"angular",
"cjt/util/locale",
"cjt/util/parse",
"uiBootstrap",
"cjt/directives/autoFocus",
"cjt/directives/spinnerDirective",
"cjt/services/alertService",
"app/services/vendorService",
"app/views/enableDisableConfigController",
"cjt/filters/notApplicableFilter"
],
function(angular, LOCALE, PARSE) {
// Retrieve the current application
var app = angular.module("App");
app.controller(
"editVendorController", [
"$scope",
"$filter",
"$routeParams",
"spinnerAPI",
"alertService",
"vendorService",
function(
$scope,
$filter,
$routeParams,
spinnerAPI,
alertService,
vendorService) {
/**
* Helper function to just make danger alerts a little more dense.
*
* @private
* @method _dangetAlert
* @param {String} msg Message for the alert
* @param {String} id HTML ID requested from the alertService
*/
function _dangerAlert(msg, id) {
alertService.add({
type: "danger",
message: msg,
id: id
});
$scope.scrollTo("top");
}
/**
* Loads the form with vendor meta-data from the WHM API.
*
* @method loadVendor
* @param {String} vendorId This will correspond to the vendor_id field from the API
*/
$scope.loadVendor = function(vendorId) {
if (!$routeParams["suppress-clear-alert"] ||
!PARSE.parseBoolean($routeParams["suppress-clear-alert"])) {
alertService.clear();
}
var promise;
if (vendorId) {
spinnerAPI.start("loadingSpinner");
promise = vendorService.fetchVendorById(vendorId)
.then(function success(data) {
angular.extend($scope.vendor, data);
$scope.vendor.report_url = $filter("na")($scope.vendor.report_url);
}, function failure(error) {
_dangerAlert(error, "errorLoadVendorConfig");
});
promise["finally"](function() {
spinnerAPI.stop("loadingSpinner");
});
} else {
_dangerAlert(LOCALE.maketext("An error occurred in the attempt to retrieve the vendor information."), "errorNoVendorID");
}
};
/**
* Toggle the show/hide vendor details flag.
*
* @method toggleDetails
*/
$scope.toggleDetails = function() {
$scope.hideDetails = !$scope.hideDetails;
};
// Initialize the form on first load.
$scope.isEditor = true;
$scope.hideDetails = true;
$scope.vendor = { id: $routeParams.id };
$scope.$on("$viewContentLoaded", function() {
$scope.loadVendor($scope.vendor.id);
});
}
]
);
}
);
/*
# templates/mod_security/vendors.js Copyright(c) 2020 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 require, define, PAGE */
define(
'app/vendors',[
"angular",
"jquery",
"lodash",
"cjt/core",
"cjt/modules",
"ngRoute",
"uiBootstrap"
],
function(angular, $, _, CJT) {
// First create the application
angular.module("App", [
"cjt2.config.whm.configProvider", // This needs to load first
"ngRoute",
"ui.bootstrap",
"cjt2.whm"
]);
// Then load the application dependencies
var app = require(
[
"cjt/bootstrap",
"cjt/util/locale",
// Application Modules
"cjt/views/applicationController",
"app/views/commonController",
"app/views/vendorListController",
"app/views/addVendorController",
"app/views/enableDisableConfigController",
"app/views/editVendorController",
"cjt/services/autoTopService",
"cjt/services/whm/breadcrumbService",
"cjt/services/whm/titleService"
], function(BOOTSTRAP, LOCALE) {
var app = angular.module("App");
app.value("PAGE", PAGE);
app.firstLoad = {
configs: true,
vendors: true
};
// routing
app.config(["$routeProvider",
function($routeProvider) {
// List of vendors
$routeProvider.when("/vendors", {
controller: "vendorListController",
templateUrl: CJT.buildFullPath("mod_security/views/vendorListView.ptt"),
breadcrumb: LOCALE.maketext("Manage Vendors"),
title: LOCALE.maketext("Manage Vendors"),
reloadOnSearch: false,
group: "vendor",
name: "vendors"
});
// Add a vendor
$routeProvider.when("/vendors/add", {
controller: "addVendorController",
templateUrl: CJT.buildFullPath("mod_security/views/addEditVendor.ptt"),
breadcrumb: LOCALE.maketext("Add Vendor"),
title: LOCALE.maketext("Add Vendor"),
reloadOnSearch: false,
group: "vendor",
name: "add"
});
// Edit a vendor
$routeProvider.when("/vendors/edit", {
controller: "editVendorController",
templateUrl: CJT.buildFullPath("mod_security/views/addEditVendor.ptt"),
breadcrumb: LOCALE.maketext("Select Vendor Rule Sets"),
title: LOCALE.maketext("Select Vendor Rule Sets"),
reloadOnSearch: false,
group: "vendor",
name: "edit"
});
$routeProvider.otherwise({
redirectTo: function(routeParams, path, search) {
return "/vendors?" + window.location.search;
}
});
}
]);
app.run(["autoTopService", "breadcrumbService", "titleService", function(autoTopService, breadcrumbService, titleService) {
// Setup the automatic scroll to top for view changes
autoTopService.initialize();
// Setup the breadcrumbs service
breadcrumbService.initialize();
// Setup the title update service
titleService.initialize();
}]);
BOOTSTRAP(document);
});
return app;
}
);