88 lines
2.3 KiB
JavaScript
88 lines
2.3 KiB
JavaScript
const Router = require('express-promise-router');
|
|
const bencode = require('bencode');
|
|
const qs = require('querystring');
|
|
|
|
const peerListFormatters = require('../lib/peerListFormatters');
|
|
const bqs = require('../lib/binaryQuerystring');
|
|
|
|
const INFO_HASH_REGEX = new RegExp('^[0-9a-f]{40}$', 'i');
|
|
|
|
module.exports = ({ dht }) => {
|
|
const app = Router();
|
|
app.get(
|
|
'/',
|
|
async (
|
|
{
|
|
log,
|
|
originalUrl,
|
|
query: { info_hash: infoHash, compact, json, event = '' },
|
|
},
|
|
res,
|
|
) => {
|
|
// worst case if every character is percent encoded, or best case if every _is_ decoded
|
|
if (!infoHash || infoHash.length > 60 || infoHash < 20) {
|
|
res
|
|
.status(400)
|
|
.end(bencode.encode({ 'failure reason': 'invalid arguments' }));
|
|
return;
|
|
}
|
|
|
|
if (infoHash.length !== 20) {
|
|
infoHash = bqs.fromUrl(originalUrl).info_hash;
|
|
|
|
if (!infoHash || infoHash.length !== 20) {
|
|
res
|
|
.status(400)
|
|
.end(bencode.encode({ 'failure reason': 'invalid arguments' }));
|
|
log({ status: 'refused', type: 'dhtGateway' });
|
|
return;
|
|
}
|
|
}
|
|
|
|
infoHash = Buffer.from(infoHash, 'latin1').toString('hex');
|
|
if (!infoHash.match(INFO_HASH_REGEX)) {
|
|
res
|
|
.status(400)
|
|
.end(bencode.encode({ 'failure reason': 'invalid arguments' }));
|
|
log({ status: 'refused', type: 'dhtGateway' });
|
|
return;
|
|
}
|
|
|
|
let format = 'bencoded';
|
|
if (compact === '1') {
|
|
format = 'compact';
|
|
} else if (json === '1') {
|
|
format = 'json';
|
|
}
|
|
|
|
try {
|
|
let peers = [];
|
|
// a completed or stopped torrent does not need peers
|
|
if (event !== 'completed' && event !== 'stopped') {
|
|
peers = await dht.lookup(infoHash);
|
|
}
|
|
// this sends the response as well as formatting it
|
|
peerListFormatters(peers, res, format);
|
|
log({
|
|
status: 'served',
|
|
type: 'dhtGateway',
|
|
format,
|
|
count: peers.length,
|
|
});
|
|
} catch (e) {
|
|
res
|
|
.status(500)
|
|
.end(bencode.encode({ 'failure reason': 'internal error' }));
|
|
log({
|
|
status: 'failed',
|
|
type: 'dhtGateway',
|
|
format,
|
|
error: e.message,
|
|
stack: e.stack,
|
|
});
|
|
}
|
|
},
|
|
);
|
|
return app;
|
|
};
|