-
-
Notifications
You must be signed in to change notification settings - Fork 18
/
index.js
430 lines (387 loc) · 15 KB
/
index.js
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
/*! bittorrent-peerid. MIT License. WebTorrent LLC <https://webtorrent.io/opensource> */
import { decodeBitCometClient, decodeBitSpiritClient, getAzStyleVersionNumber, identifyAwkwardClient, isAzStyle, isMainlineStyle, isPossibleSpoofClient, isShadowStyle } from './lib/utils.js'
/**
* Parses and returns the client type and version of a bittorrent peer id.
* Throws an exception if the peer id is invalid.
*
* @param {Buffer|string} peerId (as Buffer or hex/utf8 string)
*/
export default (peerId) => {
let buffer
if (Buffer.isBuffer(peerId)) {
buffer = peerId
} else if (typeof peerId === 'string') {
buffer = Buffer.from(peerId, 'utf8')
// assume utf8 peerId, but if that's invalid, then try hex encoding
if (buffer.length !== 20) { buffer = Buffer.from(peerId, 'hex') }
} else {
throw new Error(`Invalid peerId must be Buffer or hex string: ${peerId}`)
}
if (buffer.length !== 20) {
throw new Error(`Invalid peerId length (hex buffer must be 20 bytes): ${peerId}`)
}
// overwrite original peerId string with guaranteed utf8 version
peerId = buffer.toString('utf8')
let client = null
// If the client reuses parts of the peer ID of other peers, then try to determine this
// first (before we misidentify the client).
if (isPossibleSpoofClient(peerId)) {
if ((client = decodeBitSpiritClient(peerId, buffer))) return client
if ((client = decodeBitCometClient(peerId, buffer))) return client
return { client: 'BitSpirit?' }
}
// See if the client uses Az style identification
if (isAzStyle(peerId)) {
if ((client = getAzStyleClientName(peerId))) {
const version = getAzStyleClientVersion(client, peerId)
// Hack for fake ZipTorrent clients - there seems to be some clients
// which use the same identifier, but they aren't valid ZipTorrent clients
if (client.startsWith('ZipTorrent') && peerId.startsWith('bLAde', 8)) {
return {
client: 'Unknown [Fake: ZipTorrent]',
version
}
}
// BitTorrent 6.0 Beta currently misidentifies itself
if (client === '\u00B5Torrent' && version === '6.0 Beta') {
return {
client: 'Mainline',
version: '6.0 Beta'
}
}
// If it's the rakshasa libtorrent, then it's probably rTorrent
if (client.startsWith('libTorrent (Rakshasa)')) {
return {
client: `${client} / rTorrent*`,
version
}
}
return {
client,
version
}
}
}
// See if the client uses Shadow style identification
if (isShadowStyle(peerId)) {
if ((client = getShadowStyleClientName(peerId))) {
// TODO: handle shadow style client version numbers
return { client }
}
}
// See if the client uses Mainline style identification
if (isMainlineStyle(peerId)) {
if ((client = getMainlineStyleClientName(peerId))) {
// TODO: handle mainline style client version numbers
return { client }
}
}
// Check for BitSpirit / BitComet disregarding spoof mode
if ((client = decodeBitSpiritClient(peerId, buffer))) return client
if ((client = decodeBitCometClient(peerId, buffer))) return client
// See if the client identifies itself using a particular substring
const data = getSimpleClient(peerId)
if (data) {
client = data.client
// TODO: handle simple client version numbers
return {
client,
version: data.version
}
}
// See if client is known to be awkward / nonstandard
if ((client = identifyAwkwardClient(peerId, buffer))) {
return client
}
// TODO: handle unknown az-formatted and shadow-formatted clients
return { client: 'unknown' }
}
// Az style two byte code identifiers to real client name
const azStyleClients = {}
const azStyleClientVersions = {}
// Shadow's style one byte code identifiers to real client name
const shadowStyleClients = {}
const shadowStyleClientVersions = {}
// Mainline's new style uses one byte code identifiers too
const mainlineStyleClients = {}
// Clients with completely custom naming schemes
const customStyleClients = []
const VER_AZ_THREE_DIGITS = v => // "1.2.3"
`${v[0]}.${v[1]}.${v[2]}`
const VER_AZ_DELUGE = v => {
const alphabet = 'ABCDE'
if (isNaN(v[2])) {
return `${v[0]}.${v[1]}.1${alphabet.indexOf(v[2])}`
}
return `${v[0]}.${v[1]}.${v[2]}`
}
const VER_AZ_THREE_DIGITS_PLUS_MNEMONIC = v => {
// "1.2.3 [4]"
let mnemonic = v[3]
if (mnemonic === 'B') {
mnemonic = 'Beta'
} else if (mnemonic === 'A') {
mnemonic = 'Alpha'
} else {
mnemonic = ''
}
return `${v[0]}.${v[1]}.${v[2]} ${mnemonic}`
}
const VER_AZ_FOUR_DIGITS = v => // "1.2.3.4"
`${v[0]}.${v[1]}.${v[2]}.${v[3]}`
const VER_AZ_TWO_MAJ_TWO_MIN = v => // "12.34"
`${v[0] + v[1]}.${v[2]}${v[3]}`
const VER_AZ_SKIP_FIRST_ONE_MAJ_TWO_MIN = v => // "2.34"
`${v[1]}.${v[2]}${v[3]}`
const VER_AZ_KTORRENT_STYLE = '1.2.3=[RD].4'
const VER_AZ_TRANSMISSION_STYLE = v => {
// "transmission"
if (v[0] === '0' && v[1] === '0' && v[2] === '0') {
return `0.${v[3]}`
} else if (v[0] === '0' && v[1] === '0') {
return `0.${v[2]}${v[3]}`
}
return `${v[0]}.${v[1]}${v[2]}${v[3] === 'Z' || v[3] === 'X' ? '+' : ''}`
}
const VER_AZ_WEBTORRENT_STYLE = v => {
// "webtorrent"
let version = ''
if (v[0] === '0') {
version += `${v[1]}.`
} else {
version += `${v[0]}${v[1]}.`
}
if (v[2] === '0') {
version += v[3]
} else {
version += `${v[2]}${v[3]}`
}
return version
}
const VER_AZ_THREE_ALPHANUMERIC_DIGITS = '2.33.4'
const VER_NONE = 'NO_VERSION'
function addAzStyle (id, client, version = VER_AZ_FOUR_DIGITS) {
azStyleClients[id] = client
azStyleClientVersions[client] = version
}
function addShadowStyle (id, client, version = VER_AZ_THREE_DIGITS) {
shadowStyleClients[id] = client
shadowStyleClientVersions[client] = version
}
function addMainlineStyle (id, client) {
mainlineStyleClients[id] = client
}
function addSimpleClient (client, version, id, position) {
if (typeof id === 'number' || typeof id === 'undefined') {
position = id
id = version
version = undefined
}
customStyleClients.push({
id,
client,
version,
position: position || 0
})
}
function getAzStyleClientName (peerId) {
return azStyleClients[peerId.substring(1, 3)]
}
function getShadowStyleClientName (peerId) {
return shadowStyleClients[peerId.substring(0, 1)]
}
function getMainlineStyleClientName (peerId) {
return mainlineStyleClients[peerId.substring(0, 1)]
}
function getSimpleClient (peerId) {
for (let i = 0; i < customStyleClients.length; ++i) {
const client = customStyleClients[i]
if (peerId.startsWith(client.id, client.position)) {
return client
}
}
return null
}
function getAzStyleClientVersion (client, peerId) {
const version = azStyleClientVersions[client]
if (!version) return null
return getAzStyleVersionNumber(peerId.substring(3, 7), version)
}
(() => {
// add known clients alphabetically
addAzStyle('A~', 'Ares', VER_AZ_THREE_DIGITS)
addAzStyle('AG', 'Ares', VER_AZ_THREE_DIGITS)
addAzStyle('AN', 'Ares', VER_AZ_FOUR_DIGITS)
addAzStyle('AR', 'Ares')// Ares is more likely than ArcticTorrent
addAzStyle('AV', 'Avicora')
addAzStyle('AX', 'BitPump', VER_AZ_TWO_MAJ_TWO_MIN)
addAzStyle('AT', 'Artemis')
addAzStyle('AZ', 'Vuze', VER_AZ_FOUR_DIGITS)
addAzStyle('BB', 'BitBuddy', '1.234')
addAzStyle('BC', 'BitComet', VER_AZ_SKIP_FIRST_ONE_MAJ_TWO_MIN)
addAzStyle('BE', 'BitTorrent SDK')
addAzStyle('BF', 'BitFlu', VER_NONE)
addAzStyle('BG', 'BTG', VER_AZ_FOUR_DIGITS)
addAzStyle('bk', 'BitKitten (libtorrent)')
addAzStyle('BR', 'BitRocket', '1.2(34)')
addAzStyle('BS', 'BTSlave')
addAzStyle('BT', 'BitTorrent', VER_AZ_THREE_DIGITS_PLUS_MNEMONIC)
addAzStyle('BW', 'BitWombat')
addAzStyle('BX', 'BittorrentX')
addAzStyle('CB', 'Shareaza Plus')
addAzStyle('CD', 'Enhanced CTorrent', VER_AZ_TWO_MAJ_TWO_MIN)
addAzStyle('CT', 'CTorrent', '1.2.34')
addAzStyle('DP', 'Propogate Data Client')
addAzStyle('DE', 'Deluge', VER_AZ_DELUGE)
addAzStyle('EB', 'EBit')
addAzStyle('ES', 'Electric Sheep', VER_AZ_THREE_DIGITS)
addAzStyle('FC', 'FileCroc')
addAzStyle('FG', 'FlashGet', VER_AZ_SKIP_FIRST_ONE_MAJ_TWO_MIN)
addAzStyle('FX', 'Freebox BitTorrent')
addAzStyle('FT', 'FoxTorrent/RedSwoosh')
addAzStyle('GR', 'GetRight', '1.2')
addAzStyle('GS', 'GSTorrent')// TODO: Format is v"abcd"
addAzStyle('HL', 'Halite', VER_AZ_THREE_DIGITS)
addAzStyle('HN', 'Hydranode')
addAzStyle('KG', 'KGet')
addAzStyle('KT', 'KTorrent', VER_AZ_KTORRENT_STYLE)
addAzStyle('LC', 'LeechCraft')
addAzStyle('LH', 'LH-ABC')
addAzStyle('LK', 'linkage', VER_AZ_THREE_DIGITS)
addAzStyle('LP', 'Lphant', VER_AZ_TWO_MAJ_TWO_MIN)
addAzStyle('LT', 'libtorrent (Rasterbar)', VER_AZ_THREE_ALPHANUMERIC_DIGITS)
addAzStyle('lt', 'libTorrent (Rakshasa)', VER_AZ_THREE_ALPHANUMERIC_DIGITS)
addAzStyle('LW', 'LimeWire', VER_NONE)// The "0001" bytes found after the LW commonly refers to the version of the BT protocol implemented. Documented here: http://www.limewire.org/wiki/index.php?title=BitTorrentRevision
addAzStyle('MO', 'MonoTorrent')
addAzStyle('MP', 'MooPolice', VER_AZ_THREE_DIGITS)
addAzStyle('MR', 'Miro')
addAzStyle('MT', 'MoonlightTorrent')
addAzStyle('NE', 'BT Next Evolution', VER_AZ_THREE_DIGITS)
addAzStyle('NX', 'Net Transport')
addAzStyle('OS', 'OneSwarm', VER_AZ_FOUR_DIGITS)
addAzStyle('OT', 'OmegaTorrent')
addAzStyle('PC', 'CacheLogic', '12.3-4')
addAzStyle('PT', 'Popcorn Time')
addAzStyle('PD', 'Pando')
addAzStyle('PE', 'PeerProject')
addAzStyle('pX', 'pHoeniX')
addAzStyle('qB', 'qBittorrent', VER_AZ_DELUGE)
addAzStyle('QD', 'qqdownload')
addAzStyle('RM', 'RUM Torrent')
addAzStyle('RT', 'Retriever')
addAzStyle('RZ', 'RezTorrent')
addAzStyle('S~', 'Shareaza alpha/beta')
addAzStyle('SB', 'SwiftBit')
addAzStyle('SD', '\u8FC5\u96F7\u5728\u7EBF (Xunlei)')// Apparently, the English name of the client is "Thunderbolt".
addAzStyle('SG', 'GS Torrent', VER_AZ_FOUR_DIGITS)
addAzStyle('SN', 'ShareNET')
addAzStyle('SP', 'BitSpirit', VER_AZ_THREE_DIGITS)// >= 3.6
addAzStyle('SS', 'SwarmScope')
addAzStyle('ST', 'SymTorrent', '2.34')
addAzStyle('st', 'SharkTorrent')
addAzStyle('SZ', 'Shareaza')
addAzStyle('TG', 'Torrent GO')
addAzStyle('TN', 'Torrent.NET')
addAzStyle('TR', 'Transmission', VER_AZ_TRANSMISSION_STYLE)
addAzStyle('TS', 'TorrentStorm')
addAzStyle('TT', 'TuoTu', VER_AZ_THREE_DIGITS)
addAzStyle('UL', 'uLeecher!')
addAzStyle('UE', '\u00B5Torrent Embedded', VER_AZ_THREE_DIGITS_PLUS_MNEMONIC)
addAzStyle('UT', '\u00B5Torrent', VER_AZ_THREE_DIGITS_PLUS_MNEMONIC)
addAzStyle('UM', '\u00B5Torrent Mac', VER_AZ_THREE_DIGITS_PLUS_MNEMONIC)
addAzStyle('UW', '\u00B5Torrent Web', VER_AZ_THREE_DIGITS_PLUS_MNEMONIC)
addAzStyle('WD', 'WebTorrent Desktop', VER_AZ_WEBTORRENT_STYLE)// Go Webtorrent!! :)
addAzStyle('WT', 'Bitlet')
addAzStyle('WW', 'WebTorrent', VER_AZ_WEBTORRENT_STYLE)// Go Webtorrent!! :)
addAzStyle('WY', 'FireTorrent')// formerly Wyzo.
addAzStyle('VG', '\u54c7\u560E (Vagaa)', VER_AZ_FOUR_DIGITS)
addAzStyle('XL', '\u8FC5\u96F7\u5728\u7EBF (Xunlei)')// Apparently, the English name of the client is "Thunderbolt".
addAzStyle('XT', 'XanTorrent')
addAzStyle('XF', 'Xfplay', VER_AZ_TRANSMISSION_STYLE)
addAzStyle('XX', 'XTorrent', '1.2.34')
addAzStyle('XC', 'XTorrent', '1.2.34')
addAzStyle('ZT', 'ZipTorrent')
addAzStyle('7T', 'aTorrent')
addAzStyle('ZO', 'Zona', VER_AZ_FOUR_DIGITS)
addAzStyle('#@', 'Invalid PeerID')
addShadowStyle('A', 'ABC')
addShadowStyle('O', 'Osprey Permaseed')
addShadowStyle('Q', 'BTQueue')
addShadowStyle('R', 'Tribler')
addShadowStyle('S', 'Shad0w')
addShadowStyle('T', 'BitTornado')
addShadowStyle('U', 'UPnP NAT')
addMainlineStyle('M', 'Mainline')
addMainlineStyle('Q', 'Queen Bee')
// Simple clients with no version number.
addSimpleClient('\u00B5Torrent', '1.7.0 RC', '-UT170-')// http://forum.utorrent.com/viewtopic.php?pid=260927#p260927
addSimpleClient('Azureus', '1', 'Azureus')
addSimpleClient('Azureus', '2.0.3.2', 'Azureus', 5)
addSimpleClient('Aria', '2', '-aria2-')
addSimpleClient('BitTorrent Plus!', 'II', 'PRC.P---')
addSimpleClient('BitTorrent Plus!', 'P87.P---')
addSimpleClient('BitTorrent Plus!', 'S587Plus')
addSimpleClient('BitTyrant (Azureus Mod)', 'AZ2500BT')
addSimpleClient('Blizzard Downloader', 'BLZ')
addSimpleClient('BTGetit', 'BG', 10)
addSimpleClient('BTugaXP', 'btuga')
addSimpleClient('BTugaXP', 'BTuga', 5)
addSimpleClient('BTugaXP', 'oernu')
addSimpleClient('Deadman Walking', 'BTDWV-')
addSimpleClient('Deadman', 'Deadman Walking-')
addSimpleClient('External Webseed', 'Ext')
addSimpleClient('G3 Torrent', '-G3')
addSimpleClient('GreedBT', '2.7.1', '271-')
addSimpleClient('Hurricane Electric', 'arclight')
addSimpleClient('HTTP Seed', '-WS')
addSimpleClient('JVtorrent', '10-------')
addSimpleClient('Limewire', 'LIME')
addSimpleClient('Martini Man', 'martini')
addSimpleClient('Pando', 'Pando')
addSimpleClient('PeerApp', 'PEERAPP')
addSimpleClient('SimpleBT', 'btfans', 4)
addSimpleClient('Swarmy', 'a00---0')
addSimpleClient('Swarmy', 'a02---0')
addSimpleClient('Teeweety', 'T00---0')
addSimpleClient('TorrentTopia', '346-')
addSimpleClient('XanTorrent', 'DansClient')
addSimpleClient('MediaGet', '-MG1')
addSimpleClient('MediaGet', '2.1', '-MG21')
/**
* This is interesting - it uses Mainline style, except uses two characters instead of one.
* And then - the particular numbering style it uses would actually break the way we decode
* version numbers (our code is too hardcoded to "-x-y-z--" style version numbers).
*
* This should really be declared as a Mainline style peer ID, but I would have to
* make my code more generic. Not a bad thing - just something I'm not doing right
* now.
*/
addSimpleClient('Amazon AWS S3', 'S3-')
// Simple clients with custom version schemes
// TODO: support custom version schemes
addSimpleClient('BitTorrent DNA', 'DNA')
addSimpleClient('Opera', 'OP')// Pre build 10000 versions
addSimpleClient('Opera', 'O')// Post build 10000 versions
addSimpleClient('Burst!', 'Mbrst')
addSimpleClient('TurboBT', 'turbobt')
addSimpleClient('BT Protocol Daemon', 'btpd')
addSimpleClient('Plus!', 'Plus')
addSimpleClient('XBT', 'XBT')
addSimpleClient('BitsOnWheels', '-BOW')
addSimpleClient('eXeem', 'eX')
addSimpleClient('MLdonkey', '-ML')
addSimpleClient('Bitlet', 'BitLet')
addSimpleClient('AllPeers', 'AP')
addSimpleClient('BTuga Revolution', 'BTM')
addSimpleClient('Rufus', 'RS', 2)
addSimpleClient('BitMagnet', 'BM', 2)// BitMagnet - predecessor to Rufus
addSimpleClient('QVOD', 'QVOD')
// Top-BT is based on BitTornado, but doesn't quite stick to Shadow's naming conventions,
// so we'll use substring matching instead.
addSimpleClient('Top-BT', 'TB')
addSimpleClient('Tixati', 'TIX')
// seems to have a sub-version encoded in following 3 bytes, not worked out how: "folx/1.0.456.591" : 2D 464C 3130 FF862D 486263574A43585F66314D5A
addSimpleClient('folx', '-FL')
addSimpleClient('\u00B5Torrent Mac', '-UM')
addSimpleClient('\u00B5Torrent', '-UT') // UT 3.4+
})()