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
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
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
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
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')
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')
def get_file(self): return bencode(self.meta)
def get_info_hash(self): return sha1( bencode(self.meta_info)).digest()