forked from desktop/desktop
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathenvironment.ts
136 lines (123 loc) · 5.18 KB
/
environment.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
import { envForAuthentication } from './authentication'
import { IGitAccount } from '../../models/git-account'
import { enableAutomaticGitProxyConfiguration } from '../feature-flag'
import { resolveGitProxy } from '../resolve-git-proxy'
import { getDotComAPIEndpoint } from '../api'
import { Repository } from '../../models/repository'
/**
* For many remote operations it's well known what the primary remote
* url is (clone, push, fetch etc). But in some cases it's not as easy.
*
* Two examples are checkout, and revert where neither would need to
* hit the network in vanilla Git usage but do need to when LFS gets
* involved.
*
* What's the primary url when using LFS then? Most likely it's gonna
* be on the same as the default remote but it could theoretically
* be on a different server as well. That's too advanced for our usage
* at the moment though so we'll just need to figure out some reasonable
* url to fall back on.
*/
export function getFallbackUrlForProxyResolve(
account: IGitAccount | null,
repository: Repository
) {
// If we've got an account with an endpoint that means we've already done the
// heavy lifting to figure out what the most likely endpoint is gonna be
// so we'll try to leverage that.
if (account !== null) {
// A GitHub.com Account will have api.github.com as its endpoint
return account.endpoint === getDotComAPIEndpoint()
? 'https://github.com'
: account.endpoint
}
if (repository.gitHubRepository !== null) {
if (repository.gitHubRepository.cloneURL !== null) {
return repository.gitHubRepository.cloneURL
}
}
// If all else fails let's assume that whatever network resource
// Git is gonna hit it's gonna be using the same proxy as it would
// if it was a GitHub.com endpoint
return 'https://github.com'
}
/**
* Create a set of environment variables to use when invoking a Git
* subcommand that needs to communicate with a remote (i.e. fetch, clone,
* push, pull, ls-remote, etc etc).
*
* The environment variables deal with setting up sane defaults, configuring
* authentication, and resolving proxy urls if necessary.
*
* @param account The authentication information (if available) to provide
* to Git for use when connectingt to the remote
* @param remoteUrl The primary remote URL for this operation. Note that Git
* might connect to other remotes in order to fulfill the
* operation. As an example, a clone of
* https://github.com/desktop/desktop could containt a submodule
* pointing to another host entirely. Used to resolve which
* proxy (if any) should be used for the operation.
*/
export async function envForRemoteOperation(
account: IGitAccount | null,
remoteUrl: string
) {
return {
...envForAuthentication(account),
...(await envForProxy(remoteUrl)),
}
}
/**
* Not intended to be used directly. Exported only in order to
* allow for testing.
*
* @param remoteUrl The remote url to resolve a proxy for.
* @param env The current environment variables, defaults
* to `process.env`
* @param resolve The method to use when resolving the proxy url,
* defaults to `resolveGitProxy`
*/
export async function envForProxy(
remoteUrl: string,
env: NodeJS.ProcessEnv = process.env,
resolve: (url: string) => Promise<string | undefined> = resolveGitProxy
): Promise<NodeJS.ProcessEnv | undefined> {
if (!enableAutomaticGitProxyConfiguration()) {
return undefined
}
// We'll play it safe and say that if the user has configured
// the ALL_PROXY environment variable they probably know what
// they're doing and wouldn't want us to override it with a
// protocol-specific proxy. cURL supports both lower and upper
// case, see:
// https://github.com/curl/curl/blob/14916a82e/lib/url.c#L2180-L2185
if ('ALL_PROXY' in env || 'all_proxy' in env) {
log.info(`proxy url not resolved, ALL_PROXY already set`)
return
}
const protocolMatch = /^(https?):\/\//i.exec(remoteUrl)
// We can only resolve and use a proxy for the protocols where cURL
// would be involved (i.e http and https). git:// relies on ssh.
if (protocolMatch === null) {
log.info(`proxy url not resolved, protocol not supported`)
return
}
// Note that HTTPS here doesn't mean that the proxy is HTTPS, only
// that all requests to HTTPS protocols should be proxied. The
// proxy protocol is defined by the url returned by `this.resolve()`
const proto = protocolMatch[1].toLowerCase() // http or https
// Lower case environment variables due to
// https://ec.haxx.se/usingcurl/usingcurl-proxies#http_proxy-in-lower-case-only
const envKey = `${proto}_proxy` // http_proxy or https_proxy
// If the user has already configured a proxy in the environment
// for the protocol we're not gonna override it.
if (envKey in env || (proto === 'https' && 'HTTPS_PROXY' in env)) {
log.info(`proxy url not resolved, ${envKey} already set`)
return
}
const proxyUrl = await resolve(remoteUrl).catch(err => {
log.error('Failed resolving Git proxy', err)
return undefined
})
return proxyUrl === undefined ? undefined : { [envKey]: proxyUrl }
}