UNPKG

@sap-cloud-sdk/connectivity

Version:

SAP Cloud SDK for JavaScript connectivity

168 lines • 7.26 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.proxyStrategy = proxyStrategy; exports.parseProxyEnv = parseProxyEnv; exports.addProxyConfigurationInternet = addProxyConfigurationInternet; exports.getProxyConfig = getProxyConfig; const node_url_1 = require("node:url"); const util_1 = require("@sap-cloud-sdk/util"); const protocol_1 = require("../protocol"); const authorization_header_1 = require("../authorization-header"); const get_protocol_1 = require("../get-protocol"); const destination_service_types_1 = require("./destination-service-types"); const logger = (0, util_1.createLogger)({ package: 'connectivity', messageContext: 'proxy-util' }); /** * @internal * Determines the proxy strategy. If the 'no_proxy' env variable is set, the `ProxyConfiguration` in the destination is omitted. * For the 'on-premise' and 'internet' proxy strategies the connectivity service or environment variables are checked to fill the `ProxyConfiguration`. * @param destination - Destination to derive the proxy strategy from. * @returns The proxy strategy for the given destination. */ function proxyStrategy(destination) { if (destination.proxyType === 'OnPremise') { logger.debug('OnPrem destination proxy settings from connectivity service will be used.'); return 'on-premise'; } if (destination.proxyType === 'PrivateLink') { logger.debug('PrivateLink destination proxy settings will be used. This is not supported in local/CI/CD environments.'); return 'private-link'; } if ((0, destination_service_types_1.isHttpDestination)(destination)) { const destinationProtocol = (0, get_protocol_1.getProtocolOrDefault)(destination); return getProxyStrategyFromProxyEnvValue(destinationProtocol, destination.url); } return 'no-proxy'; } function getProxyStrategyFromProxyEnvValue(protocol, destinationUrl) { if (!getProxyEnvValue(protocol)) { logger.debug(`Could not find proxy settings for ${protocol} in the environment variables - no proxy used.`); return 'no-proxy'; } if (getNoProxyEnvValue().includes(destinationUrl)) { logger.debug(`Destination URL ${destinationUrl} is in no_proxy list: ${getNoProxyEnvValue()} - no proxy used.`); return 'no-proxy'; } if (getProxyEnvValue(protocol)) { logger.debug(`Proxy settings for ${protocol} are found in environment variables.`); return 'internet'; } return 'no-proxy'; } function getProxyEnvValue(protocol) { const proxyEnvKey = protocol + '_proxy'; const proxyEnvValue = process.env[proxyEnvKey.toLowerCase()] || process.env[proxyEnvKey.toUpperCase()]; logger.debug(`Tried to read ${proxyEnvKey.toLowerCase()} or ${proxyEnvKey.toUpperCase()} from the environment variables. Value is ${proxyEnvValue}.`); return proxyEnvValue || undefined; } function getNoProxyEnvValue() { const noProxyEnv = process.env.no_proxy || process.env.NO_PROXY; if (!noProxyEnv) { return []; } const split = noProxyEnv.split(',').map(s => s.trim()); if (split.find(s => s.includes('*'))) { logger.warn(`The no_proxy env contains a wildcard ${noProxyEnv}, which is currently not supported`); } return split; } function getPort(url) { if (url.port) { return parseInt(url.port); } return url.protocol === 'https:' ? 443 : 80; } function getOriginalProtocol(href) { const test = href.match(/^[\w.-]+:\/\//); return test ? test[0].slice(0, -2) : undefined; } function sanitizeUrl(href) { const protocol = getOriginalProtocol(href); if (!protocol) { logger.debug('No protocol specified, using "http:".'); return `http://${href}`; } return href; } function validateUrl(url) { if (url.protocol !== 'http:' && url.protocol !== 'https:') { throw new Error(`Unsupported protocol "${url.protocol}".`); } if (url.protocol === 'https:') { logger.debug('Using protocol "https:" to connect to a proxy. This is unusual but possible.'); } if (url.username && !url.password) { throw new Error('Password missing.'); } } /** * Parses the environment variable for the web proxy and extracts the values considering defaults like http for the protocol and 80 or 443 for the port. * The general pattern to be parsed is `protocol://user:password@host:port`, where everything besides the host is optional. * Special characters in the user and password need to be percent encoded. * @param proxyEnvValue - Environment variable which is parsed. * @returns Configuration with default values or `undefined` if the parsing failed. */ function parseProxyEnv(proxyEnvValue) { const href = sanitizeUrl(proxyEnvValue); try { const url = new node_url_1.URL(href); validateUrl(url); const proxyConfig = { host: url.hostname, protocol: (0, protocol_1.getProtocol)(url.protocol), port: getPort(url) }; if (url.username && url.password) { proxyConfig.headers = { 'Proxy-Authorization': (0, authorization_header_1.basicHeader)(decodeURIComponent(url.username), decodeURIComponent(url.password)) }; } if (proxyConfig) { const loggableConfig = { ...proxyConfig, headers: (0, util_1.sanitizeRecord)(proxyConfig.headers || {}, 'Authorization header present. Not logged for security reasons.') }; logger.debug(`Used Proxy Configuration: ${JSON.stringify(loggableConfig, null, 2)}.`); } return proxyConfig; } catch (err) { logger.warn(`Could not parse proxy configuration from environment variable. Reason: ${err.message}`); return undefined; } } /** * Adds the proxy configuration to a destination based on web proxies defined in environment variables. See {@link ProxyConfiguration} and {@link proxyStrategy} for details. * @param destination - to which the proxy configuration is added. * @returns Destination containing the configuration for web proxy. * @internal */ function addProxyConfigurationInternet(destination) { const proxyEnvValue = getProxyEnvValue((0, get_protocol_1.getProtocolOrDefault)(destination)); if (proxyEnvValue) { return { ...destination, proxyConfiguration: parseProxyEnv(proxyEnvValue) || destination.proxyConfiguration }; } logger.warn('Attempt to get proxy config from environment variables failed. At this point this should not happen - no proxy used.'); return { ...destination }; } /** * Picks the the proxy config properties. * Note, that the protocol ('http' or 'https') is not related to the destinations' target system protocol and in most cases 'http'. * @param destination - Destination containing the proxy configuration. * @returns Reduced proxy configuration. * @internal */ function getProxyConfig(destination) { if (destination.proxyConfiguration) { const { host, protocol, port } = destination.proxyConfiguration; return { host, protocol, port }; } return false; } //# sourceMappingURL=http-proxy-util.js.map