-
Notifications
You must be signed in to change notification settings - Fork 46
/
Copy pathhttp-agent.ts
156 lines (137 loc) · 4.93 KB
/
http-agent.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/* Copyright (c) 2020 SAP SE or an SAP affiliate company. All rights reserved. */
import * as http from 'http';
import * as https from 'https';
import { createLogger } from '@sap-cloud-sdk/util';
import { assoc, last, pipe } from 'rambda';
import { Destination, DestinationCertificate } from './scp-cf';
import { proxyAgent } from './util/proxy-util';
import { Protocol } from './protocol';
import { HttpAgentConfig, HttpsAgentConfig } from './agent-config';
import { getProtocolOrDefault } from './get-protocol';
const logger = createLogger({
package: 'core',
messageContext: 'http-agent'
});
/**
* Returns the http or https-agent config depending on the destination URL.
* If the destination contains a proxy configuration, the agent will be a proxy-agent.
* If not it will be the default http-agent coming from node.
*
* @param destination - determining which kind of configuration is returned
* @returns The http or http-agent configuration.
*/
export function getAgentConfig(
destination: Destination
): HttpAgentConfig | HttpsAgentConfig {
const agentType = destination.proxyConfiguration
? AgentType.PROXY
: AgentType.DEFAULT;
if (agentType === AgentType.PROXY) {
return createProxyAgent(destination);
}
return createDefaultAgent(destination);
}
enum AgentType {
DEFAULT,
PROXY
}
function createProxyAgent(
destination: Destination
): HttpAgentConfig | HttpsAgentConfig {
if (!destination.proxyConfiguration) {
throw new Error(
`The destination proxy configuration: ${destination.proxyConfiguration} is undefined.`
);
}
if (destination.isTrustingAllCertificates) {
logger.warn(
'The destination is configured to both use a proxy and to trust all certificates. This is currently not supported. The proxy configuration will be applied, but certificates will be validated.'
);
}
return proxyAgent(destination);
}
const trustAllOptions = (destination: Destination) => (
options: Record<string, any>
): Record<string, any> =>
assoc('rejectUnauthorized', !destination.isTrustingAllCertificates, options);
const certificateOptions = (destination: Destination) => (
options: Record<string, any>
): Record<string, any> => {
if (destination.keyStoreName && destination.keyStorePassword) {
const certificate = selectCertificate(destination);
return {
...options,
pfx: Buffer.from(certificate.content, 'base64'),
passphrase: destination.keyStorePassword
};
}
return options;
};
const supportedCertificateFormats = ['p12', 'pfx'];
function hasSupportedFormat(certificate: DestinationCertificate): boolean {
const certificateFormat = last(certificate.name.split('.'));
if (certificateFormat) {
return supportedCertificateFormats.includes(certificateFormat);
}
return false;
}
function selectCertificate(destination): DestinationCertificate {
const certificate = destination.certificates.find(
c => c.name === destination.keyStoreName
);
if (!certificate) {
throw Error(
`No certificate with name ${destination.keyStoreName} could be found on the destination!`
);
}
if (!hasSupportedFormat(certificate)) {
const format: string | undefined = last(certificate.name.split('.'));
throw Error(
`The format of the provided certificate ${
certificate.name
} is not supported. Supported formats are: ${supportedCertificateFormats.join(
', '
)}. ${
format && ['jks', 'keystore'].includes(format)
? "You can convert Java Keystores (.jks, .keystore) into PKCS#12 keystores using the JVM's keytool CLI: keytool -importkeystore -srckeystore your-keystore.jks -destkeystore your-keystore.p12 -deststoretype pkcs12"
: ''
}`
);
}
return certificate;
}
function createDefaultAgent(
destination: Destination
): HttpAgentConfig | HttpsAgentConfig {
if (getProtocolOrDefault(destination) === Protocol.HTTPS) {
if (destination.isTrustingAllCertificates) {
logger.warn(
'"isTrustingAllCertificates" property in the provided destination is set to "true". This is highly discouraged in production.'
);
}
const options = pipe(
trustAllOptions(destination),
certificateOptions(destination)
)({});
return { httpsAgent: new https.Agent(options) };
}
if (destination.isTrustingAllCertificates) {
logger.warn('"isTrustingAllCertificates" is not available for HTTP.');
}
return { httpAgent: new http.Agent() };
}
/**
* @deprecated Since v1.5.1. use getProtocolOrDefault instead
* Takes the destination URL and return everything before the '://'.
*
* @param destination - URL of this destination is parsed
* @returns The protocol either undefined if no :// is found or anything before the delimiter.
*/
export function getUrlProtocol(destination: Destination): Protocol | undefined {
if (destination.url) {
const urlParts = destination.url.toLowerCase().split('://');
if (urlParts.length > 1) {
return urlParts[0] as Protocol;
}
}
}