webseeded-torrent-generator
Version:
Generate webseeded torrent files from urls to files.
352 lines (324 loc) • 13.3 kB
JavaScript
// var assert = require('assert');
// //var HttpFile = require('../lib/http-fs').HttpFile;
// var nt = require('nt');
// describe('Torrent Generation', function () {
// this.timeout(10000);
// it('generates the same torrent as nt', function (done) {
// });
// });
;
var Torrent = require('../lib/torrent');
var fs = require('fs');
var path = require('path');
var assert = require('assert');
var q = require('q');
var _ = require('lodash');
var crypto = require('crypto');
var BunyanPromiseLogger = require('bunyan-promise');
var bencode = require('bencode');
var promiseLog = new BunyanPromiseLogger({
name: 'test-torrent'
});
var kB = 0x400;
var MB = kB * kB;
describe('Piece Size', function () {
it('uses correct piece size for small files', function (done) {
var base = 'http://ia700201.us.archive.org/6/items/';
var name = 'jj2005-02-27.fm.shnf';
var files = [
'jj2005-02-27.fm.d1.md5',
'jj2005-02-27.fm.d1t1_vbr.mp3'
];
var torrent = new Torrent(base, name, files);
torrent.getPieceLength().then(function (length) {
// should be the minimum piece size...16kB
assert(length === 256 * kB);
done();
}).fail(function (err) {
done(new Error(err));
});
});
it('uses correct piece size for huge files', function (done) {
var base = 'https://s3.amazonaws.com/content-bundles/production-df0ec56d-0fbb-bc2c-11e7-354ff3af9c4e/bf3a4aa8cfe2a908002c9981948f38a07c9997df752a9abeee537aa6dc7bcebf/originals/';
var name = 'Footsteps';
var files = [
'00_What\'s-Inside.html',
'FOOTSTEPS_2012_FEATUREFILM_1080p.mp4',
'FOOTSTEPS_2012_TRAILER_1080p.mp4'
];
var torrent = new Torrent(base, name, files);
torrent.getPieceLength().then(function (length) {
// should be 4 MB
assert(length === 4 * MB);
done();
}).fail(function (err) {
done(new Error(err));
});
});
});
describe('Torrent Generation', function () {
this.timeout(300000);
it('provides progress updates when generating a torrent', function (done) {
var base = 'http://ia700201.us.archive.org/6/items/';
var name = 'jj2005-02-27.fm.shnf';
var files = [
'jj2005-02-27.fm.d1.md5',
'jj2005-02-27.fm.d1t1_vbr.mp3'
];
var torrent = new Torrent(base, name, files);
var metadataRequest = torrent.getMetadata();
var expectedProgressNotifications = [
16.573486745648847,
33.14697349129769,
49.720460236946536,
66.29394698259539,
82.86743372824424,
99.44092047389307,
100
];
metadataRequest.progress(function (progress) {
process.stdout.write('AAAA - ' + progress + '\n');
if (!_.contains(expectedProgressNotifications, progress)) {
done(new Error('expected the received progress to be in the expected list'));
}
expectedProgressNotifications = _.without(expectedProgressNotifications, progress);
});
metadataRequest.then(function () {
assert(expectedProgressNotifications.length === 0, 'expected to see all the progress updates');
}).then(function () {
done();
}, function (err) {
done(new Error(err));
});
promiseLog.trace(metadataRequest, 'provides progress updates when generating a large torrent');
});
it('generates a private torrent', function (done) {
var infoHash = '154f36b266a03e1f50bd469b038b944e043dbb16';
var base = 'http://ia700201.us.archive.org/6/items/';
var name = 'jj2005-02-27.fm.shnf';
var files = [
'jj2005-02-27.fm.d1.md5',
'jj2005-02-27.fm.d1.txt'
];
var options = {
private: true,
'announce-list': []
};
var torrent = new Torrent(base, name, files, options);
var infoHashRequest = torrent.getInfoHash().then(function (res) {
assert(infoHash === res, 'torrent info hash generated matches expected torrent file info hash');
});
infoHashRequest.then(function () {
done();
}, function (err) {
done(new Error(err));
});
});
it('generates a replica of a small working internet archive backed torrent', function (done) {
var infoHash = 'ab715690d4c95dd147f6f2fe9f071705bbe22028';
var torrentFile = fs.readFileSync('./test/torrents/' + infoHash + '.torrent');
var base = 'http://ia700201.us.archive.org/6/items/';
var name = 'jj2005-02-27.fm.shnf';
var files = [
'jj2005-02-27.fm.d1.md5',
'jj2005-02-27.fm.d1.txt'
];
var torrent = new Torrent(base, name, files);
var metadataRequest = torrent.getMetadata().then(function (res) {
assert(torrentFile.toString() === res.toString(), 'torrent generated matches expected torrent file');
return q.resolve();
});
var infoHashRequest = torrent.getInfoHash().then(function (res) {
assert(infoHash === res, 'torrent info hash generated matches expected torrent file info hash');
return q.resolve();
});
var ret = q.all([
metadataRequest,
infoHashRequest
]);
promiseLog.trace(ret, 'generates a replica of a small working internet archive backed torrent');
ret.then(function () {
done();
}, function (err) {
done(new Error(err));
});
});
it('generates a torrent with non-ascii characters', function (done) {
var base = 'http://s3.amazonaws.com/content-test/';
var name = '布碌崙滅門慘案報導';
var files = [
'布碌崙滅門慘案報導.mp4',
'00_What\'s-Inside.html',
'folder/_#_布碌崙滅門慘案報導.png'
];
var torrent = new Torrent(base, name, files);
torrent.getMetadata().then(function () {
done();
}, function (err) {
done(new Error(err));
});
});
it('generates torrents with url reserved characters in the file names', function (done) {
var base = 'http://s3.amazonaws.com/';
var name = 'content-test';
var files = [
'!@#$%^&*().html',
'{}[]<>,.?.html',
'file_with_a_#_in_it',
'and&?.png'
];
new Torrent(base, name, files).getMetadata().then(function () {
done();
}, function (err) {
done(new Error(err));
});
});
it('generates torrents correctly with url reserved characters in file names', function (done) {
var base = 'http://s3.amazonaws.com/';
var name = 'content-test';
var files = [
'1+2=3.png',
'file_with_a_#_in_it',
'and&?.png'
];
var torrent = new Torrent(base, name, files);
torrent.getMetadata().then(function (res) {
var torrentFilePath = path.resolve(__dirname, 'torrents', '45676365a2639359e1291f4945f158a04e9934c8.torrent');
var torrentFile = fs.readFileSync(torrentFilePath);
if (torrentFile.toString() === res.toString()) {
done();
} else {
done(new Error('torrent generated expected to match torrent file'));
}
}, function (err) {
done(new Error(err));
});
});
it('generates torrents with similar and collections', function (done) {
var base = 'http://ia700201.us.archive.org/6/items/';
var name = 'jj2005-02-27.fm.shnf';
var files = [
'jj2005-02-27.fm.d1.md5',
'jj2005-02-27.fm.d1.txt'
];
var torrent = new Torrent(base, name, files, {
similar: [
'ab715690d4c95dd147f6f2fe9f071705bbe22028'
],
collections: [
'com.network.seriesname.season1',
'do.vo.pioneerone.season2'
]
});
torrent.getMetadata().then(function (res) {
var torrentFilePath = path.resolve(__dirname, 'torrents', 'c9dde7f0febd5105d1f1f531e780da7bff5fd6c5.torrent');
var torrentFile = fs.readFileSync(torrentFilePath);
if (torrentFile.toString() === res.toString()) {
done();
} else {
done(new Error('torrent generated expected to match torrent file'));
}
}).fail(function (err) {
done(new Error(err));
});
});
it('generates signed torrents', function (done) {
var base = 'http://ia700201.us.archive.org/6/items/';
var name = 'jj2005-02-27.fm.shnf';
var files = [
'jj2005-02-27.fm.d1.md5',
'jj2005-02-27.fm.d1.txt'
];
var key = fs.readFileSync(path.resolve(__dirname, 'signing', 'privkey.pem'));
var cert = fs.readFileSync(path.resolve(__dirname, 'signing', 'cert.pem'));
var torrent = new Torrent(base, name, files, {
signing: {
'com.bittorrent': {
key: key,
cert: cert,
info: { '_test': 'Genuine Torrent' }
}
},
originator: cert
});
q.all([
torrent.getInfo(),
torrent.getSignatures(),
torrent.getSigningAlgorithm()
]).spread(function (info, signatures, algorithm) {
/* Assert static info */
assert(signatures.hasOwnProperty('com.bittorrent'), 'expected signing entity');
var certificatePem = '-----BEGIN CERTIFICATE-----' +
signatures['com.bittorrent'].certificate.toString('base64') +
'-----END CERTIFICATE-----';
assert(certificatePem === cert.toString().replace(/\n/g, ''), 'expected certificate');
var originatorPem = '-----BEGIN CERTIFICATE-----' +
info.originator.toString('base64') +
'-----END CERTIFICATE-----';
assert(originatorPem === cert.toString().replace(/\n/g, ''), 'expected originator');
/* Verify signature */
var buf = Buffer.concat([
bencode.encode(info),
bencode.encode(signatures['com.bittorrent'].info)
]);
var verify = crypto.createVerify(algorithm);
verify.update(buf);
var verifyResult = verify.verify(cert, signatures['com.bittorrent'].signature);
assert(verifyResult === true, 'signature verifies');
done();
}).fail(function (err) {
done(err);
});
});
it('generates signed torrents with a sign callback', function (done) {
var base = 'http://ia700201.us.archive.org/6/items/';
var name = 'jj2005-02-27.fm.shnf';
var files = [
'jj2005-02-27.fm.d1.md5',
'jj2005-02-27.fm.d1.txt'
];
var key = fs.readFileSync(path.resolve(__dirname, 'signing', 'privkey.pem'));
var cert = fs.readFileSync(path.resolve(__dirname, 'signing', 'cert.pem'));
var torrent = new Torrent(base, name, files, {
signing: {
'com.bittorrent': {
signCallback: function (buf) {
var rsaSign = crypto.createSign('RSA-MD5');
rsaSign.update(buf);
return q.resolve(rsaSign.sign(key));
},
cert: cert,
info: { '_test': 'Genuine Torrent' }
}
},
originator: cert
});
q.all([
torrent.getInfo(),
torrent.getSignatures()
]).spread(function (info, signatures) {
/* Assert static info */
assert(signatures.hasOwnProperty('com.bittorrent'), 'expected signing entity');
var certificatePem = '-----BEGIN CERTIFICATE-----' +
signatures['com.bittorrent'].certificate.toString('base64') +
'-----END CERTIFICATE-----';
assert(certificatePem === cert.toString().replace(/\n/g, ''), 'expected certificate');
var originatorPem = '-----BEGIN CERTIFICATE-----' +
info.originator.toString('base64') +
'-----END CERTIFICATE-----';
assert(originatorPem === cert.toString().replace(/\n/g, ''), 'expected originator');
/* Verify signature */
var buf = Buffer.concat([
bencode.encode(info),
bencode.encode(signatures['com.bittorrent'].info)
]);
var verify = crypto.createVerify('RSA-MD5');
verify.update(buf);
var verifyResult = verify.verify(cert, signatures['com.bittorrent'].signature);
assert(verifyResult === true, 'signature verifies');
done();
}).fail(function (err) {
done(err);
});
});
});