"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.proxyConfForEnvVars = proxyConfForEnvVars;
exports.proxyForUrl = proxyForUrl;
exports.translateToElectronProxyConfig = translateToElectronProxyConfig;
exports.getSocks5OnlyProxyOptions = getSocks5OnlyProxyOptions;
exports.extractProxySecrets = extractProxySecrets;
exports.mergeProxySecrets = mergeProxySecrets;
exports.redactUrl = redactUrl;
function proxyConfForEnvVars(env) {
    const map = new Map();
    let noProxy = '';
    for (const [_key, value] of Object.entries(env)) {
        if (value === undefined)
            continue;
        const key = _key.toUpperCase();
        if (key.endsWith('_PROXY') && key !== 'NO_PROXY') {
            map.set(key.replace(/_PROXY$/, '').toLowerCase(), value || 'direct://');
        }
        if (key === 'NO_PROXY')
            noProxy = value;
    }
    return { map, noProxy };
}
function shouldProxy(noProxy, url) {
    if (!noProxy)
        return true;
    if (noProxy === '*')
        return false;
    for (const noProxyItem of noProxy.split(/[\s,]/)) {
        let { host, port } = noProxyItem.match(/(?<host>.+)(:(?<port>\d+)$)?/)?.groups ?? {};
        if (!host) {
            host = noProxyItem;
            port = '';
        }
        if (port && url.port !== port)
            continue;
        if (host === url.hostname ||
            (host.startsWith('*') && url.hostname.endsWith(host.substring(1))))
            return false;
    }
    return true;
}
function proxyForUrl(proxyOptions, target, req) {
    if (proxyOptions.proxy) {
        const proxyUrl = proxyOptions.proxy;
        if (new URL(proxyUrl).protocol === 'direct:')
            return '';
        if (shouldProxy(proxyOptions.noProxyHosts || '', new URL(target))) {
            return proxyUrl;
        }
        return '';
    }
    if (proxyOptions.useEnvironmentVariableProxies) {
        const { map, noProxy } = proxyConfForEnvVars(proxyOptions.env ?? process.env);
        const url = new URL(target);
        const protocol = (req?.overrideProtocol ?? url.protocol).replace(/:$/, '');
        const combinedNoProxyRules = [noProxy, proxyOptions.noProxyHosts]
            .filter(Boolean)
            .join(',');
        const proxyForProtocol = map.get(protocol) || map.get('all');
        if (proxyForProtocol && shouldProxy(combinedNoProxyRules, url)) {
            return proxyForProtocol;
        }
        return '';
    }
    return '';
}
function validateElectronProxyURL(url) {
    url = new URL(url.toString());
    if (url.protocol === 'ssh:') {
        throw new Error(`Using ssh:// proxies for generic browser proxy usage is not supported (translating '${redactUrl(url)}')`);
    }
    if (url.username || url.password) {
        throw new Error(`Using authenticated proxies for generic browser proxy usage is not supported (translating '${redactUrl(url)}')`);
    }
    if (url.protocol !== 'http:' &&
        url.protocol !== 'https:' &&
        url.protocol !== 'socks5:') {
        throw new Error(`Unsupported proxy protocol (translating '${redactUrl(url)}')`);
    }
    if (url.search || url.hash) {
        throw new Error(`Unsupported URL extensions in proxy specification (translating '${redactUrl(url)}')`);
    }
    if (url.pathname === '')
        return url.toString();
    if (url.pathname !== '/') {
        throw new Error(`Unsupported URL pathname in proxy specification (translating '${redactUrl(url)}')`);
    }
    return url.toString().replace(/\/$/, '');
}
function translateToElectronProxyConfig(proxyOptions) {
    if (proxyOptions.proxy) {
        let url = proxyOptions.proxy;
        if (new URL(url).protocol.startsWith('pac+')) {
            url = url.replace('pac+', '');
            return {
                mode: 'pac_script',
                pacScript: url.toString(),
                proxyBypassRules: proxyOptions.noProxyHosts,
            };
        }
        return {
            mode: 'fixed_servers',
            proxyRules: validateElectronProxyURL(url),
            proxyBypassRules: proxyOptions.noProxyHosts,
        };
    }
    if (proxyOptions.useEnvironmentVariableProxies) {
        const proxyRulesList = [];
        const proxyBypassRulesList = [proxyOptions.noProxyHosts];
        const { map, noProxy } = proxyConfForEnvVars(proxyOptions.env ?? process.env);
        for (const key of ['http', 'https', 'ftp']) {
            const value = map.get(key) || map.get('all');
            if (!value)
                continue;
            proxyRulesList.push(`${key}=${validateElectronProxyURL(value)}`);
        }
        proxyBypassRulesList.push(noProxy);
        const proxyRules = proxyRulesList.join(';');
        const proxyBypassRules = proxyBypassRulesList.filter(Boolean).join(',') || undefined;
        if (!proxyRules) {
            if (!proxyBypassRules)
                return {};
            else
                return { proxyBypassRules };
        }
        return {
            mode: 'fixed_servers',
            proxyBypassRules,
            proxyRules,
        };
    }
    return {};
}
function getSocks5OnlyProxyOptions(proxyOptions, target) {
    let proxyUrl;
    if (target !== undefined)
        proxyUrl = proxyForUrl(proxyOptions, target);
    else if (!proxyOptions.noProxyHosts)
        proxyUrl = proxyOptions.proxy;
    if (!proxyUrl)
        return undefined;
    const url = new URL(proxyUrl);
    if (url.protocol !== 'socks5:')
        return undefined;
    return {
        proxyHost: decodeURIComponent(url.hostname),
        proxyPort: +(url.port || 1080),
        proxyUsername: decodeURIComponent(url.username) || undefined,
        proxyPassword: decodeURIComponent(url.password) || undefined,
    };
}
function extractProxySecrets(proxyOptions) {
    const secrets = {};
    if (proxyOptions.proxy) {
        const proxyUrl = new URL(proxyOptions.proxy);
        secrets.password = proxyUrl.password;
        proxyUrl.password = '';
        proxyOptions = { ...proxyOptions, proxy: proxyUrl.toString() };
    }
    if (proxyOptions.sshOptions) {
        secrets.sshIdentityKeyPassphrase =
            proxyOptions.sshOptions.identityKeyPassphrase;
        proxyOptions = {
            ...proxyOptions,
            sshOptions: {
                ...proxyOptions.sshOptions,
                identityKeyPassphrase: undefined,
            },
        };
    }
    return {
        secrets: JSON.stringify(secrets),
        proxyOptions: proxyOptions,
    };
}
function mergeProxySecrets({ proxyOptions, secrets, }) {
    const parsedSecrets = JSON.parse(secrets || '{}');
    if ((parsedSecrets.username || parsedSecrets.password) &&
        proxyOptions.proxy) {
        const proxyUrl = new URL(proxyOptions.proxy);
        proxyUrl.password = parsedSecrets.password || '';
        proxyOptions = { ...proxyOptions, proxy: proxyUrl.toString() };
    }
    if (parsedSecrets.sshIdentityKeyPassphrase) {
        proxyOptions = {
            ...proxyOptions,
            sshOptions: {
                ...proxyOptions.sshOptions,
                identityKeyPassphrase: parsedSecrets.sshIdentityKeyPassphrase,
            },
        };
    }
    return proxyOptions;
}
function redactUrl(urlOrString) {
    const url = new URL(urlOrString.toString());
    if (url.password)
        url.password = '(credential)';
    return url.toString();
}
//# sourceMappingURL=proxy-options.js.map