@sap-cloud-sdk/core
Version:
SAP Cloud SDK for JavaScript core
204 lines • 9.87 kB
JavaScript
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
;