freebuff 0.0.21 → 0.0.23

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.
Files changed (2) hide show
  1. package/index.js +109 -11
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -6,6 +6,7 @@ const http = require('http')
6
6
  const https = require('https')
7
7
  const os = require('os')
8
8
  const path = require('path')
9
+ const tls = require('tls')
9
10
  const zlib = require('zlib')
10
11
 
11
12
  const tar = require('tar')
@@ -95,6 +96,76 @@ function trackUpdateFailed(errorMessage, version, context = {}) {
95
96
  }
96
97
  }
97
98
 
99
+ function getProxyUrl() {
100
+ return (
101
+ process.env.HTTPS_PROXY ||
102
+ process.env.https_proxy ||
103
+ process.env.HTTP_PROXY ||
104
+ process.env.http_proxy ||
105
+ null
106
+ )
107
+ }
108
+
109
+ function shouldBypassProxy(hostname) {
110
+ const noProxy = process.env.NO_PROXY || process.env.no_proxy || ''
111
+ if (!noProxy) return false
112
+ const domains = noProxy.split(',').map((d) => d.trim().toLowerCase().replace(/:\d+$/, ''))
113
+ const host = hostname.toLowerCase()
114
+ return domains.some((d) => {
115
+ if (d === '*') return true
116
+ if (d.startsWith('.')) return host.endsWith(d) || host === d.slice(1)
117
+ return host === d || host.endsWith('.' + d)
118
+ })
119
+ }
120
+
121
+ function connectThroughProxy(proxyUrl, targetHost, targetPort) {
122
+ return new Promise((resolve, reject) => {
123
+ const proxy = new URL(proxyUrl)
124
+ const isHttpsProxy = proxy.protocol === 'https:'
125
+ const connectOptions = {
126
+ hostname: proxy.hostname,
127
+ port: proxy.port || (isHttpsProxy ? 443 : 80),
128
+ method: 'CONNECT',
129
+ path: `${targetHost}:${targetPort}`,
130
+ headers: {
131
+ Host: `${targetHost}:${targetPort}`,
132
+ },
133
+ }
134
+
135
+ if (proxy.username || proxy.password) {
136
+ const auth = Buffer.from(
137
+ `${decodeURIComponent(proxy.username || '')}:${decodeURIComponent(proxy.password || '')}`,
138
+ ).toString('base64')
139
+ connectOptions.headers['Proxy-Authorization'] = `Basic ${auth}`
140
+ }
141
+
142
+ const transport = isHttpsProxy ? https : http
143
+ const req = transport.request(connectOptions)
144
+
145
+ req.on('connect', (res, socket) => {
146
+ if (res.statusCode === 200) {
147
+ resolve(socket)
148
+ } else {
149
+ socket.destroy()
150
+ reject(
151
+ new Error(`Proxy CONNECT failed with status ${res.statusCode}`),
152
+ )
153
+ }
154
+ })
155
+
156
+ req.on('error', (err) => {
157
+ reject(new Error(`Proxy connection failed: ${err.message}`))
158
+ })
159
+
160
+ req.setTimeout(CONFIG.requestTimeout, () => {
161
+ req.destroy()
162
+ reject(new Error('Proxy connection timeout.'))
163
+ })
164
+
165
+ req.end()
166
+ })
167
+ }
168
+
98
169
  const PLATFORM_TARGETS = {
99
170
  'linux-x64': `${packageName}-linux-x64.tar.gz`,
100
171
  'linux-arm64': `${packageName}-linux-arm64.tar.gz`,
@@ -119,20 +190,37 @@ const term = {
119
190
  },
120
191
  }
121
192
 
122
- function httpGet(url, options = {}) {
123
- return new Promise((resolve, reject) => {
124
- const parsedUrl = new URL(url)
125
- const reqOptions = {
126
- hostname: parsedUrl.hostname,
127
- path: parsedUrl.pathname + parsedUrl.search,
128
- headers: {
129
- 'User-Agent': CONFIG.userAgent,
130
- ...options.headers,
131
- },
132
- }
193
+ async function httpGet(url, options = {}) {
194
+ const parsedUrl = new URL(url)
195
+ const proxyUrl = getProxyUrl()
196
+
197
+ const reqOptions = {
198
+ hostname: parsedUrl.hostname,
199
+ path: parsedUrl.pathname + parsedUrl.search,
200
+ headers: {
201
+ 'User-Agent': CONFIG.userAgent,
202
+ ...options.headers,
203
+ },
204
+ }
205
+
206
+ if (proxyUrl && !shouldBypassProxy(parsedUrl.hostname)) {
207
+ const tunnelSocket = await connectThroughProxy(
208
+ proxyUrl,
209
+ parsedUrl.hostname,
210
+ parsedUrl.port || 443,
211
+ )
212
+ reqOptions.agent = false
213
+ reqOptions.createConnection = () =>
214
+ tls.connect({
215
+ socket: tunnelSocket,
216
+ servername: parsedUrl.hostname,
217
+ })
218
+ }
133
219
 
220
+ return new Promise((resolve, reject) => {
134
221
  const req = https.get(reqOptions, (res) => {
135
222
  if (res.statusCode === 302 || res.statusCode === 301) {
223
+ res.resume()
136
224
  return httpGet(new URL(res.headers.location, url).href, options)
137
225
  .then(resolve)
138
226
  .catch(reject)
@@ -388,6 +476,11 @@ async function ensureBinaryExists() {
388
476
  if (!version) {
389
477
  console.error('❌ Failed to determine latest version')
390
478
  console.error('Please check your internet connection and try again')
479
+ if (!getProxyUrl()) {
480
+ console.error(
481
+ 'If you are behind a proxy, set the HTTPS_PROXY environment variable',
482
+ )
483
+ }
391
484
  process.exit(1)
392
485
  }
393
486
 
@@ -397,6 +490,11 @@ async function ensureBinaryExists() {
397
490
  term.clearLine()
398
491
  console.error('❌ Failed to download freebuff:', error.message)
399
492
  console.error('Please check your internet connection and try again')
493
+ if (!getProxyUrl()) {
494
+ console.error(
495
+ 'If you are behind a proxy, set the HTTPS_PROXY environment variable',
496
+ )
497
+ }
400
498
  process.exit(1)
401
499
  }
402
500
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "freebuff",
3
- "version": "0.0.21",
3
+ "version": "0.0.23",
4
4
  "description": "The world's strongest free coding agent",
5
5
  "license": "MIT",
6
6
  "bin": {