@heroku/heroku-cli-util 8.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +3 -0
- package/README.md +269 -0
- package/index.js +40 -0
- package/lib/action.js +54 -0
- package/lib/auth.js +207 -0
- package/lib/command.js +171 -0
- package/lib/console.js +105 -0
- package/lib/date.js +18 -0
- package/lib/errors.js +122 -0
- package/lib/exit.js +42 -0
- package/lib/got.js +153 -0
- package/lib/linewrap.js +783 -0
- package/lib/mutex.js +41 -0
- package/lib/open.js +22 -0
- package/lib/preauth.js +26 -0
- package/lib/process.js +14 -0
- package/lib/prompt.js +150 -0
- package/lib/spinner.js +147 -0
- package/lib/spinners.json +739 -0
- package/lib/styled.js +131 -0
- package/lib/table.js +132 -0
- package/lib/util.js +38 -0
- package/lib/vars.js +29 -0
- package/lib/yubikey.js +14 -0
- package/package.json +80 -0
package/lib/command.js
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const Heroku = require('heroku-client')
|
|
4
|
+
const cli = require('..')
|
|
5
|
+
const auth = require('./auth')
|
|
6
|
+
const vars = require('./vars')
|
|
7
|
+
const Mutex = require('./mutex')
|
|
8
|
+
|
|
9
|
+
function twoFactorWrapper (options, preauths, context) {
|
|
10
|
+
return function (res, buffer) {
|
|
11
|
+
let body
|
|
12
|
+
try {
|
|
13
|
+
body = this.parseBody(buffer)
|
|
14
|
+
} catch (e) {
|
|
15
|
+
this._handleFailure(res, buffer)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// safety check for if we have already seen this request for preauthing
|
|
19
|
+
// this prevents an infinite loop in case some preauth fails silently
|
|
20
|
+
// and we continue to get two_factor failures
|
|
21
|
+
|
|
22
|
+
// this might be better done with a timer in case a command takes too long
|
|
23
|
+
// and the preauthorization runs out, but that seemed unlikely
|
|
24
|
+
if (res.statusCode === 403 && body.id === 'two_factor' && !preauths.requests.includes(this)) {
|
|
25
|
+
let self = this
|
|
26
|
+
// default preauth to always happen unless explicitly disabled
|
|
27
|
+
if (options.preauth === false || !body.app) {
|
|
28
|
+
twoFactorPrompt(options, preauths, context)
|
|
29
|
+
.then(function (secondFactor) {
|
|
30
|
+
self.options.headers = Object.assign({}, self.options.headers, { 'Heroku-Two-Factor-Code': secondFactor })
|
|
31
|
+
self.request()
|
|
32
|
+
})
|
|
33
|
+
.catch(function (err) {
|
|
34
|
+
self.reject(err)
|
|
35
|
+
})
|
|
36
|
+
} else {
|
|
37
|
+
preauths.requests.push(self)
|
|
38
|
+
|
|
39
|
+
// if multiple requests are run in parallel for the same app, we should
|
|
40
|
+
// only preauth for the first so save the fact we already preauthed
|
|
41
|
+
if (!preauths.promises[body.app.name]) {
|
|
42
|
+
preauths.promises[body.app.name] = twoFactorPrompt(options, preauths, context)
|
|
43
|
+
.then(function (secondFactor) {
|
|
44
|
+
return cli.preauth(body.app.name, heroku(context), secondFactor)
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
preauths.promises[body.app.name].then(function () {
|
|
49
|
+
self.request()
|
|
50
|
+
})
|
|
51
|
+
.catch(function (err) {
|
|
52
|
+
self.reject(err)
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
} else {
|
|
56
|
+
this._handleFailure(res, buffer)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function apiMiddleware (options, preauths, context) {
|
|
62
|
+
let twoFactor = twoFactorWrapper(options, preauths, context)
|
|
63
|
+
return function (response, cb) {
|
|
64
|
+
let warning = response.headers['x-heroku-warning'] || response.headers['warning-message']
|
|
65
|
+
if (warning) cli.action.warn(warning)
|
|
66
|
+
|
|
67
|
+
// override the _handleFailure for this request
|
|
68
|
+
if (!this._handleFailure) {
|
|
69
|
+
this._handleFailure = this.handleFailure
|
|
70
|
+
this.handleFailure = twoFactor.bind(this)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
cb()
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function heroku (context, options) {
|
|
78
|
+
let host = context.apiUrl || vars.apiUrl || 'https://api.heroku.com'
|
|
79
|
+
|
|
80
|
+
let preauths = {
|
|
81
|
+
promises: {},
|
|
82
|
+
requests: [],
|
|
83
|
+
twoFactorMutex: new Mutex()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
let opts = {
|
|
87
|
+
userAgent: context.version,
|
|
88
|
+
debug: context.debug,
|
|
89
|
+
debugHeaders: context.debugHeaders,
|
|
90
|
+
token: context.auth ? context.auth.password : null,
|
|
91
|
+
host: host,
|
|
92
|
+
headers: {},
|
|
93
|
+
rejectUnauthorized: !(process.env.HEROKU_SSL_VERIFY === 'disable' || host.endsWith('herokudev.com')),
|
|
94
|
+
middleware: apiMiddleware(options, preauths, context)
|
|
95
|
+
}
|
|
96
|
+
if (process.env.HEROKU_HEADERS) {
|
|
97
|
+
Object.assign(opts.headers, JSON.parse(process.env.HEROKU_HEADERS))
|
|
98
|
+
}
|
|
99
|
+
if (context.secondFactor) {
|
|
100
|
+
Object.assign(opts.headers, { 'Heroku-Two-Factor-Code': context.secondFactor })
|
|
101
|
+
}
|
|
102
|
+
if (context.reason) {
|
|
103
|
+
Object.assign(opts.headers, { 'X-Heroku-Sudo-Reason': context.reason })
|
|
104
|
+
}
|
|
105
|
+
cli.heroku = new Heroku(opts)
|
|
106
|
+
return cli.heroku
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
let httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy || process.env.HTTP_PROXY || process.env.http_proxy
|
|
110
|
+
|
|
111
|
+
function setupHttpProxy () {
|
|
112
|
+
const url = require('url')
|
|
113
|
+
cli.hush(`proxy set to ${httpsProxy}`)
|
|
114
|
+
let proxy = url.parse(httpsProxy)
|
|
115
|
+
process.env.HEROKU_HTTP_PROXY_HOST = proxy.hostname
|
|
116
|
+
process.env.HEROKU_HTTP_PROXY_PORT = proxy.port
|
|
117
|
+
process.env.HEROKU_HTTP_PROXY_AUTH = proxy.auth
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function relogin () {
|
|
121
|
+
if (process.env.HEROKU_LOGIN_REDIRECT === '1') return auth.login({ save: true })
|
|
122
|
+
process.env.HEROKU_LOGIN_REDIRECT = '1'
|
|
123
|
+
require('child_process').execSync('heroku login', { stdio: 'inherit' })
|
|
124
|
+
return Promise.resolve()
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function twoFactorPrompt (options, preauths, context) {
|
|
128
|
+
cli.yubikey.enable()
|
|
129
|
+
return preauths.twoFactorMutex.synchronize(function () {
|
|
130
|
+
return cli.prompt('Two-factor code', { mask: true })
|
|
131
|
+
.catch(function (err) {
|
|
132
|
+
cli.yubikey.disable()
|
|
133
|
+
throw err
|
|
134
|
+
})
|
|
135
|
+
.then(function (secondFactor) {
|
|
136
|
+
cli.yubikey.disable()
|
|
137
|
+
return secondFactor
|
|
138
|
+
})
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function reasonPrompt (context) {
|
|
143
|
+
return cli.prompt('Reason')
|
|
144
|
+
.then(function (reason) {
|
|
145
|
+
context.reason = reason
|
|
146
|
+
})
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
module.exports = function command (options, fn) {
|
|
150
|
+
return function (context) {
|
|
151
|
+
if (typeof options === 'function') [fn, options] = [options, {}]
|
|
152
|
+
if (httpsProxy) setupHttpProxy()
|
|
153
|
+
cli.color.enabled = context.supportsColor
|
|
154
|
+
let handleErr = cli.errorHandler({ debug: context.debug })
|
|
155
|
+
let run = function () {
|
|
156
|
+
context.auth = { password: auth.token() }
|
|
157
|
+
let p = fn(context, heroku(context, options))
|
|
158
|
+
if (!p.catch) return
|
|
159
|
+
return p.catch(function (err) {
|
|
160
|
+
if (err && err.body && err.body.id === 'unauthorized') {
|
|
161
|
+
cli.error(err.body.message || 'Unauthorized')
|
|
162
|
+
return relogin().then(run).catch(handleErr)
|
|
163
|
+
} else if (err && err.body && err.body.id === 'sudo_reason_required') {
|
|
164
|
+
cli.warn(err.body.message)
|
|
165
|
+
return reasonPrompt(context).then(run).catch(handleErr)
|
|
166
|
+
} else throw err
|
|
167
|
+
}).catch(handleErr)
|
|
168
|
+
}
|
|
169
|
+
return run()
|
|
170
|
+
}
|
|
171
|
+
}
|
package/lib/console.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
var cli = require('..')
|
|
4
|
+
const stripAnsi = require('strip-ansi')
|
|
5
|
+
|
|
6
|
+
var mocking
|
|
7
|
+
|
|
8
|
+
function concatArguments (args) {
|
|
9
|
+
return Array.prototype.map.call(args, function (arg) {
|
|
10
|
+
return arg + ''
|
|
11
|
+
}).join(' ')
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* log is a wrapper for console.log() but can be mocked
|
|
16
|
+
*
|
|
17
|
+
* @param {...Object} obj - objects to be printed to stdout
|
|
18
|
+
*/
|
|
19
|
+
function log () {
|
|
20
|
+
if (mocking) {
|
|
21
|
+
cli.stdout += stripAnsi(concatArguments(arguments) + '\n')
|
|
22
|
+
} else {
|
|
23
|
+
console.log.apply(null, arguments)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* writeLog is a wrapper for process.stdout.write() but can be mocked
|
|
29
|
+
*
|
|
30
|
+
* @param {...Object} obj - objects to be printed to stdout
|
|
31
|
+
*/
|
|
32
|
+
function writeLog () {
|
|
33
|
+
if (mocking) {
|
|
34
|
+
cli.stdout += stripAnsi(concatArguments(arguments))
|
|
35
|
+
} else {
|
|
36
|
+
process.stdout.write.apply(process.stdout, arguments)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function hush () {
|
|
41
|
+
let debug = process.env.HEROKU_DEBUG
|
|
42
|
+
if (debug && (debug === '1' || debug.toUpperCase() === 'TRUE')) {
|
|
43
|
+
console.error.apply(null, arguments)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* error is a wrapper for console.error() but can be mocked
|
|
49
|
+
*
|
|
50
|
+
* @param {...Object} obj - objects to be printed to stderr
|
|
51
|
+
*/
|
|
52
|
+
function error () {
|
|
53
|
+
if (mocking) {
|
|
54
|
+
cli.stderr += stripAnsi(concatArguments(arguments) + '\n')
|
|
55
|
+
} else {
|
|
56
|
+
console.error.apply(null, arguments)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* writeError is a wrapper for process.stderr.write() but can be mocked
|
|
62
|
+
*
|
|
63
|
+
* @param {...Object} obj - objects to be printed to stderr
|
|
64
|
+
*/
|
|
65
|
+
function writeError () {
|
|
66
|
+
if (mocking) {
|
|
67
|
+
cli.stderr += stripAnsi(concatArguments(arguments))
|
|
68
|
+
} else {
|
|
69
|
+
process.stderr.write.apply(process.stderr, arguments)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* mock will make {@link log} and {@link error}
|
|
75
|
+
* stop printing to stdout and stderr and start writing to the
|
|
76
|
+
* stdout and stderr strings.
|
|
77
|
+
*/
|
|
78
|
+
function mock (mock) {
|
|
79
|
+
if (mock === false) {
|
|
80
|
+
mocking = false
|
|
81
|
+
} else {
|
|
82
|
+
mocking = true
|
|
83
|
+
cli.stderr = ''
|
|
84
|
+
cli.stdout = ''
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* debug pretty prints an object.
|
|
90
|
+
* It simply calls console.dir with color enabled.
|
|
91
|
+
*
|
|
92
|
+
* @param {Object} obj - object to be printed
|
|
93
|
+
*/
|
|
94
|
+
function debug (obj) {
|
|
95
|
+
console.dir(obj, { colors: true })
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
exports.hush = hush
|
|
99
|
+
exports.log = log
|
|
100
|
+
exports.writeLog = writeLog
|
|
101
|
+
exports.error = error
|
|
102
|
+
exports.writeError = writeError
|
|
103
|
+
exports.mock = mock
|
|
104
|
+
exports.mocking = () => mocking
|
|
105
|
+
exports.debug = debug
|
package/lib/date.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* formatDate will format a date in a standard Heroku format
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* let cli = require('heroku-cli-util')
|
|
8
|
+
* var d = new Date()
|
|
9
|
+
* cli.formatDate(d); // '2015-05-14T18:03:10.034Z'
|
|
10
|
+
*
|
|
11
|
+
* @param {Date} date the date to format
|
|
12
|
+
* @return {String} string representing the date
|
|
13
|
+
*/
|
|
14
|
+
function formatDate (date) {
|
|
15
|
+
return date.toISOString()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
exports.formatDate = formatDate
|
package/lib/errors.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const stripAnsi = require('strip-ansi')
|
|
4
|
+
let cli = require('..')
|
|
5
|
+
let console = require('./console')
|
|
6
|
+
let linewrap = require('./linewrap')
|
|
7
|
+
let path = require('path')
|
|
8
|
+
let os = require('os')
|
|
9
|
+
|
|
10
|
+
function errtermwidth () {
|
|
11
|
+
if (global.columns) return global.columns
|
|
12
|
+
if (!process.stderr.isTTY || !process.stderr.getWindowSize) return 80
|
|
13
|
+
let width = process.stderr.getWindowSize()[0]
|
|
14
|
+
return width < 30 ? 30 : width
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function wrap (msg) {
|
|
18
|
+
return linewrap(6,
|
|
19
|
+
errtermwidth(), {
|
|
20
|
+
skipScheme: 'ansi-color',
|
|
21
|
+
skip: /^\$ .*$/
|
|
22
|
+
})(msg || '')
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function bangify (msg, c) {
|
|
26
|
+
let lines = msg.split('\n')
|
|
27
|
+
for (let i = 0; i < lines.length; i++) {
|
|
28
|
+
let line = lines[i]
|
|
29
|
+
lines[i] = ' ' + c + line.substr(2, line.length)
|
|
30
|
+
}
|
|
31
|
+
return lines.join('\n')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function getErrorMessage (err) {
|
|
35
|
+
if (err.body) {
|
|
36
|
+
// API error
|
|
37
|
+
if (err.body.message) {
|
|
38
|
+
return err.body.message
|
|
39
|
+
} else if (err.body.error) {
|
|
40
|
+
return err.body.error
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Unhandled error
|
|
44
|
+
if (err.message && err.code) {
|
|
45
|
+
return `${err.code}: ${err.message}`
|
|
46
|
+
} else if (err.message) {
|
|
47
|
+
return err.message
|
|
48
|
+
}
|
|
49
|
+
return err
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let arrow = process.platform === 'win32' ? '!' : '▸'
|
|
53
|
+
|
|
54
|
+
function error (err) {
|
|
55
|
+
console.error(bangify(wrap(getErrorMessage(err)), cli.color.red(arrow)))
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function warn (msg) {
|
|
59
|
+
console.error(renderWarning(msg))
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function renderWarning (msg) {
|
|
63
|
+
return bangify(wrap(msg), cli.color.yellow(arrow))
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function logtimestamp () {
|
|
67
|
+
return new Date().toISOString()
|
|
68
|
+
.replace(/T/, ' ')
|
|
69
|
+
.replace(/-/g, '/')
|
|
70
|
+
.replace(/\..+/, '')
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function cacheHome () {
|
|
74
|
+
let base
|
|
75
|
+
if (process.env.XDG_CACHE_HOME) base = process.env.XDG_CACHE_HOME
|
|
76
|
+
if (!base) {
|
|
77
|
+
if (process.platform === 'darwin') {
|
|
78
|
+
base = path.join(os.homedir(), 'Library', 'Caches')
|
|
79
|
+
} else if (process.platform === 'win32' && process.env.LOCALAPPDATA) {
|
|
80
|
+
base = process.env.LOCALAPPDATA
|
|
81
|
+
} else {
|
|
82
|
+
base = path.join(os.homedir(), '.cache')
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return path.join(base, 'heroku')
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function log (msg) {
|
|
89
|
+
let fs = require('fs')
|
|
90
|
+
let logPath = path.join(cacheHome(), 'error.log')
|
|
91
|
+
fs.appendFileSync(logPath, logtimestamp() + ' ' + stripAnsi(msg) + '\n')
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function errorHandler (options) {
|
|
95
|
+
options = options || {}
|
|
96
|
+
function exit () {
|
|
97
|
+
if (options.exit !== false) {
|
|
98
|
+
process.exit(1)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return function handleErr (err) {
|
|
102
|
+
if (cli.raiseErrors) throw err
|
|
103
|
+
try {
|
|
104
|
+
if (err !== '') error(err)
|
|
105
|
+
if (err.stack) {
|
|
106
|
+
log(err.stack)
|
|
107
|
+
if (options.debug) console.error(err.stack)
|
|
108
|
+
}
|
|
109
|
+
if (err.body) log(JSON.stringify(err.body))
|
|
110
|
+
exit()
|
|
111
|
+
} catch (err) {
|
|
112
|
+
console.error(err.stack)
|
|
113
|
+
process.exit(-1)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
module.exports.error = error
|
|
119
|
+
module.exports.warn = warn
|
|
120
|
+
module.exports.errorHandler = errorHandler
|
|
121
|
+
module.exports.renderWarning = renderWarning
|
|
122
|
+
module.exports.errtermwidth = errtermwidth
|
package/lib/exit.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
var util = require('util')
|
|
4
|
+
var cli = require('./errors')
|
|
5
|
+
|
|
6
|
+
function ErrorExit (code, message) {
|
|
7
|
+
Error.call(this)
|
|
8
|
+
Error.captureStackTrace(this, this.constructor)
|
|
9
|
+
this.name = this.constructor.name
|
|
10
|
+
|
|
11
|
+
this.code = code
|
|
12
|
+
this.message = message
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
util.inherits(ErrorExit, Error)
|
|
16
|
+
|
|
17
|
+
var mocking
|
|
18
|
+
|
|
19
|
+
function exit (code, message) {
|
|
20
|
+
if (message) {
|
|
21
|
+
cli.error(message)
|
|
22
|
+
}
|
|
23
|
+
if (mocking) {
|
|
24
|
+
throw new ErrorExit(code, message)
|
|
25
|
+
} else {
|
|
26
|
+
process.exit(code)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
exit.mock = function (mock) {
|
|
31
|
+
if (mock === false) {
|
|
32
|
+
mocking = false
|
|
33
|
+
} else {
|
|
34
|
+
mocking = true
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
exit.ErrorExit = ErrorExit
|
|
39
|
+
|
|
40
|
+
module.exports = {
|
|
41
|
+
exit
|
|
42
|
+
}
|
package/lib/got.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
let hush = require('./console').hush
|
|
4
|
+
|
|
5
|
+
function findProxy (urlParsed) {
|
|
6
|
+
let httpProxy = process.env.HTTP_PROXY || process.env.http_proxy
|
|
7
|
+
let httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy
|
|
8
|
+
|
|
9
|
+
if (urlParsed.protocol === 'https:') {
|
|
10
|
+
return httpsProxy || httpProxy
|
|
11
|
+
} else {
|
|
12
|
+
return httpProxy
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function findTunnel (urlParsed) {
|
|
17
|
+
let tunnel = require('tunnel-agent')
|
|
18
|
+
|
|
19
|
+
if (urlParsed.protocol === 'https:') {
|
|
20
|
+
return tunnel.httpsOverHttp
|
|
21
|
+
} else {
|
|
22
|
+
return tunnel.httpOverHttp
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function agent (urlParsed, proxyParsed, certs) {
|
|
27
|
+
let tunnelMethod = findTunnel(urlParsed)
|
|
28
|
+
let opts = {
|
|
29
|
+
proxy: {
|
|
30
|
+
host: proxyParsed.hostname,
|
|
31
|
+
port: proxyParsed.port || '8080'
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (proxyParsed.auth) {
|
|
36
|
+
opts.proxy.proxyAuth = proxyParsed.auth
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (certs.length > 0) {
|
|
40
|
+
opts.ca = certs
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let tunnelAgent = tunnelMethod(opts)
|
|
44
|
+
if (urlParsed.protocol === 'https:') {
|
|
45
|
+
tunnelAgent.defaultPort = 443
|
|
46
|
+
}
|
|
47
|
+
return tunnelAgent
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function sslCertFile () {
|
|
51
|
+
return process.env.SSL_CERT_FILE ? [process.env.SSL_CERT_FILE] : []
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function sslCertDir () {
|
|
55
|
+
let certDir = process.env.SSL_CERT_DIR
|
|
56
|
+
if (certDir) {
|
|
57
|
+
const fs = require('fs')
|
|
58
|
+
const path = require('path')
|
|
59
|
+
return fs.readdirSync(certDir).map(f => path.join(certDir, f))
|
|
60
|
+
} else {
|
|
61
|
+
return []
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getCerts () {
|
|
66
|
+
let filenames = sslCertFile().concat(sslCertDir())
|
|
67
|
+
|
|
68
|
+
if (filenames.length > 0) {
|
|
69
|
+
hush('Adding the following trusted certificate authorities')
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return filenames.map(function (filename) {
|
|
73
|
+
const fs = require('fs')
|
|
74
|
+
hush(' ' + filename)
|
|
75
|
+
return fs.readFileSync(filename)
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function addToOpts (url, opts) {
|
|
80
|
+
const urlLib = require('url')
|
|
81
|
+
|
|
82
|
+
let urlParsed = urlLib.parse(url)
|
|
83
|
+
let proxy = findProxy(urlParsed)
|
|
84
|
+
|
|
85
|
+
let certs = getCerts()
|
|
86
|
+
|
|
87
|
+
if (proxy) {
|
|
88
|
+
let proxyParsed = urlLib.parse(proxy)
|
|
89
|
+
opts = Object.assign({}, opts, { agent: agent(urlParsed, proxyParsed, certs) })
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (certs.length > 0) {
|
|
93
|
+
opts = Object.assign({}, opts, { ca: certs })
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return opts
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let loadErrors
|
|
100
|
+
|
|
101
|
+
function got (url, opts) {
|
|
102
|
+
const gotDelegate = require('got')
|
|
103
|
+
loadErrors()
|
|
104
|
+
return gotDelegate(url, addToOpts(url, opts))
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
got.stream = function (url, opts) {
|
|
108
|
+
const gotDelegate = require('got')
|
|
109
|
+
loadErrors()
|
|
110
|
+
return gotDelegate.stream(url, addToOpts(url, opts))
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const helpers = [
|
|
114
|
+
'get',
|
|
115
|
+
'post',
|
|
116
|
+
'put',
|
|
117
|
+
'patch',
|
|
118
|
+
'head',
|
|
119
|
+
'delete'
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
helpers.forEach(el => {
|
|
123
|
+
got[el] = (url, opts) => got(url, Object.assign({}, opts, { method: el }))
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
helpers.forEach(el => {
|
|
127
|
+
got.stream[el] = function (url, opts) {
|
|
128
|
+
return got.stream(url, Object.assign({}, opts, { method: el }))
|
|
129
|
+
}
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
loadErrors = () => {
|
|
133
|
+
const gotDelegate = require('got')
|
|
134
|
+
|
|
135
|
+
const errors = [
|
|
136
|
+
'CacheError',
|
|
137
|
+
'CancelError',
|
|
138
|
+
'UnsupportedProtocolError',
|
|
139
|
+
'HTTPError',
|
|
140
|
+
'MaxRedirectsError',
|
|
141
|
+
'ParseError',
|
|
142
|
+
'ReadError',
|
|
143
|
+
'RequestError',
|
|
144
|
+
'TimeoutError',
|
|
145
|
+
'UploadError'
|
|
146
|
+
]
|
|
147
|
+
|
|
148
|
+
errors.forEach(el => {
|
|
149
|
+
got[el] = gotDelegate[el]
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
module.exports = got
|