UNPKG

@sap-cloud-sdk/core

Version:
204 lines • 9.87 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ProxyStrategy = exports.proxyAgent = exports.addProxyConfigurationInternet = exports.parseProxyEnv = exports.proxyStrategy = void 0; var url_1 = require("url"); var http_proxy_agent_1 = require("http-proxy-agent"); var https_proxy_agent_1 = require("https-proxy-agent"); var util_1 = require("@sap-cloud-sdk/util"); var get_protocol_1 = require("../connectivity/scp-cf/get-protocol"); var protocol_1 = require("../connectivity/scp-cf/protocol"); var authorization_header_1 = require("../connectivity/scp-cf/authorization-header"); var logger = (0, util_1.createLogger)({ package: 'core', messageContext: 'proxy-util' }); /** * Determines the proxy strategy. If noProxy is set the ProxyConfiguration in the destination is omitted. * For onPremProxy or internetProxy the connectivity service or environment variables are checked to fill the [[ProxyConfiguration]]. * @param destination - from which the proxy strategy is derived. * @returns ProxyStrategy possible values are noProxy, internetProxy or onPremProxy. */ function proxyStrategy(destination) { if (destination.proxyType === 'OnPremise') { logger.info('OnPrem destination proxy settings from connectivity service will be used.'); return ProxyStrategy.ON_PREMISE_PROXY; } if (destination.proxyType === 'PrivateLink') { logger.info('PrivateLink destination proxy settings will be used. This is not supported in local/CI/CD environments.'); return ProxyStrategy.PRIVATELINK_PROXY; } var destinationProtocol = (0, get_protocol_1.getProtocolOrDefault)(destination); if (!getProxyEnvValue(destinationProtocol)) { logger.info("No Proxy settings for ".concat(destinationProtocol, " are found in environment variables - no proxy used")); return ProxyStrategy.NO_PROXY; } if (getNoProxyEnvValue().includes(destination.url)) { logger.info("Destination URL ".concat(destination.url, " is in no_proxy list: ").concat(getNoProxyEnvValue(), " - no proxy used")); return ProxyStrategy.NO_PROXY; } if (getProxyEnvValue(destinationProtocol)) { logger.info("Proxy settings for ".concat(destinationProtocol, " are found in environment variables.")); return ProxyStrategy.INTERNET_PROXY; } return ProxyStrategy.NO_PROXY; } exports.proxyStrategy = proxyStrategy; function getProxyEnvValue(protocol) { var proxyEnvKey = protocol + '_proxy'; var proxyEnvValue = process.env[proxyEnvKey.toLowerCase()] || process.env[proxyEnvKey.toUpperCase()]; logger.info("Try to fetch ".concat(proxyEnvKey.toLowerCase(), " or ").concat(proxyEnvKey.toUpperCase(), " from the process env. Found value is ").concat(proxyEnvValue)); if (!proxyEnvValue) { return undefined; } return proxyEnvValue; } function getNoProxyEnvValue() { var noProxyEnv = process.env.no_proxy || process.env.NO_PROXY; if (!noProxyEnv) { return []; } var split = noProxyEnv.split(',').map(function (s) { return s.trim(); }); if (split.find(function (s) { return s.includes('*'); })) { logger.warn("The no_proxy env contains a wildcard ".concat(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) { var test = href.match(/^[\w.-]+:\/\//); return test ? test[0].slice(0, -2) : undefined; } function sanitizeUrl(href) { var protocol = getOriginalProtocol(href); if (!protocol) { logger.debug('No protocol specified, using "http:".'); return "http://".concat(href); } return href; } function validateUrl(url) { if (url.protocol !== 'http:' && url.protocol !== 'https:') { throw new Error("Unsupported protocol \"".concat(url.protocol, "\".")); } if (url.protocol === 'https:') { logger.info('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) { var href = sanitizeUrl(proxyEnvValue); try { var url = new url_1.URL(href); validateUrl(url); var proxyConfig = { host: url.hostname, protocol: protocol_1.Protocol.of(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) { var loggableConfig = __assign(__assign({}, proxyConfig), { headers: proxyConfig.headers ? 'Authorization header present. Not logged for security reasons.' : 'No authorization header present.' }); logger.debug("Used Proxy Configuration: ".concat(JSON.stringify(loggableConfig, null, 2), ".")); } return proxyConfig; } catch (err) { logger.warn("Could not parse proxy configuration from environment variable. Reason: ".concat(err.message)); } } exports.parseProxyEnv = parseProxyEnv; /** * Adds the proxy configuration to a destination based on web proxies defined in environment variables. See [[ProxyConfiguration]] and [[proxyStrategy]] for details. * @param destination - to which the proxy configuration is added. * @returns Destination containing the configuration for web proxy. */ function addProxyConfigurationInternet(destination) { var proxyEnvValue = getProxyEnvValue((0, get_protocol_1.getProtocolOrDefault)(destination)); if (proxyEnvValue) { var proxyConfiguration = parseProxyEnv(proxyEnvValue); if (proxyConfiguration) { return __assign(__assign({}, destination), { proxyConfiguration: proxyConfiguration }); } return __assign({}, destination); } logger.warn('Attempt to get proxy config from environment variables failed. At this point this should not happen - no proxy used.'); return __assign({}, destination); } exports.addProxyConfigurationInternet = addProxyConfigurationInternet; /** * Builds the http(s)-agent config. Note that the proxy agent type like http or https is determined by the destination RUL protocol. * The protocol from the proxy is unrelated to this and in most cases http. * All additional options are forwarded to tls.connect and net.connect see https://github.com/TooTallNate/node-https-proxy-agent#new-httpsproxyagentobject-options * @param destination - Destination containing the proxy configurations * @param options - Additional options for the agent * @returns The http(s)-agent containing the proxy configuration */ function proxyAgent(destination, options) { var targetProtocol = (0, get_protocol_1.getProtocolOrDefault)(destination); var proxyConfig = destination.proxyConfiguration; if (!proxyConfig) { throw new Error('Proxy config must not be undefined.'); } if (options === null || options === void 0 ? void 0 : options.host) { logger.warn("The agent options you passed to the proxy agent creation contains the host \"".concat(options.host, "\" which will overwrite the host from the proxy config.")); } if (options === null || options === void 0 ? void 0 : options.port) { logger.warn("The agent options you passed to the proxy agent creation contains the port \"".concat(options.port, "\" which will overwrite the port from the proxy config.")); } var agentConfig = __assign({ host: proxyConfig.host, protocol: proxyConfig.protocol, port: proxyConfig.port }, options); switch (targetProtocol) { case protocol_1.Protocol.HTTP: return { httpAgent: new http_proxy_agent_1.HttpProxyAgent(agentConfig) }; case protocol_1.Protocol.HTTPS: return { httpsAgent: new https_proxy_agent_1.HttpsProxyAgent(agentConfig) }; } } exports.proxyAgent = proxyAgent; /** * Enum representing the different strategies for proxies on requests. Possible situations are "NO_PROXY", use the connectivity service proxy for On-Premise connection or a usual web proxy. * See also [[ProxyConfiguration]] for more details. */ var ProxyStrategy; (function (ProxyStrategy) { ProxyStrategy[ProxyStrategy["NO_PROXY"] = 0] = "NO_PROXY"; ProxyStrategy[ProxyStrategy["ON_PREMISE_PROXY"] = 1] = "ON_PREMISE_PROXY"; ProxyStrategy[ProxyStrategy["INTERNET_PROXY"] = 2] = "INTERNET_PROXY"; ProxyStrategy[ProxyStrategy["PRIVATELINK_PROXY"] = 3] = "PRIVATELINK_PROXY"; })(ProxyStrategy = exports.ProxyStrategy || (exports.ProxyStrategy = {})); //# sourceMappingURL=proxy-util.js.map