Viewing File: /usr/local/cpanel/base/frontend/jupiter/version_control/directives/cloneURLValidator.js

/*
# version_control/directives/cloneURLValidator.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([
    "angular",
    "app/utils/cloneUrlParser",
    "cjt/util/locale",
    "cjt/validator/validator-utils",
    "cjt/validator/ip-validators",
    "cjt/validator/domain-validators",
    "cjt/validator/validateDirectiveFactory",
], function(
    angular,
    cloneUrlParser,
    LOCALE,
    validationUtils,
    IP_VALIDATOR,
    DOMAIN_VALIDATOR
) {
    "use strict";

    var cloneURLValidator = {

        /**
         * Validate a git-based clone url.
         *
         * Does not validate local paths like: file:///path/to/repo.git/ and /path/to/repo.git/
         *
         * @method validCloneUrl
         * @param {String} cloneUrl - Check if this is a valid clone url.
         * @return {object} result - Validator-Utils result.
         */
        validCloneUrl: function(cloneUrl) {
            var result = validationUtils.initializeValidationResult();

            // Check for blank string.
            if (typeof cloneUrl === "undefined" || cloneUrl === null) {
                result.isValid = false;
                result.add(
                    "cloneURLValidator",
                    LOCALE.maketext("You must specify a valid clone URL.")
                );
                return result;
            }

            var parts = cloneUrlParser.parse(cloneUrl);
            var scheme = parts.scheme;
            var userInfo = parts.userInfo;
            var ipv6Authority = parts.ipv6Authority;
            var authority = parts.authority;
            var path = parts.path;
            var unparsed = parts.unparsed;

            // Check for valid protocols (http:// | https:// | ssh:// | git://)
            var protocolPattern = /^(?:git|ssh|https?)(?::\/\/)$/i;
            var hasValidProtocol = protocolPattern.test(scheme);

            // Check for invalid username and password (user:pass@)
            var userAndPassPattern = /^\S+:\S+@/i;
            if (userAndPassPattern.test(userInfo)) {
                result.isValid = false;
                result.add(
                    "cloneURLValidator",
                    LOCALE.maketext(
                        "The clone URL [output,strong,cannot] include a password."
                    )
                );
                return result;
            }

            // Check for valid username (username@)
            var emailPattern =
                /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@/i;
            var hasValidUser = emailPattern.test(userInfo);

            // Assess if provided scheme and user@ is valid
            var preDomainValid = false;
            if (hasValidProtocol && hasValidUser) {

                // has both
                preDomainValid = true;
            }
            if (hasValidProtocol ^ hasValidUser) {

                // has one or the other

                // Prevents invalid non-required protocol.
                if (!hasValidProtocol && scheme !== null) {
                    result.isValid = false;
                    result.add(
                        "cloneURLValidator",
                        LOCALE.maketext(
                            "The provided clone URL [output,strong,must] include a valid protocol."
                        )
                    );
                    return result;
                }

                preDomainValid = true;
            }
            if (!preDomainValid) {
                result.isValid = false;
                result.add(
                    "cloneURLValidator",
                    LOCALE.maketext(
                        "Clone URLs [output,strong,must] include a valid protocol or username."
                    )
                );
                return result;
            }

            // Check for valid ipv6
            if (ipv6Authority !== null) {
                var validIPV6 = IP_VALIDATOR.methods.ipv6(ipv6Authority);

                if (!validIPV6.isValid) {
                    var errorMsg = combineErrorMessages(validIPV6.messages);

                    result.isValid = false;
                    result.add("cloneURLValidator", errorMsg);
                    return result;
                }
            }

            // Check for valid ipv4 or domain name
            if (authority !== null && authority !== "") {
                var validIPV4 = IP_VALIDATOR.methods.ipv4(authority);
                var validFQDN = DOMAIN_VALIDATOR.methods.fqdn(authority);

                if (!validIPV4.isValid && !validFQDN.isValid) {
                    result.isValid = false;
                    result.add(
                        "cloneURLValidator",
                        LOCALE.maketext(
                            "The clone URL [output,strong,must] include a valid IP address or a fully-qualified domain name."
                        )
                    );
                    return result;
                }

                // If there is no valid ipv4, ipv6, or domain name
            } else if (ipv6Authority === null) {
                result.isValid = false;
                result.add(
                    "cloneURLValidator",
                    LOCALE.maketext(
                        "The clone URL [output,strong,must] include a valid IP address or a fully-qualified domain name."
                    )
                );
                return result;
            }

            // Check for ip/domain -> path delimiter: if there is a protocol and path starts with : then throw error
            var scpSyntaxPattern = /^:/i;
            var hasSCPsyntaxPathStart = scpSyntaxPattern.test(path);
            if (hasValidProtocol && hasValidUser && hasSCPsyntaxPathStart) {
                result.isValid = false;
                result.add(
                    "cloneURLValidator",
                    LOCALE.maketext(
                        "The repository path should [output,strong,not] begin with “:” if it includes the protocol."
                    )
                );
                return result;
            }

            // Check for valid path with .git extension (:|/ + path + .git? + /? )
            // This could also indicate a problem with the port number format.
            // This ignores any query string vars or page anchors.
            var pathAndExtensionPattern = /^(:|\/)\S*(\.git)?\/?/i;
            var hasValidPath = pathAndExtensionPattern.test(path);
            if (!hasValidPath) {
                result.isValid = false;
                result.add(
                    "cloneURLValidator",
                    LOCALE.maketext(
                        "The path or port number is [output,strong,not] valid."
                    )
                );
                return result;
            }

            // Check for any left over cloneUrl parts that indicates spaces were used in the URL construction.
            if (unparsed !== "") {
                result.isValid = false;
                result.add(
                    "cloneURLValidator",
                    LOCALE.maketext(
                        "The clone URL [output,strong,cannot] include whitespace characters."
                    )
                );
                return result;
            }

            return result;

            /**
             * Private method to combine all validation error messages from other validators.
             * This method is used to reduce the number of LOCALE.maketext calls via re-useability.
             *
             * @method combineErrorMessages
             * @param {array} msgArr - An array of messages from the validation-utils :: ValidationResult object.
             * @return {string} msg - All messages combined into one string.
             */
            function combineErrorMessages(msgArr) {
                var msg = "";

                for (var a = 0, len = msgArr.length; a < len; a++) {
                    msg +=
                        a !== len - 1
                            ? msgArr[a].message + " "
                            : msgArr[a].message;
                }

                return msg;
            }
        },
    };

    var validatorModule = angular.module("cjt2.validate");

    validatorModule.run([
        "validatorFactory",
        function(validatorFactory) {
            validatorFactory.generate(cloneURLValidator);
        },
    ]);

    return {
        methods: cloneURLValidator,
        name: "clone-url-validator",
        description: "Validation on git-based clone URLs.",
        version: 1.0,
    };
});
Back to Directory File Manager