bittorrent-relay
Advanced tools
Comparing version 12.0.5 to 12.0.6
@@ -19,3 +19,4 @@ #!/usr/bin/env node | ||
'version', | ||
'ev' | ||
'ev', | ||
'status' | ||
], | ||
@@ -30,3 +31,4 @@ string: [ | ||
'pub', | ||
'priv' | ||
'priv', | ||
'server' | ||
], | ||
@@ -47,3 +49,5 @@ default: { | ||
'limit': {}, | ||
'ev': false | ||
'ev': false, | ||
'status': true, | ||
'server': '0.0.0.0' | ||
} | ||
@@ -50,0 +54,0 @@ }) |
{ | ||
"name": "bittorrent-relay", | ||
"description": "Uses the mainline dht to relay requests to other trackers in a swarm", | ||
"version": "12.0.5", | ||
"version": "12.0.6", | ||
"bin": { | ||
@@ -6,0 +6,0 @@ "bittorrent-relay": "./bin/cmd.js" |
262
server.js
@@ -87,8 +87,12 @@ import Debug from 'debug' | ||
this.timer.active = this.timer.active || 5 * 60 * 1000 | ||
this.host = opts.host || '0.0.0.0' | ||
this.server = opts.server || '0.0.0.0' | ||
if(!opts.host){ | ||
throw new Error('must have host') | ||
} | ||
this.host = opts.host | ||
this.port = opts.port || 10509 | ||
this.address = `${this.host}:${this.port}` | ||
this._trustProxy = Boolean(opts.trustProxy) | ||
this.web = `${this.domain}:${this.port}` | ||
this.hash = crypto.createHash('sha1').update(this.web).digest('hex') | ||
this.web = `${this.domain || this.host}:${this.port}` | ||
this.id = crypto.createHash('sha1').update(this.address).digest('hex') | ||
this.sockets = new Map() | ||
@@ -161,3 +165,3 @@ this.triedAlready = new Map() | ||
// if(socket.readyState === 1){ | ||
// socket.send(JSON.stringify({action: 'web', domain: self.domain, host: self.host, port: self.port, web: self.web, hash: self.hash})) | ||
// socket.send(JSON.stringify({action: 'web', domain: self.domain, host: self.host, port: self.port, web: self.web, id: self.id})) | ||
// } | ||
@@ -187,8 +191,18 @@ // } | ||
for(const test in this.sockets.values()){ | ||
if(!test.relays.length){ | ||
if(!test.active){ | ||
test.terminate() | ||
continue | ||
} else { | ||
test.close() | ||
continue | ||
} | ||
} | ||
if(!test.active){ | ||
test.terminate() | ||
continue | ||
} else { | ||
test.active = false | ||
test.send(JSON.stringify({action: 'ping'})) | ||
} | ||
test.active = false | ||
test.send(JSON.stringify({action: 'ping'})) | ||
} | ||
@@ -257,33 +271,7 @@ }, this.timer.inactive) | ||
try { | ||
if(req.url.startsWith('/announce/')){ | ||
const useInfoHash = req.url.slice(0, req.url.indexOf('?')).replace('/announce/', '') | ||
if(!this.hashes.has(useInfoHash)){ | ||
return res.end(bencode.encode({'failure reason': 'infohash is not supported'})) | ||
} | ||
// const useQueryString = req.url.replace('/announce/', '').slice(0, req.url.indexOf('?')) | ||
// if(!this.hashes.has(useQueryString)){} | ||
return this.onHttpRequest(req, res) | ||
} else if(req.url.startsWith('/relay/')){ | ||
const useRelayHash = req.url.slice(0, req.url.indexOf('?')).replace('/relay/', '') | ||
const para = new URLSearchParams(req.url.slice(req.url.indexOf('?'))) | ||
if(!this.relays.has(useRelayHash)){ | ||
return res.end(bencode.encode({'failure reason': 'relayhash is not supported'})) | ||
} | ||
let size | ||
if(para.has('size')){ | ||
if(JSON.parse(para.get('size'))){ | ||
size = this.limit.serverConnections | ||
} | ||
} | ||
let keys | ||
if(para.has('keys')){ | ||
if(JSON.parse(para.get('keys'))){ | ||
keys = this.relays.get(useRelayHash).map((data) => {return data.key}) | ||
} | ||
} | ||
// const rh = req.url.replace('/relay/', '').replace(para, '') | ||
// const useQueryString = req.url.replace('/relay/', '').slice(0, req.url.indexOf('?')) | ||
// if(!this.relays.has(useQueryString)){} | ||
res.setHeader('Content-Type', 'text/plain; charset=UTF-8') | ||
return res.end(bencode.encode({size, keys})) | ||
if(req.url.startsWith('/announce?')){ | ||
this.onHttpRequest(req, res) | ||
} else if(req.url.startsWith('/relay?')){ | ||
const useParams = new URLSearchParams(req.url.slice(req.url.indexOf('?'))) | ||
this.onHttpRelay(req, res, useParams) | ||
} else if(req.method === 'HEAD' && req.url === '/'){ | ||
@@ -395,8 +383,8 @@ res.statusCode = 200 | ||
res.end(JSON.stringify(Array.from(this.hashes))) | ||
} else if(req.method === 'GET' && req.url === '/hash.html'){ | ||
} else if(req.method === 'GET' && req.url === '/id.html'){ | ||
res.setHeader('Content-Type', 'text/html') | ||
res.end(`<html><head><title>Relay</title></head><body>${(() => {const arr = [];this.sockets.forEach((data) => {arr.push(data.hash)});return arr;})().join('\n')}</body></html>`) | ||
} else if(req.method === 'GET' && req.url === '/hash.json'){ | ||
res.end(`<html><head><title>Relay</title></head><body>${(() => {const arr = [];this.sockets.forEach((data) => {arr.push(data.id)});return arr;})().join('\n')}</body></html>`) | ||
} else if(req.method === 'GET' && req.url === '/id.json'){ | ||
res.setHeader('Content-Type', 'application/json') | ||
res.end(JSON.stringify((() => {const arr = [];this.sockets.forEach((data) => {arr.push(data.hash)});return arr;})())) | ||
res.end(JSON.stringify((() => {const arr = [];this.sockets.forEach((data) => {arr.push(data.id)});return arr;})())) | ||
} else if(req.method === 'GET' && req.url === '/key.html'){ | ||
@@ -633,39 +621,42 @@ res.setHeader('Content-Type', 'text/html') | ||
// else handle websockets as usual | ||
if(req.url.startsWith('/announce/')){ | ||
const useTest = req.url.replace('/announce/', '') | ||
// const useTest = crypto.createHash('sha1').update(req.url.slice(req.url.lastIndexOf('/')).slice(1)).digest('hex') | ||
if(!this.hashes.has(useTest)){ | ||
socket.send(JSON.stringify({action: 'failure reason', error: 'infohash is not supported'})) | ||
if(req.url === '/announce'){ | ||
socket.upgradeReq = req | ||
self.onWebSocketConnection(socket) | ||
} else if(req.url.startsWith('/relay?')){ | ||
const params = new URLSearchParams(req.url.slice(req.url.indexOf('?'))) | ||
const getRelayHash = params.has('relay_hash') ? params.get('relay_hash') : null | ||
const checkRelayHash = getRelayHash && typeof(getRelayHash) === 'string' || getRelayHash.length === 20 | ||
const getId = params.has('id') ? params.get('id') : null | ||
const checkId = getId && typeof(getId) === 'string' && getId.length === 20 | ||
const checkHasSocket = getId ? this.sockets.has(getId) : null | ||
const checkHasRelay = getRelayHash ? this.relays.has(getRelayHash) : null | ||
if(!checkRelayHash || !checkId || checkHasSocket || !checkHasRelay){ | ||
socket.send(JSON.stringify({action: 'failure reason', error: 'there was a error, check the other properties of this object', relay_hash: checkRelayHash, id: checkId, socket: checkHasSocket, relay: checkHasRelay})) | ||
socket.close() | ||
return | ||
} | ||
socket.upgradeReq = req | ||
self.onWebSocketConnection(socket) | ||
} else if(req.url.startsWith('/relay/')){ | ||
// have id and relay in the url routes | ||
// have different functions to handle connections and extras | ||
const useTest = req.url.replace('/relay/', '') | ||
// const useTest = crypto.createHash('sha1').update(req.url.slice(req.url.lastIndexOf('/')).slice(1)).digest('hex') | ||
if(!this.relays.has(useTest)){ | ||
socket.send(JSON.stringify({action: 'failure reason', error: 'relay is not supported'})) | ||
socket.close() | ||
return | ||
} | ||
if(this.limit.serverConnections){ | ||
if(this.relays.get(useTest).length < this.limit.serverConnections){ | ||
socket.hash = null | ||
if(this.relays.get(getRelayHash).length < this.limit.serverConnections){ | ||
socket.id = getId | ||
socket.server = true | ||
socket.active = true | ||
socket.relay = getRelayHash | ||
socket.relays = [] | ||
socket.proc = false | ||
// socket.relay = useTest | ||
this.sockets.set(socket.id, socket) | ||
this.onRelaySocketConnection(socket) | ||
} | ||
} else { | ||
socket.hash = null | ||
socket.id = getId | ||
socket.server = true | ||
socket.relay = getRelayHash | ||
socket.relays = [] | ||
socket.active = true | ||
socket.proc = false | ||
// socket.relay = useTest | ||
this.sockets.set(socket.id, socket) | ||
this.onRelaySocketConnection(socket) | ||
@@ -710,9 +701,9 @@ } | ||
const hash = crypto.createHash('sha1').update(peer.host + ':' + peer.port).digest('hex') | ||
if(self.hash === hash){ | ||
const id = crypto.createHash('sha1').update(peer.host + ':' + peer.port).digest('hex') | ||
if(self.id === id){ | ||
return | ||
} | ||
if(this.triedAlready.has(hash)){ | ||
const check = this.triedAlready.get(hash) | ||
if(this.triedAlready.has(id)){ | ||
const check = this.triedAlready.get(id) | ||
const checkStamp = (Date.now() - check.stamp) / 1000 | ||
@@ -724,6 +715,6 @@ if(check.wait >= checkStamp){ | ||
// if(this.sockets.has(hash)){ | ||
// const checkTracker = this.sockets.get(hash) | ||
// if(this.sockets.has(id)){ | ||
// const checkTracker = this.sockets.get(id) | ||
// const checkRelay = this.relays.get(ih) | ||
// if(checkRelay.every((data) => {return checkTracker.hash !== data.hash})){ | ||
// if(checkRelay.every((data) => {return checkTracker.id !== data.id})){ | ||
// // checkRelay.push(checkTracker) | ||
@@ -738,6 +729,6 @@ // // if(!checkTracker.relays.includes(ih)){ | ||
if(this.sockets.has(hash)){ | ||
const checkTracker = this.sockets.get(hash) | ||
if(this.sockets.has(id)){ | ||
const checkTracker = this.sockets.get(id) | ||
const checkRelay = this.relays.get(ih) | ||
if(checkRelay.every((data) => {return checkTracker.hash !== data.hash})){ | ||
if(checkRelay.every((data) => {return checkTracker.id !== data.id})){ | ||
// checkRelay.push(checkTracker) | ||
@@ -754,12 +745,11 @@ // if(!checkTracker.relays.includes(ih)){ | ||
if(this.relays.get(ih).length < this.limit.serverConnections){ | ||
const relay = `ws://${peer.host}:${peer.port}/relay/${ih}` | ||
const relay = `ws://${peer.host}:${peer.port}/relay?relay_hash=${ih}&id=${this.id}` | ||
const con = new WebSocket(relay) | ||
con.server = false | ||
con.active = true | ||
con.relay = ih | ||
con.relays = [] | ||
con.relay = ih | ||
con.proc = false | ||
con.hash = ih | ||
this.sockets.set(con.hash, con) | ||
// con.hash = hash | ||
con.id = id | ||
this.sockets.set(con.id, con) | ||
self.onRelaySocketConnection(con) | ||
@@ -769,12 +759,11 @@ return | ||
} else { | ||
const relay = `ws://${peer.host}:${peer.port}/relay/${ih}` | ||
const relay = `ws://${peer.host}:${peer.port}/relay?relay_hash=${ih}&id=${this.id}` | ||
const con = new WebSocket(relay) | ||
con.server = false | ||
con.active = true | ||
con.relay = ih | ||
con.relays = [] | ||
con.relay = ih | ||
con.proc = false | ||
con.hash = ih | ||
this.sockets.set(con.hash, con) | ||
// con.hash = hash | ||
con.id = id | ||
this.sockets.set(con.id, con) | ||
self.onRelaySocketConnection(con) | ||
@@ -792,7 +781,7 @@ return | ||
turnOnHTTP(){ | ||
this.http.listen(this.port, this.host) | ||
this.http.listen(this.port, this.server) | ||
} | ||
turnOnDHT(){ | ||
this.relay.listen(this.port, this.host) | ||
this.relay.listen(this.port, this.server) | ||
} | ||
@@ -835,11 +824,6 @@ | ||
_filter(infoHash, params, cb){ | ||
// const hashes = (() => {if(!opts.hashes){throw new Error('must have hashes')}return Array.isArray(opts.hashes) ? opts.hashes : opts.hashes.split(',')})() | ||
if(this.status){ | ||
if(this.hashes.has(infoHash)){ | ||
cb(null) | ||
} else { | ||
cb(new Error('disallowed torrent')) | ||
} | ||
if(this.hashes.has(infoHash)){ | ||
cb(null) | ||
} else { | ||
cb(null) | ||
cb(new Error('disallowed torrent')) | ||
} | ||
@@ -932,2 +916,3 @@ } | ||
this.hashes.clear() | ||
this.triedAlready.clear() | ||
if(cb){ | ||
@@ -962,10 +947,10 @@ cb() | ||
// send the right messages | ||
// self.sockets[socket.hash] = socket | ||
if(socket.hash){ | ||
if(self.triedAlready.has(socket.hash)){ | ||
self.triedAlready.delete(socket.hash) | ||
// self.sockets[socket.id] = socket | ||
if(socket.id){ | ||
if(self.triedAlready.has(socket.id)){ | ||
self.triedAlready.delete(socket.id) | ||
} | ||
} | ||
if(!socket.server){ | ||
socket.send(JSON.stringify({hash: self.hash, key: self.key, address: self.address, web: self.web, host: self.host, port: self.port, domain: self.domain, relay: socket.relay, status: self.status, sig: self.sig, action: 'session', reply: true})) | ||
socket.send(JSON.stringify({id: self.id, key: self.key, address: self.address, web: self.web, host: self.host, port: self.port, domain: self.domain, relay: socket.relay, status: self.status, sig: self.sig, action: 'session', reply: true})) | ||
delete socket.relay | ||
@@ -976,10 +961,10 @@ } | ||
let useSocket | ||
if(socket.hash){ | ||
useSocket = socket.hash | ||
if(self.triedAlready.has(socket.hash)){ | ||
const check = self.triedAlready.get(socket.hash) | ||
if(socket.id){ | ||
useSocket = socket.id | ||
if(self.triedAlready.has(socket.id)){ | ||
const check = self.triedAlready.get(socket.id) | ||
check.stamp = Date.now() | ||
check.wait = check.wait * 2 | ||
} else { | ||
self.triedAlready.set(socket.hash, {stamp: Date.now(), wait: 1}) | ||
self.triedAlready.set(socket.id, {stamp: Date.now(), wait: 1}) | ||
} | ||
@@ -999,3 +984,3 @@ } else { | ||
if(message.action === 'session'){ | ||
if(!message.sig || !ed.verify(message.sig, self.test, message.key) || self.sockets.has(message.hash)){ | ||
if(socket.relay !== message.relay || message.id !== crypto.createHash('sha1').update(message.address).digest('hex') || !ed.verify(message.sig, self.test, message.key) || self.sockets.has(message.id)){ | ||
socket.close() | ||
@@ -1008,7 +993,6 @@ return | ||
// message.relays = [useRelay] | ||
const useRelay = message.relay | ||
delete message.relay | ||
for(const m in message){ | ||
if(!socket[m]){ | ||
socket[m] = message[m] | ||
} | ||
socket[m] = message[m] | ||
} | ||
@@ -1021,7 +1005,6 @@ for(const r of socket.relays){ | ||
socket.session = true | ||
// self.sockets.set(socket.hash, socket) | ||
if(socket.server){ | ||
self.sockets.set(socket.hash, socket) | ||
socket.send(JSON.stringify({hash: self.hash, key: self.key, address: self.address, web: self.web, host: self.host, port: self.port, domain: self.domain, relay: useRelay, status: self.status, sig: self.sig, action: 'session', reply: false})) | ||
socket.send(JSON.stringify({id: self.id, key: self.key, address: self.address, web: self.web, host: self.host, port: self.port, domain: self.domain, relay: useRelay, status: self.status, sig: self.sig, action: 'session', reply: false})) | ||
} | ||
delete socket.relay | ||
} | ||
@@ -1034,3 +1017,3 @@ if(message.action === 'add'){ | ||
const checkRelay = self.relays.get(message.relay) | ||
const i = checkRelay.findIndex((data) => {return socket.hash === data.hash}) | ||
const i = checkRelay.findIndex((data) => {return socket.id === data.id}) | ||
if(i === -1){ | ||
@@ -1054,3 +1037,3 @@ checkRelay.push(socket) | ||
const checkRelay = self.relays.get(message.relay) | ||
const i = checkRelay.findIndex((data) => {return socket.hash === data.hash}) | ||
const i = checkRelay.findIndex((data) => {return socket.id === data.id}) | ||
if(i !== -1){ | ||
@@ -1074,3 +1057,3 @@ checkRelay.splice(i, 1) | ||
const checkRelay = self.relays.get(r) | ||
const i = checkRelay.find((soc) => {return socket.hash === soc.hash}) | ||
const i = checkRelay.find((soc) => {return socket.id === soc.id}) | ||
if(i){ | ||
@@ -1086,3 +1069,3 @@ i.session = true | ||
const checkRelay = self.relays.get(r) | ||
const i = checkRelay.find((soc) => {return socket.hash === soc.hash}) | ||
const i = checkRelay.find((soc) => {return socket.id === soc.id}) | ||
if(i){ | ||
@@ -1095,3 +1078,3 @@ i.session = false | ||
} catch (error) { | ||
self.emit('ev', socket.hash || 'socket' + ' had an error, will wait and try to connect later, ' + error.message) | ||
self.emit('ev', socket.id || 'socket' + ' had an error, will wait and try to connect later, ' + error.message) | ||
socket.close() | ||
@@ -1108,3 +1091,3 @@ } | ||
const checkRelay = self.relays.get(soc) | ||
const i = checkRelay.findIndex((data) => {return socket.hash === data.hash}) | ||
const i = checkRelay.findIndex((data) => {return socket.id === data.id}) | ||
if(i !== -1){ | ||
@@ -1117,5 +1100,5 @@ checkRelay.splice(i, 1) | ||
if(socket.hash){ | ||
if(self.sockets.has(socket.hash)){ | ||
self.sockets.delete(socket.hash) | ||
if(socket.id){ | ||
if(self.sockets.has(socket.id)){ | ||
self.sockets.delete(socket.id) | ||
} | ||
@@ -1175,2 +1158,21 @@ } | ||
onHttpRelay(req, res, par){ | ||
// const useRelayHash = req.url.slice(0, req.url.indexOf('?')).replace('/relay/', '') | ||
const getRelayHash = par.has('relay_hash') ? par.get('relay_hash') : null | ||
const checkRelayHash = getRelayHash && typeof(getRelayHash) === 'string' && getRelayHash.length === 20 | ||
const getId = par.has('id') ? par.get('id') : null | ||
const checkId = getId && typeof(getId) === 'string' && getId.length === 20 | ||
if(!checkRelayHash && !checkId){ | ||
res.end(bencode.encode({'failure reason': 'must have relay-hash or id'})) | ||
} | ||
const check = {} | ||
if(checkRelayHash){ | ||
check.relay_hash = this.relays.has(par.relay_hash) | ||
} | ||
if(checkId){ | ||
check.id = this.sockets.has(par.id) | ||
} | ||
res.end(bencode.encode(check)) | ||
} | ||
onWebSocketConnection (socket, opts = {}) { | ||
@@ -1370,3 +1372,3 @@ this.clientCount = this.clientCount + 1 | ||
const checkGet = this.relays.get(relay).filter((data) => {return data.session}) | ||
params.relay = checkGet.length ? `${params.type}://${checkGet[Math.floor(Math.random() * checkGet.length)].web}/announce/${params.info_hash}` : '' | ||
params.relay = checkGet.length ? `${params.type}://${checkGet[Math.floor(Math.random() * checkGet.length)].web}/announce` : '' | ||
} else { | ||
@@ -1378,7 +1380,7 @@ params.relay = '' | ||
} else if(this.limit.clientConnections && this.clientCount >= this.limit.clientConnections){ | ||
const relay = crypto.createHash('sha1').update(hash).digest('hex') | ||
const relay = crypto.createHash('sha1').update(params.info_hash).digest('hex') | ||
const checkHas = this.relays.has(relay) | ||
if(checkHas){ | ||
const checkGet = this.relays.get(relay).filter((data) => {return data.session}) | ||
params.relay = checkGet.length ? `${params.type}://${checkGet[Math.floor(Math.random() * checkGet.length)].web}/announce/${params.info_hash}` : '' | ||
params.relay = checkGet.length ? `${params.type}://${checkGet[Math.floor(Math.random() * checkGet.length)].web}/announce` : '' | ||
} else { | ||
@@ -1402,7 +1404,19 @@ params.relay = '' | ||
getOrCreateSwarm((err, swarm) => { | ||
if (err) return cb(err) | ||
announce(swarm) | ||
}) | ||
if (this.status) { | ||
this._filter(params.info_hash, params, err => { | ||
// Presence of `err` means that this announce request is disallowed | ||
if (err) return cb(err) | ||
getOrCreateSwarm((err, swarm) => { | ||
if (err) return cb(err) | ||
announce(swarm) | ||
}) | ||
}) | ||
} else { | ||
getOrCreateSwarm((err, swarm) => { | ||
if (err) return cb(err) | ||
announce(swarm) | ||
}) | ||
} | ||
// Get existing swarm, or create one if one does not exist | ||
@@ -1409,0 +1423,0 @@ function getOrCreateSwarm (cb) { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
102639
2708