def _clean_torrent(hsh):
    import magic
    if hsh is None:
        return ''
    m = magic.open(magic.MAGIC_MIME)
    m.load()
    hsh = hsh.read()
    if not 'x-bittorrent' in m.buffer(hsh):
        m.close()
        raise forms.ValidationError, _(
            "Uploaded file doesn't look like torrent.")
    m.close()
    try:
        # do not forget to add LimitRequestBody to apache config
        hsh = bdecode(hsh)
    except ValueError:
        raise forms.ValidationError, _(
            "Uploaded file doesn't look like torrent.")
    hsh['announce'] = ANNOUNCE_URL
    hsh['modified-by'] = [SITE_NAME]
    if hsh.has_key('comment'):
        hsh['comment'] = SITE_NAME
    info_hash = sha.new(bencode(hsh['info'])).hexdigest()
    t = Torrent.objects.filter(info_hash=info_hash)
    if t:
        raise forms.ValidationError, _("This torrent already exists.")
    return (hsh, info_hash)
def _fail(reason, xhr=False):
    if not xhr:
	return HttpResponse(bencode({'failure reason': reason}))
    r = HttpResponse(mimetype="text/xml")
    r.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
    r.write("<result><msg>failure</msg></result>")
    return r
Example #3
0
def _clean_torrent(hsh):
    import magic
    if hsh is None:
	return ''
    m = magic.open(magic.MAGIC_MIME)
    m.load()
    hsh = hsh.read()
    if not 'x-bittorrent' in m.buffer(hsh):
	m.close()
	raise forms.ValidationError, _("Uploaded file doesn't look like torrent.")
    m.close()
    try:
	# do not forget to add LimitRequestBody to apache config
	hsh = bdecode(hsh)
    except ValueError:
	raise forms.ValidationError, _("Uploaded file doesn't look like torrent.")
    hsh['announce'] = ANNOUNCE_URL
    hsh['modified-by'] = [SITE_NAME]
    if hsh.has_key('comment'):
	hsh['comment'] = SITE_NAME
    info_hash=sha.new(bencode(hsh['info'])).hexdigest()
    t = Torrent.objects.filter(info_hash=info_hash)
    if t:
	raise forms.ValidationError, _("This torrent already exists.")
    return (hsh, info_hash)
def scrape(request):
    request.encoding = 'latin-1'
    xhr = request.GET.get('xhr')

    info_hash = request.GET.get('info_hash', '')
    if len(info_hash) < 20:
	return _fail("invalid request", xhr=xhr)
    try:
	info_hash = info_hash.encode('iso-8859-1').encode('hex')
    except:
	return _fail("invalid request", xhr=xhr)
    t = Torrent.objects.filter(info_hash=info_hash).values('id')
    if not t:
	return _fail("no such torrent", xhr=xhr)

    mc = memcache.Client([MEMCACHE], debug=0)
    peers = mc.get('peers')

    if not peers:
	peers = []

    # calculate scrape interval
    now = datetime.datetime.now()
    num_peers = len([p for p in peers if p['expire_time']>now])
    announce_rate = len([p for p in peers if p['update_time']>now-datetime.timedelta(minutes=1)])
    scrape_interval = max(num_peers * announce_rate / MAX_ANNOUNCE_RATE**2 * 60, MIN_ANNOUNCE_INTERVAL) * SCRAPE_FACTOR

    result = {info_hash: {'complete': 0, 'incomplete': 0, 'downloaded': 0}}
    for p in peers:
	if p['info_hash'] == info_hash:
	    if p['left'] == 0 and p['expire_time']>now:
		result[info_hash]['complete'] += 1
	    elif p['left'] > 0 and p['expire_time']>now:
		result[info_hash]['incomplete'] += 1
	    elif p['left'] == 0:
		result[info_hash]['downloaded'] += 1
    if xhr:
	r = HttpResponse(mimetype="text/xml")
	r.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
	r.write("""<scraper><msg>success</msg>
	    <leechers>%s</leechers>
	    <seeds>%s</seeds>
	    <downloaded>%s</downloaded>
	    </scraper>""" % (
		result[info_hash].get('incomplete', 0),
		result[info_hash].get('complete', 0),
		result[info_hash].get('downloaded', 0),
	    )
	)
	return r
    return HttpResponse(bencode({
	    'files': result,
	    'flags': {'min_request_interval': int(scrape_interval)},
	}),
    mimetype = 'text/plain')
def get_info_hash(torrentfile):
    f = open(torrentfile, 'rb')
    try:
        bencoded_data = bdecode(f.read())
    except ValueError:
        print('ERR: Invalid File')
        return
    # encode the value of the info key of the dictionary with the metainfo 
    # in sha1; encode the sha1 hash into hex.
    info_hash = hashlib.sha1(bencode(bencoded_data['info'])).hexdigest()
    return info_hash
Example #6
0
def get_torrent(request, the_id):
    from users.views import login
    import base64
    from benc import bdecode, bencode
    if not OPEN_TRACKER:
	if not request.user.is_authenticated():
	    return HttpResponseRedirect(reverse(login) + '?redirect=' + request.path)
    torrent = get_object_or_404(Torrent, pk=the_id)
    content = base64.b64decode(torrent.info)
    content = bdecode(content)
    if not OPEN_TRACKER:
	content['announce'] += "?passkey=%s"%request.user.passkey
    content = bencode(content)
    response = HttpResponse(content, mimetype='application/x-bittorrent')
    response["Content-Length"] = len(content)
    response["Content-Disposition"] = "attachment; filename=\"%s\""% torrent.fn
    return response
Example #7
0
def get_torrent(request, the_id):
    from users.views import login
    import base64
    from benc import bdecode, bencode
    if not OPEN_TRACKER:
        if not request.user.is_authenticated():
            return HttpResponseRedirect(
                reverse(login) + '?redirect=' + request.path)
    torrent = get_object_or_404(Torrent, pk=the_id)
    content = base64.b64decode(torrent.info)
    content = bdecode(content)
    if not OPEN_TRACKER:
        content['announce'] += "?passkey=%s" % request.user.passkey
    content = bencode(content)
    response = HttpResponse(content, mimetype='application/x-bittorrent')
    response["Content-Length"] = len(content)
    response[
        "Content-Disposition"] = "attachment; filename=\"%s\"" % torrent.fn
    return response
Example #8
0
def _save_torrent(instance, data):
    from utils import slughifi, genslug
    import base64
    if not data:
	return
    slug = slughifi(instance.title)
    if not slug.strip().replace('-', '') or len(slug)>=50:
	slug = genslug()
    slug = slug.replace(' ', '-')
    fn = "%sxDF-%s.torrent"%(instance.author.id, slug)
    torrent = Torrent()
    torrent.fn = fn
    torrent.author = instance.author
    torrent.info_hash = data[1]
    if data[0]['info'].has_key('length'):
	file_length = data[0]['info']['length']
    else:
	file_length = reduce(lambda x,y: x+y, [f['length'] for f in data[0]['info']['files']])
    torrent.bytes = file_length
    hsh = base64.b64encode(bencode(data[0]))
    torrent.info = hsh
    torrent.save()
    instance.torrent = torrent
def _save_torrent(instance, data):
    from utils import slughifi, genslug
    import base64
    if not data:
        return
    slug = slughifi(instance.title)
    if not slug.strip().replace('-', '') or len(slug) >= 50:
        slug = genslug()
    slug = slug.replace(' ', '-')
    fn = "%sxDF-%s.torrent" % (instance.author.id, slug)
    torrent = Torrent()
    torrent.fn = fn
    torrent.author = instance.author
    torrent.info_hash = data[1]
    if data[0]['info'].has_key('length'):
        file_length = data[0]['info']['length']
    else:
        file_length = reduce(lambda x, y: x + y,
                             [f['length'] for f in data[0]['info']['files']])
    torrent.bytes = file_length
    hsh = base64.b64encode(bencode(data[0]))
    torrent.info = hsh
    torrent.save()
    instance.torrent = torrent
#!/usr/bin/python
import sys
import os
import base64

sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from fs.models import Topic
from tracker.models import Torrent
from benc import bdecode, bencode
from users.models import User

user = User.objects.get(username="******")
dest = os.path.join(os.path.dirname(__file__), "ex")

for t in Topic.objects.all():
    content = base64.b64decode(t.torrent.info)
    content = bdecode(content)
    content["announce"] += "?passkey=%s" % user.passkey
    content = bencode(content)
    f = open(os.path.join(dest, t.torrent.fn), "wb")
    f.write(content)
    f.close()
    print t.torrent.fn
#!/usr/bin/python
import sys
import os
import base64
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from fs.models import Topic
from tracker.models import Torrent
from benc import bdecode, bencode
from users.models import User

user = User.objects.get(username='******')
dest = os.path.join(os.path.dirname(__file__), 'ex')

for t in Topic.objects.all():
    content = base64.b64decode(t.torrent.info)
    content = bdecode(content)
    content['announce'] += "?passkey=%s" % user.passkey
    content = bencode(content)
    f = open(os.path.join(dest, t.torrent.fn), 'wb')
    f.write(content)
    f.close()
    print t.torrent.fn
def announce(request):
    request.encoding = 'latin-1'
    if not OPEN_TRACKER:
	if not request.GET.get('passkey'):
	    return _fail("you need to provide passkey")
	if len(request.GET['passkey']) < 40:
	    return _fail("you need to provide valid passkey")
	u = User.objects.filter(passkey=request.GET['passkey'])
	if not u:
	    return _fail("user with this passkey wasn't found")
	else:
	    u = u[0]

    args = {}
    args['ip'] = request.GET.get('ip') or request.META.get('REMOTE_ADDR')
    try:
	gethostbyname(args['ip'])
    except:
	return _fail("unable to resolve host name %s"%args['ip'])

    for key in ['uploaded', 'downloaded', 'port', 'left']:
	if request.GET.has_key(key):
	    try:
		args[key] = int(request.GET[key])
	    except ValueError:
		return _fail("argument '%s' specified incorrectly."%key)
	else:
	    return _fail("argument '%s' not specified."%key)
    event = request.GET.get('event', '')
    if event not in ['completed','stopped','started'] and len(event.strip())>0:
	return _fail("invalid request")

    # is the announce method allowed ?
    if REQUIRE_ANNOUNCE_PROTOCOL == 'no_peer_id':
	if not request.GET.get('compact') and not request.GET.get('no_peer_id'):
	    return _fail("standard announces not allowed; use no_peer_id or compact option")
    elif REQUIRE_ANNOUNCE_PROTOCOL == 'compact':
	if not request.GET.get('compact'):
	    return _fail("tracker requires use of compact option")

    info_hash = request.GET.get('info_hash', '')
    if len(info_hash) < 20 or not request.GET.get('peer_id'):
	return _fail("invalid request")
    try:
	info_hash = info_hash.encode('iso-8859-1').encode('hex')
    except:
	return _fail("invalid request")
    args['peer_id'] = request.GET['peer_id']
    torrent_id = Torrent.objects.filter(info_hash=info_hash).values('id')
    if not torrent_id:
	return _fail("no such torrent")
    else:
	torrent_id = torrent_id[0]['id']

    # calculate announce interval
    now = datetime.datetime.now()

    mc = memcache.Client([MEMCACHE], debug=0)
    peers = mc.get('peers')

    if not peers:
	peers = []

    if not OPEN_TRACKER:
	dwns = len([p for p in peers if p['user_id'] == u.id and p['expire_time']>now])
	cur_dwns = u.attrs.get('max_sim_dwn', 2)
	if dwns >= cur_dwns and cur_dwns != 0:
	    return _fail("maximum number of simultaneous downloads reached: %s"% dwns)

    num_peers = len([p for p in peers if p['expire_time']>now])
    announce_rate = len([p for p in peers if p['update_time']>now-datetime.timedelta(minutes=1)])

    announce_interval = max(num_peers * announce_rate / (MAX_ANNOUNCE_RATE**2) * 60, MIN_ANNOUNCE_INTERVAL)
    # calculate expiration time offset
    if event == 'stopped':
	expire_time = 0
    else:
	expire_time = announce_interval * EXPIRE_FACTOR

    for p in peers:
	if p['peer_id'] == args['peer_id']:
	    peers.remove(p)
    if event == 'completed':
	topic = Topic.objects.filter(torrent__pk=torrent_id)
	if len(topic)>0:
	    topic[0].attrs['downloaded'] = topic[0].attrs.get('downloaded', 0)+1
	    topic[0].save()
    if event != 'stopped':
	peer_dict = {
	    'info_hash': info_hash,
	    'peer_id': args['peer_id'],
	    'ip': args['ip'],
	    'port': args['port'],
	    'uploaded': args['uploaded'],
	    'downloaded': args['downloaded'],
	    'left': args['left'],
	    'expire_time': now+datetime.timedelta(seconds=int(expire_time)),
	    'update_time': now,
	    'torrent_id': torrent_id,
	}
	if not OPEN_TRACKER:
	    peer_dict['user_id'] = u.id
	peers.append(peer_dict)

    mc.set('peers', peers)

    numwant = request.GET.get('numwant', 50)
    try:
	numwant = int(numwant)
    except ValueError:
	numwant = 50
    result = [p for p in peers if p['torrent_id'] == torrent_id and p['expire_time']>now and p['info_hash']==info_hash] #this may be optimized
    shuffle(result)
    result = result[:numwant]

    if request.GET.get('compact'):
	peers = ""
	for peer in result:
	    peers += pack('>4sH', inet_aton(peer['ip']), peer['port'])
    elif request.GET.get('no_peer_id'):
	peers = []
	for peer in result:
	    peers.append({'ip': peer['ip'], 'port': peer['port']})
    else:
	peers = []
	for peer in result:
	    peers.append({'ip': peer['ip'], 'port': peer['port'], 'peer id': peer['peer_id']})

    return HttpResponse(bencode({
	    'interval': int(announce_interval),
	    'peers': peers,
	}),
	mimetype = 'text/plain')
Example #13
0
        peer.uploaded=uploaded
        peer.left=left
        peer.save()
        profile.save()

        """
        And again something needs to go here to update a model
        generically
        """
        if numwant:
                # The random order is expensive. by caching for the announce interval, we guarantee that
                # a random peer list will be generated every announce period and will be served to all clients
                # looking for that info. The expiry guarantees that new results will be generated on next announce
            peers = [dict((pkey.replace('_', ' '),value) for pkey, value in peer.iteritems())
                 for peer in torrent.peers.order_by('?').values('peer_id','port','ip')[:100] ]
                #cache.set("tracker-peers-iphandout-"+info_hash, peers, settings.TRACKER_ANNOUNCE_INTERVAL)
            response['peers'] = peers[:min(numwant, 100)]
        print 'finished'
    except MultiValueDictKeyError:
        response['failure reason'] = 'invalid request, duplicate GET keys.'
    except Torrent.DoesNotExist:
        response['failure reason'] = 'torrent not available'
    except ValueError, e:
        response['failure reason'] = str(e)
    except:
        response['failure reason'] = 'suck it'
    finally:
        if response.get('failure reason'): response['interval']=20
        return HttpResponse(bencode(response), content_type='text/plain')

Example #14
0
 def get_file(self):
     return bencode(self.meta)
Example #15
0
 def get_info_hash(self):
     return sha1( bencode(self.meta_info)).digest()