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