Viewing File: /usr/local/cpanel/whostmgr/docroot/templates/api_tokens/index.cmb.js

/*
# cpanel - whostmgr/docroot/templates/api_tokens/services/api_tokens.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
*/

define(
    'app/services/api_tokens',[
        "angular",
        "lodash",
        "cjt/util/locale",
        "cjt/io/whm-v1-request",
        "cjt/util/parse",
        "cjt/io/api",
        "cjt/io/whm-v1",
        "cjt/services/APIService"
    ],
    function(angular, _, LOCALE, APIREQUEST, PARSE) {

        "use strict";

        var app = angular.module("whm.apiTokens.apiCallService", []);
        app.factory(
            "Tokens",
            ["$q", "APIService", function($q, APIService) {

                var TokensService = function() {};
                TokensService.prototype = new APIService();

                var isEmptyObject = function(obj) {
                    for (var key in obj) {
                        if (Object.prototype.hasOwnProperty.call(obj, key)) {
                            return false;
                        }
                    }
                    return true;
                };

                var addAclsTo = function addAclsTo(apiCall, acls) {
                    if (typeof acls !== "undefined") {
                        var i = 0, apiCount = acls.length;
                        for (; i < apiCount; i++) {
                            apiCall.addArgument("acl-" + i, acls[i]);
                        }
                    }
                };

                var tokensData = {};
                var userPrivileges = {};

                angular.extend(TokensService.prototype, {
                    getTokens: function getTokens(force) {
                        if (force || isEmptyObject(tokensData)) {
                            var apiCall = new APIREQUEST.Class();
                            apiCall.initialize("", "api_token_list");

                            return this.deferred(apiCall).promise
                                .then(function(response) {
                                    tokensData = response.data.tokens;
                                    return tokensData;
                                })
                                .catch(function(error) {
                                    return $q.reject(error);
                                });
                        } else {
                            return $q.when(tokensData);
                        }
                    },

                    createToken: function createToken(name, acls, expiresAt, whitelistIps) {
                        var apiCall = new APIREQUEST.Class();
                        apiCall.initialize("", "api_token_create");
                        apiCall.addArgument("token_name", name);

                        if (expiresAt) {
                            apiCall.addArgument("expires_at", expiresAt);
                        }

                        if (whitelistIps && whitelistIps.length) {
                            whitelistIps.forEach(function(ip, index) {
                                apiCall.addArgument("whitelist_ip-" + index, ip);
                            });
                        }

                        addAclsTo(apiCall, acls);

                        return this.deferred(apiCall).promise
                            .then(function(data) {
                                return data;
                            })
                            .catch(function(error) {
                                return $q.reject(error);
                            });
                    },

                    updateToken: function updateToken(name, newName, acls, expiresAt, whitelistIps) {
                        var apiCall = new APIREQUEST.Class();
                        apiCall.initialize("", "api_token_update");
                        apiCall.addArgument("token_name", name);
                        if (expiresAt) {
                            apiCall.addArgument("expires_at", expiresAt);
                        }

                        if (whitelistIps && whitelistIps.length) {
                            whitelistIps.forEach(function(ip, index) {
                                apiCall.addArgument("whitelist_ip-" + index, ip);
                            });
                        }

                        if (whitelistIps && !whitelistIps.length) {
                            apiCall.addArgument("whitelist_ip", "any");
                        }

                        if (newName !== name) {
                            apiCall.addArgument("new_name", newName);
                        }

                        addAclsTo(apiCall, acls);

                        return this.deferred(apiCall).promise
                            .then(function(data) {
                                return data;
                            })
                            .catch(function(error) {
                                return $q.reject(error);
                            });
                    },

                    revokeToken: function revokeToken(name) {
                        var apiCall = new APIREQUEST.Class();
                        apiCall.initialize("", "api_token_revoke");
                        if (typeof (name) === "string") {
                            apiCall.addArgument("token_name", name);
                        } else if (Array.isArray(name)) {
                            var i = 0, nameCount = name.length;
                            for (; i < nameCount; i++) {
                                apiCall.addArgument("token_name-" + i, name[i]);
                            }
                        }

                        return this.deferred(apiCall).promise
                            .then(function(data) {
                                return data;
                            })
                            .catch(function(error) {
                                return $q.reject(error);
                            });
                    },

                    getPrivileges: function getPrivileges(force) {
                        if (force || isEmptyObject(userPrivileges)) {

                            var apiCall = new APIREQUEST.Class();
                            apiCall.initialize("", "myprivs");

                            return this.deferred(apiCall).promise
                                .then(function(result) {
                                    var obj = {};
                                    var hasAll = false;

                                    if (result.data) {
                                        obj = result.data[0];

                                        if (obj !== null && typeof obj !== "undefined") {
                                            hasAll = Object.prototype.hasOwnProperty.call(obj, "all") && obj.all === 1;

                                            // Remove the "demo" acl since it is not a real acl
                                            delete obj.demo;

                                            var keys = Object.keys(obj);
                                            for (var i = 0, len = keys.length; i < len; i++) {
                                                if (keys[i] !== "all" && (hasAll || obj[keys[i]] === 1)) {
                                                    userPrivileges[keys[i]] = true;
                                                }
                                            }
                                            if (hasAll) {
                                                userPrivileges["all"] = false;
                                            }
                                        }
                                    }

                                    return userPrivileges;
                                })
                                .catch(function(error) {
                                    return $q.reject(error);
                                });
                        } else {
                            return $q.when(userPrivileges);
                        }
                    },

                    getDetailsFor: function getDetailsFor(tokenName) {
                        return this.getTokens(false)
                            .then(function(data) {
                                if (data !== null &&
                                    typeof data !== "undefined" &&
                                    Object.prototype.hasOwnProperty.call(data, tokenName)) {
                                    if (data[tokenName] && Object.prototype.hasOwnProperty.call(data[tokenName], "acls")) {
                                        var acls = data[tokenName].acls;

                                        // Remove the "demo" acl since it is not a real acl
                                        delete acls.demo;

                                        for (var acl in acls) {
                                            if (Object.prototype.hasOwnProperty.call(acls, acl)) {
                                                acls[acl] = PARSE.parsePerlBoolean(acls[acl]);
                                            }
                                        }
                                    }
                                    return data[tokenName];
                                }

                                return $q.reject(LOCALE.maketext("The [asis,API] token “[_1]” does not exist.", _.escape(tokenName)));
                            });
                    }
                });


                return new TokensService();
            }
            ]);
    });

// Copyright 2022 cPanel, L.L.C. - All rights reserved.
// copyright@cpanel.net
// https://cpanel.net
// This code is subject to the cPanel license. Unauthorized copying is prohibited

function ipv6short(input) {
    "use strict";

    // remove all zeros to the right
    input = input.replace(/^(0{4}:)+/g, "::");

    // remove all zeros to the left
    input = input.replace(/(?::?0{4})+(\/\d+)?$/g, "::$1");

    // remove all leading zeros
    input = input.replace(/(:|^)(0{1,3})(?=[^0])/g, "$1");

    // find the longest group of continuous empty 16-bit hexets if string doesn't alreay contain ::
    if (input.match("::") === null) {
        var matches = input.match(/(:0{4})+/g);
        if (!matches) {
            return input;
        }
        var match = matches.reduce((a, b) => a.length > b.length ? a : b);
        input = input.replace(match, ":");
    }

    // replace remaning empty 16-bit hexets with a single 0
    return input.replace(/(?!:)(0{4})/g, "0");
}

define(
    'app/filters',[
        "angular",
    ],
    function(angular) {
        "use strict";
        var module = angular.module("whm.apiTokens.filters", []);
        module.filter("ipv6short", function() {
            return ipv6short;
        });

        return module;
    });

/*
# cpanel - whostmgr/docroot/templates/api_tokens/views/home.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(
    'app/views/home',[
        "angular",
        "cjt/util/locale",
        "cjt/util/table",
        "uiBootstrap",
        "cjt/decorators/growlDecorator",
        "cjt/decorators/paginationDecorator",
        "cjt/directives/actionButtonDirective",
        "cjt/directives/searchDirective",
        "cjt/directives/pageSizeDirective",
        "cjt/directives/alertList",
        "cjt/directives/toggleSortDirective",
        "cjt/services/viewNavigationApi",
        "cjt/directives/autoFocus",
    ],
    function(angular, LOCALE, Table) {
        "use strict";
        var app = angular.module("whm.apiTokens");

        var controller = app.controller(
            "homeController",
            ["$q", "growl", "Tokens", "$uibModal", "viewNavigationApi", "PAGE",
                function($q, growl, Tokens, $uibModal, viewNavigationApi, PAGE) {
                    var home = this;

                    home.loading = false;
                    home.showFormToggleBtn = true;
                    home.tokenAdded = false;
                    home.loadingError = false;
                    home.loadingErrorMessage = "";
                    home.allChecked = false;
                    home.checkedCount = 0;
                    home.paginationMessage = "";
                    home.showChildAccountsExistWarning = PAGE.childAccountsExist;
                    home.childAccountsExistWarning = "";
                    home.childAccountsExistWarning += LOCALE.maketext("There are accounts on this server controlled by a parent node.");
                    home.childAccountsExistWarning += " ";
                    home.childAccountsExistWarning += LOCALE.maketext("Do not delete [asis,API] tokens a parent node uses to communicate with this server.");

                    function searchByName(item, searchText) {
                        return item.name.toLowerCase().indexOf(searchText.toLowerCase()) !== -1;
                    }

                    var table = new Table();
                    table.setSearchFunction(searchByName);
                    table.setSort("create_time,name", "desc");
                    home.meta = table.getMetadata();
                    home.filteredList = table.getList();
                    home.allTokens = [];
                    home.render = function() {
                        home.resetCheckAll();
                        home.filteredList = table.update();
                        home.paginationMessage = table.paginationMessage();
                    };
                    home.sortList = function() {
                        home.render();
                    };
                    home.selectPage = function() {
                        home.render();
                    };
                    home.selectPageSize = function() {
                        home.render();
                    };
                    home.searchList = function() {
                        home.render();
                    };

                    home.resetCheckAll = function() {
                        home.allChecked = false;
                        home.toggleCheckAll();
                        home.checkedCount = 0;
                    };

                    home.getIndeterminateState = function() {
                        return home.checkedCount > 0 && !home.allChecked;
                    };

                    home.toggleCheckAll = function() {
                        if (home.filteredList.length === 0) {
                            return;
                        }
                        var i = 0, listLength = home.filteredList.length;
                        for (i; i < listLength; i++) {
                            home.filteredList[i].checked = home.allChecked;
                        }
                        if (home.allChecked) {
                            home.checkedCount = listLength;
                        } else {
                            home.checkedCount = 0;
                        }
                    };

                    home.syncCheckAll = function(listItem) {
                        if (listItem.checked) {
                            home.checkedCount++;
                        } else {
                            home.checkedCount--;
                        }
                        home.allChecked = home.checkedCount === home.filteredList.length;
                    };

                    home.checkAll = function() {
                        home.allChecked = true;
                        home.toggleCheckAll();
                    };

                    home.editToken = function(token) {
                        if (token === void 0) {
                            viewNavigationApi.loadView("/edit");
                        } else {
                            viewNavigationApi.loadView("/edit/" + token.name);
                        }
                    };

                    home.getSelectedTokens = function() {
                        var selectedTokens = [];
                        for (var i = 0; i < home.filteredList.length; i++) {
                            if (home.filteredList[i].checked) {
                                selectedTokens.push(home.filteredList[i]);
                            }
                        }

                        return selectedTokens;
                    };

                    home.getHumanReadableTime = function(epochTime) {
                        return LOCALE.local_datetime(epochTime, "datetime_format_medium");
                    };

                    function RevokeTokenModalController($uibModalInstance, token) {
                        var ctrl = this;
                        var tokenCount = 0;

                        ctrl.cancel = function() {
                            $uibModalInstance.dismiss("cancel");
                        };

                        ctrl.buildTokenNameList = function() {
                            tokenCount = token.length;
                            var i = 0, tokensToDelete = [];

                            for (i = 0; i < tokenCount; i++) {
                                tokensToDelete.push(token[i].name);
                            }

                            return tokensToDelete;
                        };

                        var revokeParam;

                        if (Array.isArray(token) && token.length === home.allTokens.length) {
                            ctrl.prompt = LOCALE.maketext("Are you certain that you want to revoke all of your [asis,API] tokens?" );
                            revokeParam = ctrl.buildTokenNameList();
                        } else if (Array.isArray(token)) {
                            ctrl.prompt = LOCALE.maketext("Are you certain that you want to revoke [numf,_1] [asis,API] [numerate,_1,token,tokens]?", token.length);
                            revokeParam = ctrl.buildTokenNameList();
                        } else {
                            ctrl.prompt = LOCALE.maketext("Are you certain that you want to revoke the [asis,API] token, “[_1]”?", token.name);
                            revokeParam = token.name;
                        }

                        ctrl.confirm = function() {
                            return Tokens.revokeToken(revokeParam)
                                .then(function() {
                                    if (Array.isArray(token)) {
                                        if (token.length === home.allTokens.length) {
                                            growl.success(LOCALE.maketext("You successfully revoked all of your [asis,API] tokens."));
                                            table.clear();
                                            home.allTokens = [];
                                        } else {
                                            growl.success(LOCALE.maketext("You successfully revoked [numf,_1] [asis,API] [numerate,_1,token,tokens].", token.length));
                                            for (var i = 0; i < tokenCount; i++) {
                                                table.remove(token[i]);
                                            }
                                        }
                                    } else {
                                        growl.success(LOCALE.maketext("You successfully revoked the [asis,API] token “[_1]”.", token.name));
                                        table.remove(token);
                                    }

                                    home.render();
                                })
                                .catch(function(error) {
                                    growl.error(error);
                                })
                                .finally(function() {
                                    $uibModalInstance.close();
                                });
                        };
                    }

                    RevokeTokenModalController.$inject = ["$uibModalInstance", "token"];

                    home.confirmRevokeToken = function(token) {
                        $uibModal.open({
                            templateUrl: "confirm_token_revocation.html",
                            controller: RevokeTokenModalController,
                            controllerAs: "ctrl",
                            resolve: {
                                token: function() {
                                    return token;
                                },
                            },
                        });
                    };

                    home.refreshList = function() {
                        home.filteredList = [];
                        home.allTokens = [];
                        return load();
                    };

                    function load() {
                        home.loading = true;

                        var _currentDateTime = new Date();
                        _currentDateTime = _currentDateTime.getTime() / 1000;

                        var _twentyFourHours = 24 * 60 * 60;

                        // In addition to getting the list of api tokens, we want to fetch the
                        // privileges for the user now to cache them for when the user will
                        // need to create a token. This helps avoid showing a spinner on the
                        // create view.
                        return $q.all([
                            Tokens.getTokens(true),
                            Tokens.getPrivileges(true)])
                            .then(function(data) {
                                var tableData = [];
                                var tokenData = data[0];
                                if (tokenData !== null && typeof tokenData !== "undefined") {
                                    for (var tokenName in tokenData) {
                                        if (tokenData.hasOwnProperty(tokenName)) {
                                            tokenData[tokenName].checked = false;
                                            tokenData[tokenName].create_time_friendly = LOCALE.local_datetime(tokenData[tokenName].create_time, "datetime_format_medium");
                                            tokenData[tokenName].expiresAtFriendly = "";
                                            if (tokenData[tokenName].expires_at) {

                                                var expiresAt = parseInt(tokenData[tokenName].expires_at, 10);

                                                if (expiresAt <= _currentDateTime) {
                                                    tokenData[tokenName].expired = true;
                                                } else if (expiresAt - _currentDateTime < _twentyFourHours) {
                                                    tokenData[tokenName].expiresSoon = true;
                                                }

                                                tokenData[tokenName].expiresAtFriendly = LOCALE.local_datetime(tokenData[tokenName].expires_at, "datetime_format_medium");
                                            }
                                            tableData.push(tokenData[tokenName]);
                                        }
                                    }
                                    table.load(tableData);
                                    home.allTokens = tableData;
                                    home.render();
                                }
                            })
                            .catch(function(error) {
                                home.loadingError = true;
                                home.loadingErrorMessage = error;
                            })
                            .finally(function() {
                                home.loading = false;
                            });
                    }

                    function init() {
                        load();
                    }

                    init();
                },
            ]);

        return controller;
    }
);

/*
# cpanel - whostmgr/docroot/templates/api_tokens/views/edit.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
*/

define(
    'app/views/edit',[
        "angular",
        "lodash",
        "cjt/util/locale",
        "cjt/util/parse",
        "cjt/validator/ip-validators",
        "cjt/validator/validator-utils",
        "cjt/util/table",
        "uiBootstrap",
        "cjt/decorators/growlDecorator",
        "cjt/directives/alertList",
        "cjt/directives/autoFocus",
        "cjt/directives/triStateCheckbox",
        "cjt/directives/timePicker",
        "cjt/directives/datePicker",
        "cjt/services/viewNavigationApi",
        "cjt/directives/validationContainerDirective",
        "cjt/directives/validationItemDirective",
    ],
    function(angular, _, LOCALE, PARSE, VALIDATORS, UTILS) {
        "use strict";

        /**
         * Parse the text block into a list of IPv4 and CIDR items. These can
         * be separated by a \n, \r\n, a comma, or a sequence of 1 or more
         * whitespaces. Excess leading and trailing whitespace is removed from
         * each item and blank entries are removed from the list.
         *
         * @param {string} txtIps
         * @returns {string[]}
         */
        function parseIps(txtIps) {
            if (!txtIps) {
                return [];
            }
            var ips = txtIps.split(/\r?\n|,|\s+/);
            return ips.map(function(ip) {
                return _.trim(ip);
            }).filter(function(ip) {
                return !!ip;
            });
        }

        /**
         * Try to guess the IP version based on group separator
         * defaults to ipv4 if ipv6 checks fail
         *
         * @param {string} ip - any string.
         * @returns {string} - ip version.
         */
        function guessIpVersion(ip) {

            if (/:/.test(ip)) {
                return "ipv6";
            }

            return "ipv4";
        }

        /**
         * Validate ipv6 address and the prefix length of ipv6 range
         *
         * @param {string} ipOrCidr - ipv6 range specified in CIDR notation.
         * @returns {ValidationResult}
         */
        function cidr6(str) {
            var cidr = str.split("/");
            var range = cidr[1], address = cidr[0];

            var result = VALIDATORS.methods.ipv6(address);

            if (!range) {
                result.isValid = false;
                result.add("cidr", LOCALE.maketext("The [asis,IP] address prefix must include a ‘/’ followed by the prefix length."));
            }

            if (range < 1 || range > 128 || !range) {
                result.isValid = false;
                result.add("cidr", LOCALE.maketext("You must specify a valid prefix length between 1 and 128."));
            }

            return result;
        }

        /**
         * Validate the string is either a valid IPv4 address or
         * that it is a valid CIDR address range.
         *
         * @param {string} ipOrCidr - an unvalidated string from the ui.
         * @returns {ValidationResult}
         */
        function validateIp(ipOrCidr) {
            var result;
            var ipversion = guessIpVersion(ipOrCidr);
            if (/[/]/.test(ipOrCidr)) {
                result = ipversion === "ipv4" ? VALIDATORS.methods.cidr4(ipOrCidr) : cidr6(ipOrCidr);
                if (!result.isValid) {
                    if (result.lookup["cidr"]) {
                        result.lookup["cidr"].message = ipOrCidr + " - " + result.lookup["cidr"].message;
                    } else {
                        if (result.lookup["cidr-details"]) {
                            result.lookup["cidr-details"].message = ipOrCidr + " - " + result.lookup["cidr-details"].message;
                        }
                    }

                    // Handle cases where an invalid ipv4 address is used along with a CIDR range
                    if (result.lookup[ipversion]) {
                        result.lookup[ipversion].message = ipOrCidr + " - " + result.lookup[ipversion].message;
                    }
                }
            } else {
                result = ipversion === "ipv4" ? VALIDATORS.methods.ipv4(ipOrCidr) : VALIDATORS.methods.ipv6(ipOrCidr);
                if (!result.isValid) {
                    result.lookup[ipversion].message = ipOrCidr + " - " + result.lookup[ipversion].message;
                }
            }
            return result;
        }

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

        /**
         * Add a custom parser and validator for a list of IPv4 addresses
         * or CIDR ranges.
         */
        app.directive("ipv4OrCidr4List", function() {
            return {
                restrict: "A",
                require: "ngModel",
                link: function(scope, elem, attr, ctrl) {
                    var form = elem.controller("form");
                    UTILS.initializeExtendedReporting(ctrl, form);

                    ctrl.$parsers.push(function(value) {
                        return parseIps(value);
                    });

                    ctrl.$formatters.push(function(value) {
                        return value.join("\r\n");
                    });

                    ctrl.$isEmpty = function(value) {
                        return angular.isUndefined(value) || value === "" || value === null || value !== value || value.length && value.length === 0;
                    };

                    ctrl.$validators.ipv4OrCidr4 = function(modelValue, viewValue) {

                        // Adapter to support multiple flags in a validator
                        ["ipv6", "ipv4", "cidr", "cidr-details", "size-exceeded"].forEach(function(key) {
                            delete ctrl.$error[key];
                        });
                        ctrl.$error_details.clear();

                        if (ctrl.$isEmpty(modelValue)) {

                            // consider empty models to be valid
                            return true;
                        }

                        if (modelValue.length > 100) {
                            var sizeResult = UTILS.initializeValidationResult();
                            sizeResult.isValid = false;
                            sizeResult.add("size-exceeded", LOCALE.maketext("You have exceeded the limit of 100 whitelisted [asis,IP] addresses per token."));
                            ctrl.$error["size-exceeded"] = true;
                            UTILS.updateExtendedReportingList(ctrl, form, ["size-exceeded"], sizeResult);
                            return false;
                        }

                        // Perform progressive validation, rather the all at the same time
                        for (var i = 0, l = modelValue.length; i < l; i++) {
                            var ipOrCidr = modelValue[i];
                            var result = validateIp(ipOrCidr);
                            if (!result.isValid) {

                                var possibleErrors = ["ipv6", "ipv4", "cidr", "cidr-details"];

                                // Package the additional error messages into the collections
                                possibleErrors.forEach(function(key) {
                                    var isError = result.lookup[key] ? true : false;
                                    if (isError) {
                                        ctrl.$error[key] = true;
                                    } else {
                                        delete ctrl.$error[key];
                                    }
                                });
                                UTILS.updateExtendedReportingList(ctrl, form, possibleErrors, result);
                                return false;
                            }
                        }

                        // it is valid if all the individual items are valid
                        return true;
                    };

                    scope.$watch(attr.ngModel,
                        function(newVal) {
                            ctrl.$validate();
                        }
                    );
                },
            };
        });

        var controller = app.controller(
            "editController",
            ["$routeParams", "growl", "Tokens", "viewNavigationApi", "PAGE", "growlMessages",
                function($routeParams, growl, Tokens, viewNavigationApi, PAGE, growlMessages) {
                    var edit = this;

                    var minDate = new Date();
                    minDate.setHours(0);
                    minDate.setMinutes(0);
                    minDate.setSeconds(0, 0);

                    edit.datePickerOptions = {
                        minDate: minDate,
                    };

                    edit.timePickerOptions = {
                        min: minDate,
                    };
                    edit.stringify = function(obj) {
                        return JSON.stringify(obj, undefined, 2);
                    };
                    var defaultExpiresDate = new Date(minDate.getTime());
                    defaultExpiresDate.setHours(23);
                    defaultExpiresDate.setMinutes(59);
                    defaultExpiresDate.setSeconds(59, 999);
                    defaultExpiresDate.setFullYear(defaultExpiresDate.getFullYear() + 1);

                    edit.loading = false;
                    edit.loadingError = false;
                    edit.loadingErrorMessage = "";

                    edit.showExtraHelp = false;
                    edit.onToggleHelp = function() {
                        edit.showExtraHelp = !edit.showExtraHelp;
                    };

                    edit.tokenAdded = false;
                    edit.editingToken = false;
                    edit.hasPrivs = false;
                    edit.availableAcls = {};
                    edit.aclsToEdit = [];
                    edit.aclsToSend = {};

                    edit.newToken = {
                        name: "",
                        originalName: "",
                        token: "",
                        acls: [],
                        tokenExpires: false,
                        expiresAt: defaultExpiresDate,
                        whitelistIps: [],
                    };

                    var isDnsOnly = PARSE.parsePerlBoolean(PAGE.is_dns_only);

                    edit.aclWarningVisible = function(acl) {
                        if (acl.name === "all") {
                            return true;
                        }
                        if (!Object.prototype.hasOwnProperty.call(acl, "is_warning_visible")) {
                            acl.is_warning_visible = false;
                        }
                        return acl.is_warning_visible;
                    };

                    edit.toggleAclWarning = function(acl) {
                        if (!Object.prototype.hasOwnProperty.call(acl, "is_warning_visible")) {
                            acl.is_warning_visible = true;
                        } else {
                            acl.is_warning_visible = !acl.is_warning_visible;
                        }
                    };

                    edit.handleWarningIconKey = function(acl, event) {
                        if (event.type !== "keypress") {
                            return;
                        }
                        if (event.charCode === 32 || event.charCode === 13) {
                            edit.toggleAclWarning(acl);
                            event.preventDefault();
                        }
                    };

                    edit.toggleAcl = function(acl) {

                        var isRootSelected = edit.aclsToSend["all"] && acl.name !== "all";
                        var areWeSelectingRoot = acl.name === "all" && acl.selected;

                        if (acl.selected) {
                            edit.aclsToSend[acl.name] = true;
                        } else {
                            delete edit.aclsToSend[acl.name];
                        }

                        if (isRootSelected && !acl.selected) {
                            edit.removeAllToken();
                        }

                        if (areWeSelectingRoot) {

                            // select all the subcatgories except for the root subcategory
                            edit.selectAllSubcategories("Everything");
                        }
                    };

                    edit.updateAclsToSend = function(subcategory) {
                        for (var i = 0, len = subcategory.acls.length; i < len; i++) {
                            edit.toggleAcl(subcategory.acls[i]);
                        }
                    };

                    /**
                     * Select all Privileges on the interface and update the data storage we
                     * use to send privileges when we trigger the "save" call.
                     *
                     * @param except {String} - a subcategory that we do not want to select
                     */
                    edit.selectAllSubcategories = function(except) {
                        var subcategories = edit.aclsToEdit;
                        for (var i = 0, len = subcategories.length; i < len; i++) {
                            if (subcategories[i].title === except) {
                                continue;
                            }
                            for (var j = 0, aclLen = subcategories[i].acls.length; j < aclLen; j++) {
                                subcategories[i].acls[j].selected = true;
                                edit.aclsToSend[subcategories[i].acls[j].name] = true;
                            }
                        }
                    };

                    edit.hasSelectedPrivs = function() {
                        return edit.hasPrivs && Object.keys(edit.aclsToSend).length > 0;
                    };

                    edit.disableSave = function(form) {
                        return (edit.newToken.tokenExpires && edit.datePickerOptions.minDate > edit.newToken.expiresAt) || (form.$pristine || form.$invalid || !edit.hasSelectedPrivs());
                    };

                    edit.dateValidator = function(input) {
                        if (edit.newToken.tokenExpires && edit.newToken.expiresAt) {
                            edit.newToken.expiresAt.setHours(23);
                            edit.newToken.expiresAt.setMinutes(59);
                            edit.newToken.expiresAt.setSeconds(59, 999);
                        }

                        if (edit.newToken.tokenExpires && edit.datePickerOptions.minDate > edit.newToken.expiresAt) {
                            input.$invalid = true;
                            input.$valid = false;
                        }
                    };

                    edit.resetDate = function() {
                        if (edit.newToken.tokenExpires) {
                            edit.newToken.expiresAt = defaultExpiresDate;
                        }
                    };

                    edit.goHome = function() {
                        viewNavigationApi.loadView("/home");
                    };

                    edit.newTokenExpiresMessage = function newTokenExpiresMessage(token) {
                        var expirationDate = LOCALE.local_datetime(token.expiresAt, "datetime_format_medium");
                        return LOCALE.maketext("This [asis,API] token will expire on [_1][comment,Bareword is a date].", expirationDate);
                    };

                    edit.minimumIpRows = function() {
                        return this.newToken.whitelistIps.length ? this.newToken.whitelistIps.length : 4;
                    };

                    edit.saveToken = function(form) {
                        if (form.$invalid) {
                            return;
                        }

                        edit.newToken.acls = Object.keys(edit.aclsToSend);

                        if ( edit.newToken.tokenExpires ) {
                            edit.newToken.expiresAt.setHours(23);
                            edit.newToken.expiresAt.setMinutes(59);
                            edit.newToken.expiresAt.setSeconds(59, 999);
                        }

                        var expiresAt = edit.newToken.tokenExpires ? Math.floor(edit.newToken.expiresAt / 1000) : "0";

                        growlMessages.destroyAllMessages();
                        if (edit.editingToken) {
                            return Tokens.updateToken(edit.newToken.originalName, edit.newToken.name, edit.newToken.acls, expiresAt, edit.newToken.whitelistIps)
                                .then(function success(results) {
                                    growl.success(LOCALE.maketext("You successfully updated the [asis,API] token, “[_1]”.", results.data.name));
                                    viewNavigationApi.loadView("/home");
                                })
                                .catch(function error(data) {
                                    growl.error(_.escape(data));
                                });

                        } else {
                            return Tokens.createToken(edit.newToken.name, edit.newToken.acls, expiresAt, edit.newToken.whitelistIps)
                                .then(function success(results) {

                                    // notify the user of the new token
                                    edit.newToken.token = results.data.token;
                                    edit.tokenAdded = true;
                                })
                                .catch(function error(data) {
                                    growl.error(_.escape(data));
                                });
                        }
                    };

                    edit.getAvailableAcls = function() {
                        return Tokens.getPrivileges(false)
                            .then(function success(results) {
                                if (results !== null && typeof results !== "undefined" ) {
                                    edit.availableAcls = results;
                                }
                            })
                            .catch(function error(data) {
                                growl.error(_.escape(data));
                            });
                    };

                    edit.removeAllToken = function() {
                        var allSubcategory = edit.aclsToEdit[edit.aclsToEdit.length - 1];
                        allSubcategory.acls[0].selected = false;
                        delete edit.aclsToSend.all;
                        growl.info(LOCALE.maketext("The system deselected the “all” privilege."));
                    };

                    /**
                     * Create a data structure that is easy to deal with from the interface
                     * Should create the following data structure
                     * [
                     *   {
                     *     "categoryName": "standardprivileges",
                     *     "categoryTitle": "Standard Privileges",
                     *     "name": "accountinformation",
                     *     "title": "Account Information",
                     *     "selected": true,
                     *     "acls": [
                     *       {
                     *         "name": "list-accts",
                     *         "title": "List Accounts",
                     *         "selected": true
                     *       }
                     *     ]
                     *   }
                     * ]
                     * @param {Object} selectedPrivs - contains the privileges
                     * should appear in the interface and be selected.
                     * @return {Array} the data structure mapped out above
                     */
                    function prepareAclsForEdit(selectedPrivs) {
                        var formattedAcls = [];
                        var category = {};
                        var subcategory = {};
                        var acl = {};
                        var availabeAclsInSubcategory = 0;

                        selectedPrivs = (typeof selectedPrivs === "undefined") ? {} : selectedPrivs;

                        for (var i = 0, len = PAGE.ordered_categories.length; i < len; i++) {

                            // the additional software group may not have any entries, so check for definedness first
                            if (typeof PAGE.categories_metadata[PAGE.ordered_categories[i]].ordered_subcategories !== "undefined") {
                                category = {
                                    orderedSubcategories: PAGE.categories_metadata[PAGE.ordered_categories[i]].ordered_subcategories,
                                    name: PAGE.ordered_categories[i],
                                    title: PAGE.categories_metadata[PAGE.ordered_categories[i]].title,
                                };

                                for (var j = 0, jlen = category.orderedSubcategories.length; j < jlen; j++) {
                                    subcategory = {
                                        title: PAGE.subcategories_metadata[category.orderedSubcategories[j]].title,
                                        orderedAcls: PAGE.subcategories_metadata[category.orderedSubcategories[j]].ordered_acls,
                                        categoryTitle: category.title,
                                        categoryName: category.name,
                                        name: category.orderedSubcategories[j],
                                        acls: [],
                                    };
                                    availabeAclsInSubcategory = 0;

                                    for (var k = 0, klen = subcategory.orderedAcls.length, enabledCount = 0; k < klen; k++) {
                                        if (!Object.prototype.hasOwnProperty.call(selectedPrivs, subcategory.orderedAcls[k])) {
                                            continue;
                                        }
                                        if (isDnsOnly && (!PAGE.acl_metadata[subcategory.orderedAcls[k]] || !PAGE.acl_metadata[subcategory.orderedAcls[k]].dnsonly)) {
                                            continue;
                                        }
                                        availabeAclsInSubcategory++;

                                        acl = {
                                            name: subcategory.orderedAcls[k],
                                            title: PAGE.acl_metadata[subcategory.orderedAcls[k]].title,
                                        };

                                        if (PAGE.acl_metadata[subcategory.orderedAcls[k]].description) {
                                            acl.description = PAGE.acl_metadata[subcategory.orderedAcls[k]].description;
                                            acl.description_is_warning = PAGE.acl_metadata[subcategory.orderedAcls[k]].description_is_warning ? true : false;
                                        }

                                        if (selectedPrivs[acl.name]) {
                                            acl.selected = true;
                                            enabledCount++;
                                        } else {
                                            acl.selected = false;
                                        }
                                        subcategory.acls.push(acl);
                                    }

                                    subcategory.orderedAcls = void 0;
                                    subcategory.selected = (enabledCount === availabeAclsInSubcategory) ? true : false;
                                    if (availabeAclsInSubcategory > 0) {
                                        formattedAcls.push(subcategory);
                                    }
                                }
                            }
                        }
                        return formattedAcls;
                    }

                    function init() {
                        edit.loading = true;

                        var _currentDateTime = new Date();
                        _currentDateTime = _currentDateTime.getTime() / 1000;

                        var _twentyFourHours = 24 * 60 * 60;

                        if (Object.prototype.hasOwnProperty.call($routeParams, "name")) {
                            return Tokens.getDetailsFor($routeParams.name)
                                .then(function(results) {
                                    edit.newToken.name = $routeParams.name;
                                    edit.newToken.originalName = $routeParams.name;
                                    edit.editingToken = true;

                                    edit.newToken.expiresAtFriendly = "";
                                    if (results.expires_at) {
                                        edit.newToken.expiresAt = new Date(results.expires_at * 1000);
                                        edit.newToken.tokenExpires = true;

                                        var expiresAt = parseInt(results.expires_at, 10);

                                        if (expiresAt <= _currentDateTime) {
                                            edit.newToken.expired = true;
                                        } else if (expiresAt - _currentDateTime < _twentyFourHours) {
                                            edit.newToken.expiresSoon = true;
                                        }

                                        edit.newToken.expiresAtFriendly = LOCALE.local_datetime(expiresAt, "datetime_format_medium");
                                    }

                                    edit.newToken.whitelistIps = results.whitelist_ips || [];

                                    for (var acl in results.acls) {
                                        if (results.acls[acl]) {
                                            if (isDnsOnly && (!PAGE.acl_metadata[acl] || !PAGE.acl_metadata[acl].dnsonly)) {
                                                continue;
                                            }
                                            edit.aclsToSend[acl] = true;
                                        }
                                    }
                                    edit.aclsToEdit = prepareAclsForEdit(results.acls);
                                    edit.hasPrivs = edit.aclsToEdit.length > 0;
                                })
                                .catch(function(error) {
                                    edit.loadingError = true;
                                    edit.loadingErrorMessage = error;
                                })
                                .finally(function() {
                                    edit.loading = false;
                                });

                        } else {
                            return Tokens.getPrivileges(false)
                                .then(function(results) {
                                    if (results !== null && typeof results !== "undefined" ) {
                                        for (var acl in results) {
                                            if (results[acl]) {
                                                if (isDnsOnly && !PAGE.acl_metadata[acl].dnsonly) {
                                                    continue;
                                                }
                                                edit.aclsToSend[acl] = true;
                                            }
                                        }

                                        edit.aclsToEdit = prepareAclsForEdit(results);
                                        edit.hasPrivs = edit.aclsToEdit.length > 0;
                                    }
                                })
                                .catch(function(error) {
                                    edit.loadingError = true;
                                    edit.loadingErrorMessage = error;
                                })
                                .finally(function() {
                                    edit.loading = false;
                                });
                        }
                    }

                    init();
                },
            ]);

        return controller;
    }
);

/*
# cpanel - whostmgr/docroot/templates/api_tokens/index.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: false, define: false */

define(
    'app/index',[
        "angular",
        "jquery",
        "cjt/core",
        "cjt/modules",
        "ngRoute",
        "ngAnimate",
        "ngAria",
        "uiBootstrap",
        "app/services/api_tokens",
        "app/filters",
    ],
    function(angular) {
        "use strict";

        return function() {
            angular.module("whm.apiTokens", [
                "cjt2.config.whm.configProvider", // This needs to load first
                "ngRoute",
                "ngAnimate",
                "ngAria",
                "ui.bootstrap",
                "angular-growl",
                "cjt2.whm",
                "whm.apiTokens.apiCallService",
                "whm.apiTokens.filters",
            ]);
            var app = require(
                [
                    "cjt/bootstrap",
                    "app/views/home",
                    "app/views/edit",
                ], function(BOOTSTRAP) {

                    var app = angular.module("whm.apiTokens");
                    app.value("PAGE", PAGE);

                    app.config([
                        "$routeProvider",
                        function($routeProvider) {
                            $routeProvider.when("/home", {
                                controller: "homeController",
                                controllerAs: "home",
                                templateUrl: "api_tokens/views/home.ptt",
                            });

                            $routeProvider.when("/edit/:name?", {
                                controller: "editController",
                                controllerAs: "edit",
                                templateUrl: "api_tokens/views/edit.ptt",
                            });

                            $routeProvider.otherwise({
                                "redirectTo": "/home",
                            });
                        },
                    ]);

                    BOOTSTRAP(document, "whm.apiTokens");

                });

            return app;
        };
    }
);

Back to Directory File Manager