"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getGitAuthenticatedEnvironmentVariables = getGitAuthenticatedEnvironmentVariables;
exports.getAuthenticationRules = getAuthenticationRules;
exports.getGitEnvironmentVariables = getGitEnvironmentVariables;
const logger_1 = require("../../logger");
const common_1 = require("../common");
const host_rules_1 = require("../host-rules");
const regex_1 = require("../regex");
const url_1 = require("../url");
const url_2 = require("./url");
const githubApiUrls = new Set([
    'github.com',
    'api.github.com',
    'https://api.github.com',
    'https://api.github.com/',
]);
const standardGitAllowedHostTypes = [
    // All known git platforms
    'azure',
    'bitbucket',
    'bitbucket-server',
    'gitea',
    'github',
    'gitlab',
];
/**
 * Add authorization to a Git Url and returns a new environment variables object
 * @returns a new NodeJS.ProcessEnv object without modifying any input parameters
 */
function getGitAuthenticatedEnvironmentVariables(originalGitUrl, { token, username, password, hostType, matchHost }, environmentVariables) {
    if (!token && !(username && password)) {
        logger_1.logger.warn(
        // TODO: types (#22198)
        `Could not create environment variable for ${matchHost} as neither token or username and password was set`);
        return { ...environmentVariables };
    }
    // check if the environmentVariables already contain a GIT_CONFIG_COUNT or if the process has one
    const gitConfigCountEnvVariable = environmentVariables?.GIT_CONFIG_COUNT ?? process.env.GIT_CONFIG_COUNT;
    let gitConfigCount = 0;
    if (gitConfigCountEnvVariable) {
        // passthrough the gitConfigCountEnvVariable environment variable as start value of the index count
        gitConfigCount = parseInt(gitConfigCountEnvVariable, 10);
        if (Number.isNaN(gitConfigCount)) {
            logger_1.logger.warn(`Found GIT_CONFIG_COUNT env variable, but couldn't parse the value to an integer: ${String(process.env.GIT_CONFIG_COUNT)}. Ignoring it.`);
            gitConfigCount = 0;
        }
    }
    let authenticationRules;
    if (token) {
        authenticationRules = getAuthenticationRulesWithToken(originalGitUrl, hostType, token);
    }
    else {
        const encodedUsername = encodeURIComponent(username);
        const encodedPassword = encodeURIComponent(password);
        authenticationRules = getAuthenticationRules(originalGitUrl, hostType, `${encodedUsername}:${encodedPassword}`);
    }
    // create a shallow copy of the environmentVariables as base so we don't modify the input parameter object
    // add the two new config key and value to the returnEnvironmentVariables object
    // increase the CONFIG_COUNT by one for each rule and add it to the object
    const newEnvironmentVariables = {
        ...environmentVariables,
    };
    for (const rule of authenticationRules) {
        newEnvironmentVariables[`GIT_CONFIG_KEY_${gitConfigCount}`] =
            `url.${rule.url}.insteadOf`;
        newEnvironmentVariables[`GIT_CONFIG_VALUE_${gitConfigCount}`] =
            rule.insteadOf;
        gitConfigCount++;
    }
    newEnvironmentVariables['GIT_CONFIG_COUNT'] = gitConfigCount.toString();
    return newEnvironmentVariables;
}
function getAuthenticationRulesWithToken(url, hostType, authToken) {
    let token = authToken;
    let type = hostType;
    if (!type) {
        type = (0, common_1.detectPlatform)(url);
    }
    if (type === 'gitlab') {
        token = `gitlab-ci-token:${authToken}`;
    }
    return getAuthenticationRules(url, type, token);
}
/**
 * Generates the authentication rules for later git usage for the given host
 * @link https://coolaj86.com/articles/vanilla-devops-git-credentials-cheatsheet/
 * @param gitUrl Git repository URL
 * @param hostType Git host type
 * @param token Authentication token or `username:password` string
 */
function getAuthenticationRules(gitUrl, hostType, token) {
    const authenticationRules = [];
    const hasUser = token.split(':').length > 1;
    const insteadUrl = (0, url_2.parseGitUrl)(gitUrl);
    let sshPort = insteadUrl.port;
    if (hostType === 'bitbucket-server') {
        // For Bitbucket Server/Data Center, `source` must be `bitbucket-server`
        // to generate HTTP(s) URLs correctly.
        // https://github.com/IonicaBizau/git-url-parse/blob/28828546c148d58bbcff61409915a4e1e8f7eb11/lib/index.js#L304
        insteadUrl.source = 'bitbucket-server';
        if (!sshPort) {
            // By default, bitbucket-server SSH port is 7999.
            // For non-default port, the generated auth config will likely be incorrect.
            sshPort = 7999;
        }
    }
    const url = { ...insteadUrl };
    const protocol = (0, regex_1.regEx)(/^https?$/).test(url.protocol)
        ? url.protocol
        : 'https';
    // ssh protocol with user if empty
    url.token = hasUser ? token : `ssh:${token}`;
    authenticationRules.push({
        url: url.toString(protocol),
        // only edge case, need to stringify ourself because the exact syntax is not supported by the library
        // https://github.com/IonicaBizau/git-url-parse/blob/246c9119fb42c2ea1c280028fe77c53eb34c190c/lib/index.js#L246
        insteadOf: `ssh://git@${insteadUrl.resource}${sshPort ? `:${sshPort}` : ''}/${insteadUrl.full_name}${insteadUrl.git_suffix ? '.git' : ''}`,
    });
    // alternative ssh protocol with user if empty
    url.token = hasUser ? token : `git:${token}`;
    authenticationRules.push({
        url: url.toString(protocol),
        insteadOf: { ...insteadUrl, port: sshPort }.toString('ssh'),
    });
    // https protocol with no user as default fallback
    url.token = token;
    authenticationRules.push({
        url: url.toString(protocol),
        insteadOf: insteadUrl.toString(protocol),
    });
    return authenticationRules;
}
function getGitEnvironmentVariables(additionalHostTypes = []) {
    let environmentVariables = {};
    // hard-coded logic to use authentication for github.com based on the githubToken for api.github.com
    const gitHubHostRule = (0, host_rules_1.find)({
        hostType: 'github',
        url: 'https://api.github.com/',
    });
    if (gitHubHostRule?.token) {
        environmentVariables = getGitAuthenticatedEnvironmentVariables('https://github.com/', gitHubHostRule);
    }
    // construct the Set of allowed hostTypes consisting of the standard Git provides
    // plus additionalHostTypes, which are provided as parameter
    const gitAllowedHostTypes = new Set([
        ...standardGitAllowedHostTypes,
        ...additionalHostTypes,
    ]);
    // filter rules without `matchHost` and `token` or username and password and github api github rules
    const hostRules = (0, host_rules_1.getAll)()
        .filter((r) => r.matchHost && (r.token ?? (r.username && r.password)))
        .filter((r) => !gitHubHostRule || !githubApiUrls.has(r.matchHost));
    // for each hostRule without hostType we add additional authentication variables to the environmentVariables
    // for each hostRule with hostType we add additional authentication variables to the environmentVariables
    for (const hostRule of hostRules) {
        if (!hostRule.hostType || gitAllowedHostTypes.has(hostRule.hostType)) {
            environmentVariables = addAuthFromHostRule(hostRule, environmentVariables);
        }
    }
    return environmentVariables;
}
function addAuthFromHostRule(hostRule, env) {
    let environmentVariables = env;
    const httpUrl = (0, url_1.createURLFromHostOrURL)(hostRule.matchHost)?.toString();
    if ((0, url_1.isHttpUrl)(httpUrl)) {
        logger_1.logger.trace(`Adding Git authentication for ${httpUrl} using token auth.`);
        environmentVariables = getGitAuthenticatedEnvironmentVariables(httpUrl, hostRule, environmentVariables);
    }
    else {
        logger_1.logger.debug(`Could not parse registryUrl ${hostRule.matchHost} or not using http(s). Ignoring`);
    }
    return environmentVariables;
}
//# sourceMappingURL=auth.js.map