Skip to content

Commit 3763e68

Browse files
authored
Merge branch 'webtorrent:master' into master
2 parents 78147ad + f6a7993 commit 3763e68

File tree

11 files changed

+297
-246
lines changed

11 files changed

+297
-246
lines changed

AUTHORS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,8 @@
6363
- Paul Sharypov ([email protected])
6464
6565
- Tom Snelling ([email protected])
66+
67+
- Arsène Fougerouse ([email protected])
68+
- Brad Marsden ([email protected])
6669

6770
#### Generated by tools/update-authors.sh.

CHANGELOG.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,39 @@
1+
## [11.0.2](https://github.com/webtorrent/bittorrent-tracker/compare/v11.0.1...v11.0.2) (2024-03-12)
2+
3+
4+
### Bug Fixes
5+
6+
* **parse-http:** ignore announcements from peers with invalid announcement ports. ([#513](https://github.com/webtorrent/bittorrent-tracker/issues/513)) ([fe75272](https://github.com/webtorrent/bittorrent-tracker/commit/fe75272d51653e626583689081afb0b7aeadb84f))
7+
8+
## [11.0.1](https://github.com/webtorrent/bittorrent-tracker/compare/v11.0.0...v11.0.1) (2024-01-16)
9+
10+
11+
### Bug Fixes
12+
13+
* update build badge url ([#506](https://github.com/webtorrent/bittorrent-tracker/issues/506)) ([3f59b58](https://github.com/webtorrent/bittorrent-tracker/commit/3f59b58a020ea8c0926be135471a6666fe8e8b21))
14+
15+
# [11.0.0](https://github.com/webtorrent/bittorrent-tracker/compare/v10.0.12...v11.0.0) (2023-10-31)
16+
17+
18+
### Features
19+
20+
* **major:** drop simple-get ([#443](https://github.com/webtorrent/bittorrent-tracker/issues/443)) ([bce64e1](https://github.com/webtorrent/bittorrent-tracker/commit/bce64e155df6ff9fa605898cbf7498bf76188d8b))
21+
22+
23+
### BREAKING CHANGES
24+
25+
* **major:** drop simple-get
26+
27+
* perf: drop simple-get
28+
29+
* feat: undici agent and socks
30+
31+
* fix: undici as dev dependency
32+
33+
* feat: require user passed proxy objects for http and ws
34+
35+
* chore: include undici for tests
36+
137
## [10.0.12](https://github.com/webtorrent/bittorrent-tracker/compare/v10.0.11...v10.0.12) (2023-08-09)
238

339

README.md

Lines changed: 20 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# bittorrent-tracker [![ci][ci-image]][ci-url] [![npm][npm-image]][npm-url] [![downloads][downloads-image]][downloads-url] [![javascript style guide][standard-image]][standard-url]
22

3-
[ci-image]: https://img.shields.io/github/workflow/status/webtorrent/bittorrent-tracker/ci/master
3+
[ci-image]: https://img.shields.io/github/actions/workflow/status/webtorrent/bittorrent-tracker/ci.yml
44
[ci-url]: https://github.com/webtorrent/bittorrent-tracker/actions
55
[npm-image]: https://img.shields.io/npm/v/bittorrent-tracker.svg
66
[npm-url]: https://npmjs.org/package/bittorrent-tracker
@@ -57,16 +57,16 @@ npm install https://github.com/babico/bittorrent-tracker.git --save
5757
To connect to a tracker, just do this:
5858

5959
```js
60-
var Client = require('bittorrent-tracker')
60+
import Client from 'bittorrent-tracker'
6161

62-
var requiredOpts = {
62+
const requiredOpts = {
6363
infoHash: new Buffer('012345678901234567890'), // hex string or Buffer
6464
peerId: new Buffer('01234567890123456789'), // hex string or Buffer
6565
announce: [], // list of tracker server urls
6666
port: 6881 // torrent client port, (in browser, optional)
6767
}
6868

69-
var optionalOpts = {
69+
const optionalOpts = {
7070
// RTCPeerConnection config object (only used in browser)
7171
rtcConfig: {},
7272
// User-Agent header for http requests
@@ -83,47 +83,24 @@ var optionalOpts = {
8383
customParam: 'blah' // custom parameters supported
8484
}
8585
},
86-
// Proxy config object
86+
// Proxy options (used to proxy requests in node)
8787
proxyOpts: {
88-
// Socks proxy options (used to proxy requests in node)
89-
socksProxy: {
90-
// Configuration from socks module (https://github.com/JoshGlazebrook/socks)
91-
proxy: {
92-
// IP Address of Proxy (Required)
93-
ipaddress: "1.2.3.4",
94-
// TCP Port of Proxy (Required)
95-
port: 1080,
96-
// Proxy Type [4, 5] (Required)
97-
// Note: 4 works for both 4 and 4a.
98-
// Type 4 does not support UDP association relay
99-
type: 5,
100-
101-
// SOCKS 4 Specific:
102-
103-
// UserId used when making a SOCKS 4/4a request. (Optional)
104-
userid: "someuserid",
105-
106-
// SOCKS 5 Specific:
107-
108-
// Authentication used for SOCKS 5 (when it's required) (Optional)
109-
authentication: {
110-
username: "Josh",
111-
password: "somepassword"
112-
}
113-
},
114-
115-
// Amount of time to wait for a connection to be established. (Optional)
116-
// - defaults to 10000ms (10 seconds)
117-
timeout: 10000
118-
},
119-
// NodeJS HTTP agents (used to proxy HTTP and Websocket requests in node)
120-
// Populated with Socks.Agent if socksProxy is provided
121-
httpAgent: {},
122-
httpsAgent: {}
88+
// For WSS trackers this is always a http.Agent
89+
// For UDP trackers this is an object of options for the Socks Connection
90+
// For HTTP trackers this is either an undici Agent if using Node16 or later, or http.Agent if using versions prior to Node 16, ex:
91+
// import Socks from 'socks'
92+
// proxyOpts.socksProxy = new Socks.Agent(optionsObject, isHttps)
93+
// or if using Node 16 or later
94+
// import { socksDispatcher } from 'fetch-socks'
95+
// proxyOpts.socksProxy = socksDispatcher(optionsObject)
96+
socksProxy: new SocksProxy(socksOptionsObject),
97+
// Populated with socksProxy if it's provided
98+
httpAgent: new http.Agent(agentOptionsObject),
99+
httpsAgent: new https.Agent(agentOptionsObject)
123100
},
124101
}
125102

126-
var client = new Client(requiredOpts)
103+
const client = new Client(requiredOpts)
127104

128105
client.on('error', function (err) {
129106
// fatal client error!
@@ -184,7 +161,7 @@ client.on('scrape', function (data) {
184161
To start a BitTorrent tracker server to track swarms of peers:
185162

186163
```js
187-
const Server = require('bittorrent-tracker').Server
164+
import { Server } from 'bittorrent-tracker'
188165

189166
const server = new Server({
190167
udp: true, // enable udp server? [default=true]
@@ -291,7 +268,7 @@ The http server will handle requests for the following paths: `/announce`, `/scr
291268
Scraping multiple torrent info is possible with a static `Client.scrape` method:
292269

293270
```js
294-
var Client = require('bittorrent-tracker')
271+
import Client from 'bittorrent-tracker'
295272
Client.scrape({ announce: announceUrl, infoHash: [ infoHash1, infoHash2 ]}, function (err, results) {
296273
results[infoHash1].announce
297274
results[infoHash1].infoHash

bin/cmd.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -86,22 +86,22 @@ const server = new Server({
8686
})
8787

8888
server.on('error', err => {
89-
if (!argv.silent) console.error(`ERROR: ${err.message}`)
89+
if (!argv.silent) console.error(`${new Date().toISOString()} ERROR: ${err.message}`)
9090
})
9191
server.on('warning', err => {
92-
if (!argv.quiet) console.log(`WARNING: ${err.message}`)
92+
if (!argv.quiet) console.log(`${new Date().toISOString()} WARNING: ${err.message}`)
9393
})
9494
server.on('update', addr => {
95-
if (!argv.quiet) console.log(`update: ${addr}`)
95+
if (!argv.quiet) console.log(`${new Date().toISOString()} update: ${addr}`)
9696
})
9797
server.on('complete', addr => {
98-
if (!argv.quiet) console.log(`complete: ${addr}`)
98+
if (!argv.quiet) console.log(`${new Date().toISOString()} complete: ${addr}`)
9999
})
100100
server.on('start', addr => {
101-
if (!argv.quiet) console.log(`start: ${addr}`)
101+
if (!argv.quiet) console.log(`${new Date().toISOString()} start: ${addr}`)
102102
})
103103
server.on('stop', addr => {
104-
if (!argv.quiet) console.log(`stop: ${addr}`)
104+
if (!argv.quiet) console.log(`${new Date().toISOString()} stop: ${addr}`)
105105
})
106106

107107
const hostname = {
@@ -115,30 +115,30 @@ server.listen(argv.port, hostname, () => {
115115
const httpAddr = server.http.address()
116116
const httpHost = httpAddr.address !== '::' ? httpAddr.address : 'localhost'
117117
const httpPort = httpAddr.port
118-
console.log(`HTTP tracker: http://${httpHost}:${httpPort}/announce`)
118+
console.log(`${new Date().toISOString()} HTTP tracker: http://${httpHost}:${httpPort}/announce`)
119119
}
120120
if (server.udp && !argv.quiet) {
121121
const udpAddr = server.udp.address()
122122
const udpHost = udpAddr.address
123123
const udpPort = udpAddr.port
124-
console.log(`UDP tracker: udp://${udpHost}:${udpPort}`)
124+
console.log(`${new Date().toISOString()} UDP tracker: udp://${udpHost}:${udpPort}`)
125125
}
126126
if (server.udp6 && !argv.quiet) {
127127
const udp6Addr = server.udp6.address()
128128
const udp6Host = udp6Addr.address !== '::' ? udp6Addr.address : 'localhost'
129129
const udp6Port = udp6Addr.port
130-
console.log(`UDP6 tracker: udp://${udp6Host}:${udp6Port}`)
130+
console.log(`${new Date().toISOString()} UDP6 tracker: udp://${udp6Host}:${udp6Port}`)
131131
}
132132
if (server.ws && !argv.quiet) {
133133
const wsAddr = server.http.address()
134134
const wsHost = wsAddr.address !== '::' ? wsAddr.address : 'localhost'
135135
const wsPort = wsAddr.port
136-
console.log(`WebSocket tracker: ws://${wsHost}:${wsPort}`)
136+
console.log(`${new Date().toISOString()} WebSocket tracker: ws://${wsHost}:${wsPort}`)
137137
}
138138
if (server.http && argv.stats && !argv.quiet) {
139139
const statsAddr = server.http.address()
140140
const statsHost = statsAddr.address !== '::' ? statsAddr.address : 'localhost'
141141
const statsPort = statsAddr.port
142-
console.log(`Tracker stats: http://${statsHost}:${statsPort}/stats`)
142+
console.log(`${new Date().toISOString()} Tracker stats: http://${statsHost}:${statsPort}/stats`)
143143
}
144144
})

lib/client/http-tracker.js

Lines changed: 58 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import arrayRemove from 'unordered-array-remove'
22
import bencode from 'bencode'
3-
import clone from 'clone'
43
import Debug from 'debug'
5-
import get from 'simple-get'
6-
import Socks from 'socks'
4+
import fetch from 'cross-fetch-ponyfill'
75
import { bin2hex, hex2bin, arr2text, text2arr, arr2hex } from 'uint8-util'
86

97
import common from '../common.js'
@@ -13,6 +11,14 @@ import compact2string from 'compact2string'
1311
const debug = Debug('bittorrent-tracker:http-tracker')
1412
const HTTP_SCRAPE_SUPPORT = /\/(announce)[^/]*$/
1513

14+
function abortTimeout (ms) {
15+
const controller = new AbortController()
16+
setTimeout(() => {
17+
controller.abort()
18+
}, ms).unref?.()
19+
return controller
20+
}
21+
1622
/**
1723
* HTTP torrent tracker client (for an individual tracker)
1824
*
@@ -112,70 +118,72 @@ class HTTPTracker extends Tracker {
112118
}
113119
}
114120

115-
_request (requestUrl, params, cb) {
116-
const self = this
121+
async _request (requestUrl, params, cb) {
117122
const parsedUrl = new URL(requestUrl + (requestUrl.indexOf('?') === -1 ? '?' : '&') + common.querystringStringify(params))
118123
let agent
119124
if (this.client._proxyOpts) {
120125
agent = parsedUrl.protocol === 'https:' ? this.client._proxyOpts.httpsAgent : this.client._proxyOpts.httpAgent
121126
if (!agent && this.client._proxyOpts.socksProxy) {
122-
agent = new Socks.Agent(clone(this.client._proxyOpts.socksProxy), (parsedUrl.protocol === 'https:'))
127+
agent = this.client._proxyOpts.socksProxy
123128
}
124129
}
125130

126-
this.cleanupFns.push(cleanup)
127-
128-
let request = get.concat({
129-
url: parsedUrl.toString(),
130-
agent,
131-
timeout: common.REQUEST_TIMEOUT,
132-
headers: {
133-
'user-agent': this.client._userAgent || ''
134-
}
135-
}, onResponse)
136-
137-
function cleanup () {
138-
if (request) {
139-
arrayRemove(self.cleanupFns, self.cleanupFns.indexOf(cleanup))
140-
request.abort()
141-
request = null
131+
const cleanup = () => {
132+
if (!controller.signal.aborted) {
133+
arrayRemove(this.cleanupFns, this.cleanupFns.indexOf(cleanup))
134+
controller.abort()
135+
controller = null
142136
}
143-
if (self.maybeDestroyCleanup) self.maybeDestroyCleanup()
137+
if (this.maybeDestroyCleanup) this.maybeDestroyCleanup()
144138
}
145139

146-
function onResponse (err, res, data) {
147-
cleanup()
148-
if (self.destroyed) return
140+
this.cleanupFns.push(cleanup)
149141

142+
let res
143+
let controller = abortTimeout(common.REQUEST_TIMEOUT)
144+
try {
145+
res = await fetch(parsedUrl.toString(), {
146+
agent,
147+
signal: controller.signal,
148+
dispatcher: agent,
149+
headers: {
150+
'user-agent': this.client._userAgent || ''
151+
}
152+
})
153+
} catch (err) {
150154
if (err) return cb(err)
151-
if (res.statusCode !== 200) {
152-
return cb(new Error(`Non-200 response code ${res.statusCode} from ${self.announceUrl}`))
153-
}
154-
if (!data || data.length === 0) {
155-
return cb(new Error(`Invalid tracker response from${self.announceUrl}`))
156-
}
157-
158-
try {
159-
data = bencode.decode(data)
160-
} catch (err) {
161-
return cb(new Error(`Error decoding tracker response: ${err.message}`))
162-
}
163-
const failure = data['failure reason'] && arr2text(data['failure reason'])
164-
if (failure) {
165-
debug(`failure from ${requestUrl} (${failure})`)
166-
return cb(new Error(failure))
167-
}
155+
}
156+
let data = new Uint8Array(await res.arrayBuffer())
157+
cleanup()
158+
if (this.destroyed) return
168159

169-
const warning = data['warning message'] && arr2text(data['warning message'])
170-
if (warning) {
171-
debug(`warning from ${requestUrl} (${warning})`)
172-
self.client.emit('warning', new Error(warning))
173-
}
160+
if (res.status !== 200) {
161+
return cb(new Error(`Non-200 response code ${res.statusCode} from ${this.announceUrl}`))
162+
}
163+
if (!data || data.length === 0) {
164+
return cb(new Error(`Invalid tracker response from${this.announceUrl}`))
165+
}
174166

175-
debug(`response from ${requestUrl}`)
167+
try {
168+
data = bencode.decode(data)
169+
} catch (err) {
170+
return cb(new Error(`Error decoding tracker response: ${err.message}`))
171+
}
172+
const failure = data['failure reason'] && arr2text(data['failure reason'])
173+
if (failure) {
174+
debug(`failure from ${requestUrl} (${failure})`)
175+
return cb(new Error(failure))
176+
}
176177

177-
cb(null, data)
178+
const warning = data['warning message'] && arr2text(data['warning message'])
179+
if (warning) {
180+
debug(`warning from ${requestUrl} (${warning})`)
181+
this.client.emit('warning', new Error(warning))
178182
}
183+
184+
debug(`response from ${requestUrl}`)
185+
186+
cb(null, data)
179187
}
180188

181189
_onAnnounceResponse (data) {

lib/client/websocket-tracker.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
import clone from 'clone'
21
import Debug from 'debug'
32
import Peer from '@thaunknown/simple-peer/lite.js'
43
import Socket from '@thaunknown/simple-websocket'
5-
import Socks from 'socks'
64
import { arr2text, arr2hex, hex2bin, bin2hex, randomBytes } from 'uint8-util'
75

86
import common from '../common.js'
@@ -185,7 +183,7 @@ class WebSocketTracker extends Tracker {
185183
if (this.client._proxyOpts) {
186184
agent = parsedUrl.protocol === 'wss:' ? this.client._proxyOpts.httpsAgent : this.client._proxyOpts.httpAgent
187185
if (!agent && this.client._proxyOpts.socksProxy) {
188-
agent = new Socks.Agent(clone(this.client._proxyOpts.socksProxy), (parsedUrl.protocol === 'wss:'))
186+
agent = this.client._proxyOpts.socksProxy
189187
}
190188
}
191189
this.socket = socketPool[this.announceUrl] = new Socket({ url: this.announceUrl, agent })

lib/server/parse-http.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export default function (req, opts) {
2222
params.peer_id = bin2hex(params.peer_id)
2323

2424
params.port = Number(params.port)
25-
if (!params.port) throw new Error('invalid port')
25+
if (!params.port || params.port <= 0 || params.port > 65535) throw new Error('invalid port')
2626

2727
params.left = Number(params.left)
2828
if (Number.isNaN(params.left)) params.left = Infinity

0 commit comments

Comments
 (0)