Beispiel #1
0
 def _download_torrent(self):
     res = self.session.get(self.dl_link)
     torrent = bytes()
     for chunk in res.iter_content(100000):
         torrent += chunk
     ggn_dir = os.path.join(TORRENT_DIR, 'ggn/')
     if not os.path.exists(ggn_dir):
         os.makedirs(ggn_dir)
     with open(
             os.path.join(
                 ggn_dir,
                 os.path.basename('[GGn]{}.torrent'.format(
                     self.release_title))), 'wb') as t:
         t.write(torrent)
     torrent = bencodepy.decode(torrent)
     torrent[
         b'announce'] = b'https://tracker.pterclub.com/announce?passkey=' + bytes(
             PTER_KEY, encoding='utf-8')
     torrent[b'info'][b'source'] = bytes('[pterclub.com] PT之友俱乐部',
                                         encoding='utf-8')
     del torrent[b'comment']
     torrent = bencodepy.encode(torrent)
     with open(
             os.path.join(
                 'torrents',
                 os.path.basename('[PTer]{}.torrent'.format(
                     self.release_title))), 'wb') as t:
         t.write(torrent)
Beispiel #2
0
def peers_b2l(response):
    """
    Parse the response fron tracker, dig out the peers addresses
    :param response: binary data, response from the tracker
    """
    if response == b'':
        raise ValueError('No data returned')

    data = b.decode(response)
    lst = list()

    if not isinstance(data[b'peers'], bytes):
        raise TypeError('Peer list is {0}'.format(data[b'peers']))

    # parse the response
    for offset in range(0, len(data[b'peers']), 6):
        # all data are stored as big endian
        # dig out the IP address (integer)
        raw_ip = s.unpack_from(">i", data[b'peers'], offset)[0]
        ip = socket.inet_ntoa(s.pack(">i", raw_ip))

        # do the same for the port number (insigned short)
        port = s.unpack_from(">H", data[b'peers'], offset + 4)[0]

        lst.append('{0}:{1}'.format(ip, port))

    return lst
Beispiel #3
0
    async def announce(self, server_port: int, event: EventType):
        params = {
            'info_hash': self._download_info.info_hash,
            'peer_id': self._our_peer_id,
            'port': server_port,
            'uploaded': self._statistics.total_uploaded,
            'downloaded': self._statistics.total_downloaded,
            'left': self._download_info.bytes_left,
            'compact': 1,
        }
        if event != EventType.none:
            params['event'] = event.name
        if self._tracker_id is not None:
            params['trackerid'] = self._tracker_id

        params = {name: urllib.parse.quote(value) if isinstance(value, bytes) else value
                  for name, value in params.items()}
        url = yarl.URL(self._announce_url).update_query(params)

        with async_timeout.timeout(HTTPTrackerClient.REQUEST_TIMEOUT):
            async with aiohttp.ClientSession() as session:
                async with session.get(url) as conn:
                    response = await conn.read()

        response = bencodepy.decode(response)
        if not response:
            if event == EventType.started:
                raise ValueError('Tracker returned an empty answer on start announcement')
            return
        response = cast(OrderedDict, response)

        self._handle_primary_response_fields(response)
        self._handle_optional_response_fields(response)
Beispiel #4
0
def get_torrent_file(torrent_id, return_file=False):

    rows = db2.query(Torrent_File).filter_by(torrent_id=torrent_id).all()

    if len(rows) != 0:
        if return_file is False:
            return
        else:
            return {"file": rows[0].file, "source": "Cached"}

    login()
    r = gazelle.get("{0}/torrents.php?action=download&id={1}".format(
        gazelle_url, torrent_id))

    try:
        data = bencodepy.decode(r.content)
    except:
        print("Error decoding torrent %d" % torrent_id)
        exit()

    # data[b"announce"] = ""

    db2.merge(Torrent_File(torrent_id=torrent_id, file=bencodepy.encode(data)))
    db2.commit()
    #return {"file": None, "source": ""}

    if return_file is True:
        return {"file": bencodepy.encode(data), "source": "Fetched"}
Beispiel #5
0
    def __init__(self, bencontent):
        """
        Args:
            bencontent (bytes): bencoded torrent file contents
        """
        if not bencontent:
            raise TorrentDecodeError('Empty torrent file')

        try:
            content = bencodepy.decode(bencontent)
        except bencodepy.DecodingError as e:
            # TODO: better msg
            raise TorrentDecodeError from e

        # TODO: validate shape using voluptuous or schema libraries

        # 'encoding' field defines character encoding for 'pieces' field.
        encoding = content.get(b'encoding')
        if encoding and encoding.decode('utf-8').lower() != 'utf-8':
            raise(TorrentDecodeError('Unsupported encoding: %s' % encoding))

        self.announce = content[b'announce'].decode('utf-8')
        try:
            vol.Url()(self.announce)
        except vol.UrlInvalid as e:
            msg = 'Invalid announce URL: %s' % self.announce
            raise TorrentDecodeError(msg) from e

        # Ignore 'creation date', 'comment', 'created by', 'announce-list'

        info_dict = content[b'info']
        self.info_hash = hashlib.sha1(bencodepy.encode(info_dict)).digest()
        self.info = self._decode_info_dict(info_dict)
Beispiel #6
0
 def _decode(self, content):
     try:
         response = bencodepy.decode(content)
         self._decode_peers(response[b'peers'])
     except bencodepy.exceptions.DecodingError:
         raise TrackerError('Failed to decode tracker response {}'
                            .format(self._metadata.announce()))
def get_torrent_file(torrent_id, return_file=False):

	rows = db2.query(Torrent_File).filter_by(torrent_id=torrent_id).all()

	if len(rows) != 0:
		if return_file is False:
			return
		else:
			return {"file": rows[0].file, "source": "Cached"}

	login()
	r = gazelle.get("{0}/torrents.php?action=download&id={1}".format(gazelle_url, torrent_id))

	try:
		data = bencodepy.decode(r.content)
	except:
		print("Error decoding torrent %d" % torrent_id)
		exit()

	# data[b"announce"] = ""

	db2.merge(Torrent_File(torrent_id=torrent_id, file=bencodepy.encode(data)))
	db2.commit()
	#return {"file": None, "source": ""}

	if return_file is True:
		return {"file": bencodepy.encode(data), "source": "Fetched"}
Beispiel #8
0
    async def get_file_structure(self, location: str) -> List[str]:
        """
        Given a URL to a .torrent file, it will then return a list
        of the file names inside.

        Parameters
        ----------
        location: str
            A URL to a .torrent file.

        Returns
        -------
        List[str]
            List of file names.
        """
        async with self.session.get(location) as resp:
            torrent_bytes = await resp.read()
            metadata = bencodepy.decode(torrent_bytes)

        is_folder = b"files" in metadata[b"info"]

        file_names = []

        if is_folder:
            for item in metadata[b"info"][b"files"]:
                try:
                    file_names.append(item[b"path"][0].decode("utf-8"))
                except IndexError:
                    pass
        else:
            file_names.append(metadata[b"info"][b"name"].decode("utf-8"))

        return file_names
Beispiel #9
0
def handle(request):
    logging.warning('Tracker connection received!')

    def create_sock(_peer, ip):
        server = yield from loop.create_server(lambda: TorrentProxy(_peer), ip, 0)
        port = server.sockets[0].getsockname()[1]
        return port

    ip = request.GET['ip'] if ip in request.GET else '127.0.0.1'

    port = yield from create_sock({ 
        'ip': ip,
        'port': request.GET['port'] 
    }, '0.0.0.0')

    path = request.path_qs.replace('port={}'.format(request.GET['port']),
        'port={}'.format(port))

    r = yield from aiohttp.get(sys.argv[1] + path)
    data = yield from r.read()
    yield from r.release()

    torrent = bencodepy.decode(data)
    proxied_peers = []

    base_ip = ip2int('127.13.37.0')
    for index, peer in enumerate(decode_peers(torrent[b'peers'])):
        ip = int2ip(base_ip + index)
        port = yield from create_sock(peer, ip) 
        proxied_peers.append({ 'ip': ip, 'port': port })
        logging.info('Opened listener on {}'.format(port))

    torrent[b'peers'] = encode_peers(proxied_peers)

    return web.Response(body=bencodepy.encode(torrent))
Beispiel #10
0
def peers_b2l(response):
    """
    Parse the response fron tracker, dig out the peers addresses
    :param response: binary data, response from the tracker
    """
    if response == b'':
        raise ValueError('No data returned')

    data = b.decode(response)
    lst = list()

    if not isinstance(data[b'peers'], bytes):
        raise TypeError('Peer list is {0}'.format(data[b'peers']))

    # parse the response
    for offset in range(0,len(data[b'peers']), 6):
        # all data are stored as big endian
        # dig out the IP address (integer)
        raw_ip = s.unpack_from(">i", data[b'peers'], offset)[0]
        ip = socket.inet_ntoa(s.pack(">i", raw_ip))

        # do the same for the port number (insigned short)
        port = s.unpack_from(">H", data[b'peers'], offset+4)[0]

        lst.append('{0}:{1}'.format(ip, port))

    return lst
Beispiel #11
0
def get_torrent_stats(url):
    response = requests.get(url)
    data = bencodepy.decode(response.content)
    files = data[b'info'][b'files']
    size = 0
    for file in files:
        size += file[b'length']
    size = size * 1e-9
    size = round(size, 2)
    info_hash = hashlib.sha1(bencodepy.bencode(data[b"info"])).hexdigest()

    trackers_list = data[b'announce-list']

    stats = {'seeds': 0, 'peers': 0}

    for tracker_url in trackers_list:
        tracker_url = tracker_url[0].decode('utf-8')
        result = scrape(tracker_url, [info_hash])
        if not result:
            continue
        if result[info_hash]['seeds'] is None or result[info_hash][
                'peers'] is None:
            continue
        stats['seeds'] = max(stats['seeds'], result[info_hash]['seeds'])
        stats['peers'] = max(stats['peers'], result[info_hash]['peers'])
    stats['size_gb'] = size
    return stats
Beispiel #12
0
def spawn(url):
    torrent_url_components = urlparse(url)
    torrent_url_query = torrent_url_components.query
    match = re.search('ref=(.*)', torrent_url_query)
    if match is None:
        pass
    else:
        torrent_file = str(match.groups(0)[0]) + '.torrent'
        blob = download_torrent(url)
        dbx = dropbox.Dropbox(
            'JUEnSrL_pnAAAAAAAAAADGNPxjjbk3nYLnatbTN8vvJ01JM8yQIhn-MI5DqW41nR')
        path = '/torrents/%s' % torrent_file
        dbx.files_upload(blob, path)
        link = dbx.sharing_create_shared_link_with_settings(path).url
        link = re.sub('dl=0', 'dl=1', link)
        try:
            metainfo = decode(blob)
            info = metainfo[b'info']
            btih = hashlib.sha1(encode(info)).hexdigest()
            dn = metainfo[b'info'][b'name']
            magnet = 'magnet:?xt=urn:btih:{btih}&dn={dn}'.format(btih=btih,
                                                                 dn=dn)
            torrent = {'status': 'OK', 'magnet': magnet, 'torrent': link}
            r.hmset(url, torrent)
            record_event({'type': 'aisex.newtorrent'})
        except:
            torrent = {'status': 'ERROR', 'error': 'not a valid torrent file'}
        return torrent
Beispiel #13
0
def get_peers_from_tracker(announce, torrent_data, http=True) -> list:
    if http:
        response = connect_to_http_tracker(announce, torrent_data)
    else:
        transaction_id = get_udp_transaction_id()  # randomized transaction ID for UDP
        response = connect_to_udp_tracker(announce, torrent_data, transaction_id)

    if response == b'':
        log('Response of tracker was empty', 2)
        return []  # if error has occurred empty list of peers will be returned

    if http:
        # response from tracker is bencoded binary representation of peers addresses will be parsed to readable form
        decoded = bencodepy.decode(response)
        if not decoded:
            log("Decoded response is empty", 1)
            return []
        elif b'peers' not in decoded:
            log("Decoded response has no peers data in it", 1)
            return []
        bin_peers = decoded[b'peers']
    else:
        bin_peers = parse_udp_announce_response(response, transaction_id)

    log("There should be %u peers" % (len(bin_peers) / 6), 1)
    peers = []

    # bin peers data is field of bytes, where each 6 bytes represent one peer
    # for each peer will be appended to peers list
    for i in range(0, len(bin_peers), 6):
        peers.append(parse_bin_peer(bin_peers[i:i + 6]))
    return peers
Beispiel #14
0
    def _receiver(self):
        logger = logging.getLogger("btdht")
        logger.info("Receiver thread started.")
        while self.running:
            try:
                data = self.sock.recv(4096)
            except OSError:
                time.sleep(SLEEP_QUANTUM)
                continue

            try:
                recvd = bencodepy.decode(data)
                if recvd[b'y'] == b'r':
                    tid = recvd[b't']

                    response = recvd[b'r']

                    with self.lock:
                        try:
                            req = self.requests[tid]
                        except KeyError:
                            logger.info("Received response to unknown request.")
                        else:
                            del self.requests[tid]

                            if req.type == REQUEST_TYPE_FIND_NODE:
                                if self.ipv == 'ip4':
                                    nodes = parse_compact_node_info(response[b'nodes'])
                                else:
                                    nodes = parse_compact_node6_info(response[b'nodes6'])

                                for node in nodes:
                                    addr = node['addr']
                                    nodeid = node['id']

                                    # if the unique option is enabled, ignore duplicates
                                    if self.unique is not None:
                                        if addr[0] in self.unique:
                                            continue
                                        self.unique.add(addr[0])

                                    self.addr_cache.put((addr, nodeid))
                                    self.requests_success += 1

                                    if len(self.addr_pool) > 100:
                                        self.addr_pool.popleft()
                                    self.addr_pool.append(addr)
                            else:
                                logger.info("Unknown request type: {}. Seems like I've created a Request record with a unexpected request type.".format(req.type))
            except bencodepy.DecodingError:
                logger.info("bencode decoding of incoming packet failed.")
            except KeyError:
                logger.info("Malformed? packet received.")
            except Exception:
                logger.exception("Unknown error happened during response handling.")


        logger.info("Shutting down receiver.")
        self.sock.close()
Beispiel #15
0
 def read_metadata_from_file(self):
     """
     Read a .torrent file and decode metadata.
     :return: None
     """
     with open(self.file_path, 'rb') as f:
         self.metadata = bencodepy.decode(f.read())
     self.metadata = utils.dict_to_utf8(self.metadata)
Beispiel #16
0
 def loadb(self, b: bytes, options: dict) -> Any:
     kwargs = {}
     kwargs.update(Options.pop_origin_kwargs(options))
     self.check_options(options)
     try:
         return bencodepy.decode(b, **kwargs)
     except bencodepy.BencodeDecodeError as e:
         raise SerializeError(e)
Beispiel #17
0
def parseTorrent(fd):
    """
    parse a torrent from a file descriptor
    return dict that was bencoded
    will raise of parse error
    """
    data = fd.read()
    return bencodepy.decode(data)
Beispiel #18
0
    def __init__(self, filepath):
        self.file = filepath

        with open(self.file, 'rb') as f:
            self.meta_info = f.read()
            self.meta_info = bencodepy.decode(self.meta_info)
            info = bencodepy.encode(self.meta_info[b'info'])
            self.info_hash = sha1(info).digest()
            self.count_files()
Beispiel #19
0
 def run(self):
     self.re_join_DHT()
     while True:
         try:
             (data, address) = self.ufd.recvfrom(65536)
             msg = decode(data)
             self.on_message(msg, address)
         except Exception:
             pass
Beispiel #20
0
    def cleanup_torrentsdir(self, torrents_dir, dryrun: bool):
        try:
            tor_filenames = os.listdir(torrents_dir)
        except FileNotFoundError:
            echo(f'unable list file from {torrents_dir!r}.')
            return

        class _FileEntry:
            def __init__(self, name: str) -> None:
                self.name = name
                self.info_hash: str = None
                self.torrents = []

            @property
            def path(self):
                return os.path.join(torrents_dir, self.name)

        # get files from disk before get torrents from transmission
        # ensure no new torrents will be delete.
        file_entries: Dict[str, _FileEntry] = {}
        file_entries_by_infohash: Dict[str, List[_FileEntry]] = {}

        for name in tor_filenames:
            assert name not in file_entries
            file_entries[name] = fe = _FileEntry(name)

            path = os.path.join(torrents_dir, name)
            with open(path, 'rb') as f:
                tor_body = bencodepy.decode(f.read())
            magnet_info = tor_body.get(b'magnet-info')
            if magnet_info:
                # this is a magnet
                info_hash: str = magnet_info[b'info_hash'].hex()
            else:
                info_hash: str = compute_info_hash(tor_body)
            info_hash = info_hash.lower()

            fe.info_hash = info_hash
            file_entries_by_infohash.setdefault(info_hash, []).append(fe)
        echo(f'read {len(file_entries)} torrents from torrents dir.')

        drift_torrents = []
        torrents = self.tc.get_torrents(
            arguments=['id', 'hashString', 'torrentFile'])
        for tor in torrents:
            assert isinstance(tor.torrentFile, str)
            info_hash = tor.hashString.lower()
            tfn = os.path.basename(tor.torrentFile)
            fe = file_entries.get(tfn)
            if fe:
                fe.torrents.append(tor)
            else:
                if len(fels := file_entries_by_infohash.get(info_hash, (
                ))) == 1:
                    fels[0].torrents.append(tor)
                else:
                    drift_torrents.append(tor)
Beispiel #21
0
 def run(self):
     self.re_join_dht()
     while True:
         try:
             (data, address) = self.socket.recvfrom(PACKET_SIZE)
             msg = bencodepy.decode(data)
             self.process_message(msg, address)
         except Exception:
             pass
Beispiel #22
0
def peer_tracker():
    with open("./file.torrent", "rb") as f:
        raw_data = f.read()
        data = bc.decode(raw_data)
        print(data.keys())
    info_hash = hashlib.sha1(bc.bencode(data[b"info"])).hexdigest()
    print(data[b"announce-list"])

    return info_hash
Beispiel #23
0
 def run(self):
     self.re_join_dht()
     while True:
         try:
             (data, address) = self.socket.recvfrom(PACKET_SIZE)
             msg = bencodepy.decode(data)
             self.process_message(msg, address)
         except Exception:
             pass
Beispiel #24
0
	def run(self):
		self.re_join_DHT()
		while True:
			try:
				data, address = self.sock.recvfrom(65536)
				message = decode(data)
				self.on_message(message, address)
			except Exception as error:
				pass
Beispiel #25
0
    def handle_announce_response(self, http_resp):
        resp = bencodepy.decode(http_resp.text.encode('latin-1'))
        d = self.decode_announce_response(resp)

        # TODO: use 'interval', 'tracker id', 'complete', 'incomplete'

        for peer_dict in d['peers']:
            # TODO: raise error or warning on port = 0?
            if peer_dict['ip'] and peer_dict['port'] > 0:
                self.torrent.add_peer(peer_dict)
Beispiel #26
0
    def parse_tracker_response(self, content):
        resp = bencodepy.decode(content)
        split_peers = [
            resp[b'peers'][i:i + 6] for i in range(0, len(resp[b'peers']), 6)
        ]

        peers = [(socket.inet_ntoa(p[:4]), _decode_port(p[4:]))
                 for p in split_peers]
        return TrackerResponse(resp[b'complete'], resp.get(b'crypto_flags'),
                               resp.get(b'incomplete'), resp.get(b'interval'),
                               peers)
Beispiel #27
0
 def make_request_to_tracker(self):
     """
     Makes the GET request to the tracker
     :return: Decoded response content
     """
     raw_response = requests.get(self.torrent.metadata['announce'], params=self.params)
     print('status code: ', raw_response.status_code)
     if raw_response.status_code != 200:
         raise ConnectionError(f'Couldn\'t connect to tracker: {raw_response.status_code}')
     self.response = bencodepy.decode(raw_response.content)
     return self.response
Beispiel #28
0
 def torrentToMagnet(cls, torrentByte):
     try:
         metadata = bencodepy.decode(torrentByte)
         subj = metadata[b'info']
         hashcontents = bencodepy.encode(subj)
         digest = hashlib.sha1(hashcontents).digest()
         b32hash = base64.b32encode(digest).decode()
         return 'magnet:?' \
                + 'xt=urn:btih:' + b32hash
     except:
         return ""
Beispiel #29
0
    def handle_announce_responce(self, http_resp):
        resp = bencodepy.decode(http_resp.text.encode('latin-1'))
        d = self.decode_announce_response(resp)

        peer_list = d['peers']
        return peer_list
        for peer_dict in d['peers']:
            # TODO: raise error or warning on port = 0?
            if peer_dict['ip'] and peer_dict['port'] > 0:
                # print(peer_dict)
                self.torrent.add_peer(peer_dict)
Beispiel #30
0
 def run(self):
     """
     Wait for DHT responses and query the parser if it seems valid.
     """
     while True:
         try:
             (data, address) = self.ufd.recvfrom(65536)
             msg = bencodepy.decode(data)
             if msg[b'y'] == b'r':
                 self.parse_response(msg, address)
         except Exception:
             pass
Beispiel #31
0
    async def work(self):

        self.writer.write(BT_HEADER + self.infohash + self.peer_id)
        print(172)
        while True:
            if not self.handshaked:
                print(175)
                if self.check_handshake(await self.reader.readexactly(68)):
                    self.handshaked = True
                    # Send EXT Handshake
                    self.write_message(EXT_HANDSHAKE_MESSAGE)
                else:
                    return self.close()

            total_message_length, msg_id = struct.unpack(
                "!IB", await self.reader.readexactly(5))
            # Total message length contains message id length, remove it
            payload_length = total_message_length - 1
            payload = await self.reader.readexactly(payload_length)

            if msg_id != EXT_ID:
                continue
            extended_id, extend_payload = payload[0], payload[1:]
            if extended_id == 0 and not self.ut_metadata:
                # Extend handshake, receive ut_metadata and metadata_size
                try:
                    self.ut_metadata = get_ut_metadata(extend_payload)
                    self.metadata_size = get_metadata_size(extend_payload)
                except:
                    return self.close()
                self.pieces_num = math.ceil(self.metadata_size / BLOCK)
                self.pieces = [False] * self.pieces_num
                self.request_piece(0)
                continue

            try:
                split_index = extend_payload.index(b"ee") + 2
                info = decode(extend_payload[:split_index])
                if info[b'msg_type'] != MessageType.DATA:
                    return self.close()
                if info[b'piece'] != self.pieces_received_num:
                    return self.close()
                self.pieces[info[b'piece']] = extend_payload[split_index:]
            except:
                return self.close()
            self.pieces_received_num += 1

            if self.pieces_received_num == self.pieces_num:
                # return self.pieces_complete()
                loop = asyncio.get_event_loop()
                loop.create_task(self.pieces_complete())
            else:
                self.request_piece(self.pieces_received_num)
Beispiel #32
0
    def validateRSS(self):

        try:
            if self.cookies:
                success, status = self.add_cookies_from_ui()
                if not success:
                    return False, status

            # Access to a protected member of a client class
            data = self.cache._get_rss_data()['entries']
            if not data:
                return False, 'No items found in the RSS feed {0}'.format(
                    self.url)

            title, url = self._get_title_and_url(data[0])

            if not title:
                return False, 'Unable to get title from first item'

            if not url:
                return False, 'Unable to get torrent url from first item'

            if url.startswith('magnet:') and re.search(
                    r'urn:btih:([\w]{32,40})', url):
                return True, 'RSS feed Parsed correctly'
            else:
                torrent_file = self.get_url(url, returns='content')
                try:
                    bencodepy.decode(torrent_file)
                except (bencodepy.exceptions.BencodeDecodeError,
                        Exception) as error:
                    self.dumpHTML(torrent_file)
                    return False, 'Torrent link is not a valid torrent file: {0}'.format(
                        error)

            return True, 'RSS feed Parsed correctly'

        except Exception as error:
            return False, 'Error when trying to load RSS: {0}'.format(
                str(error))
Beispiel #33
0
    def handle_tracker_response(self):
        print("Raw Response: ", self.response)
        #decoded_response = self.response.decode('utf-8')
        #print("Decoded Response: ", decoded_response)
        split_decoded = self.response.split(b'\r\n\r\n')
        response_dict = decode(split_decoded[1])
        print("Tracker response: ", response_dict)

        #check for failure reason
        if b'failure reason' in response_dict:
            print(response_dict[b'failure reason'].decode('utf-8'))

        else:
            self.interval = response_dict[b'interval']
            #self.tracker_id = response_dict[b'tracker id']
            self.complete = response_dict[b'complete']
            self.incomplete = response_dict[b'incomplete']

            #parse list of peers
            peerlist = list()
            unparsed_peers = response_dict[b'peers']
            print(unparsed_peers)

            #add peers to list of tuples (IP, port)
            for x in range(len(unparsed_peers) // 6):
                ip = socket.inet_ntoa(unparsed_peers[x * 6:x * 6 + 4])
                port = int.from_bytes(unparsed_peers[x * 6 + 4:x * 6 + 6],
                                      byteorder='big')
                #print("Reading peer ", ip, port)
                peerlist.append((ip, port))

            print(peerlist)
            self.peer_list = peerlist

            #for each peer in peer list, check if connected
            for (IP, port) in self.peer_list:
                #print(self.ip_addr, IP, self.ip_addr != IP)
                #print(self.port, port, self.port != port)
                if (IP != self.ip_addr) or (port != self.port):
                    for connection in self.connection_list:
                        if (IP == connection.peer_ip_addr) and (
                                port == connection.peer_port):
                            break
                    else:
                        #if not connected, initiate handshake with peer
                        print("Connect to peer ", IP, port)
                        handshake_thread = threading.Thread(
                            target=self.initiate_handshaking, args=(IP, port))
                        handshake_thread.daemon = True
                        handshake_thread.start()

                        handshake_thread.join()
Beispiel #34
0
    def from_data(cls, data: bytes, **kwargs):
        # TODO: refactor from_{data,filename}

        dictionary = cast(OrderedDict, bencodepy.decode(data))
        download_info = DownloadInfo.from_dict(dictionary[b'info'])

        if b'announce-list' in dictionary:
            announce_list = [[url.decode() for url in tier]
                             for tier in dictionary[b'announce-list']]
        else:
            announce_list = [[dictionary[b'announce'].decode()]]

        return cls(download_info, announce_list, **kwargs)
Beispiel #35
0
def main():
    arg = ArgumentParser.ArgumentParser()
    arg.do_parsing()
    torrent_dict = decode_from_file(os.getcwd() + "\\" + arg.torrent_file_url)
    info_dict = torrent_dict[b"info"]
    piece_length = info_dict[b"piece length"]
    piece_count = int(len(info_dict[b"pieces"])/20)
    file_name = info_dict[b"name"]
    file_name = file_name.decode("utf-8")
    if b"files" in info_dict:
       print(info_dict[b"files"])
    global chunk_number
    chunk_number = int(piece_length/chunk_size)
    if piece_length % chunk_size != 0:
        chunk_number += 1
    global pieces_bitfield
    pieces_bitfield = [None] * piece_count
    global currently_used
    currently_used = [False] * piece_count
    dictionary_sha1 = helper.get_sha1(encode(info_dict))
    bencoded_info_dict = encode(info_dict)
    info_hash = helper.get_sha1(bencoded_info_dict)
    peer_id = os.urandom(20)
    listen_port = 2710
    file_length = info_dict[b"length"]
    payload = {"info_hash": info_hash, "peer_id": peer_id,
               "port": listen_port, "uploaded": 0, "downloaded": 0, "left": file_length}
    r = requests.get(torrent_dict[b"announce"], params=payload)
    response = decode(r.content)
    if b"failure reason" in response:
        return
    interval = response[b"interval"]
    peers = response[b"peers"]
    peers_list = []
    peer_num = len(peers)/6
    for elem in range(int(peer_num)):
        start_ind = 6 * elem
        peer_ip = socket.inet_ntoa(peers[start_ind:start_ind+4])
        peer_port = struct.unpack("!H", peers[start_ind+4:start_ind+6])[0]
        peers_list.append((peer_ip, peer_port))
    print(peers_list)
    for elem in peers_list:
        test_ip = elem[0]
        test_port = elem[1]
        cur_thread = Thread(target=do_for_each_peer,
                            args=(dictionary_sha1, test_ip, test_port, piece_length, info_dict, peer_id, file_length,
                                  file_name))
        # do_for_each_peer(dictionary_sha1, test_ip, test_port, piece_length, info_dict,peer_id)
        # print(cur_thread.name)
        cur_thread.start()
Beispiel #36
0
 def request_torrent_information(self):
     # try establishing a connection to the tracker
     try:
         # the reponse from HTTP tracker is an bencoded dictionary 
         bencoded_response = requests.get(self.tracker_url, self.request_parameters, timeout=5)
         # decode the bencoded dictionary to python ordered dictionary 
         raw_response_dict = bencodepy.decode(bencoded_response.content)
         # parse the dictionary containing raw data
         self.parse_http_tracker_response(raw_response_dict)
         return True
     except Exception as error_msg:
         # cannont establish a connection with the tracker
         self.tracker_logger.log(self.tracker_url + ' connection failed !' + FAILURE) 
         return False
Beispiel #37
0
 def datagram_received(self, data, addr):
     try:
         msg = bencodepy.decode(data)
     except:
         return
     try:
         self.handle_message(msg, addr)
     except Exception as e:
         self.send_message(data={
             "t": msg["t"],
             "y": "e",
             "e": [202, "Server Error"]
         },
                           addr=addr)
         raise e
Beispiel #38
0
    async def get_magnet(self, location: str) -> str:
        """
        Will take an internet location for a torrent file.
        The magnet URL for that torrent is then resolved and returned.

        If the location parameter is already detected to be a magnet URL,
        it will instantly return it.

        Parameters
        ----------
        location: str
            A file location or web address.

        Returns
        -------
        str
            The magnet URL for the torrent at the given location.
        """
        pattern = re.compile(r"\burn:btih:([A-z\d]+)\b")

        def b32_to_sha1(match: re.Match) -> str:
            hash_ = match.group(1)
            if len(hash_) == 40:
                return match.group(0)
            elif len(hash_) == 32:
                return "urn:btih:" + base64.b32decode(hash_.upper()).hex()

            return match.group(0)

        if location.startswith("magnet:?"):
            return re.sub(pattern, b32_to_sha1, location)
        else:
            async with self.session.get(location) as resp:
                torrent_bytes = await resp.read()
                metadata = bencodepy.decode(torrent_bytes)

        subject = metadata[b'info']

        hash_data = bencodepy.encode(subject)
        digest = hashlib.sha1(hash_data).hexdigest()

        magnet_url = ("magnet:?"
                      f"xt=urn:btih:{digest}"
                      f"&dn={metadata[b'info'][b'name'].decode()}"
                      f"&tr={metadata[b'announce'].decode()}")

        return re.sub(pattern, b32_to_sha1, magnet_url)
Beispiel #39
0
def create_magnet_uri(data: bytes):
    # noinspection PyTypeChecker
    metadata: dict = bencodepy.decode(data)
    subj = metadata[b'info']
    hashcontents = bencodepy.encode(subj)
    digest = hashlib.sha1(hashcontents).digest()
    b32hash = base64.b32encode(digest).decode()
    magnet_uri = 'magnet:?' + 'xt=urn:btih:' + b32hash
    if b"announce" in metadata:
        magnet_uri += ('&tr=' + metadata[b'announce'].decode())
    if b"info" in metadata:
        metadata_info = metadata[b'info']
        if b"name" in metadata_info:
            magnet_uri += ('&dn=' + metadata[b'info'][b'name'].decode())
        if b"length" in metadata_info:
            magnet_uri += ('&xl=' + str(metadata[b'info'][b'length']))
    return magnet_uri
Beispiel #40
0
 def __init__(self, file_name):
     """参数定义"""
     self.announce = None  # Tracker服务器地址
     self.info = None  # torrent文件中的info0字节内容
     self.info_hash = None  # info字节内容的sha1 hash值
     self.name = None  # 资源若为单个资源文件,则为文件名称,若为资源文件夹,则为最顶层目录名称
     """读取torrent文件内容"""
     with open(file_name, 'rb') as f:
         content = f.read()
     content = bencodepy.decode(content)
     self.announce = content[b'announce'].decode('utf-8')
     self.announce_list = [
         t.decode('utf-8')
         for t in self.parse_list(content[b'announce-list'])
     ]
     self.info = self._decode_info_dict(content[b'info'])
     self.info_hash = hashlib.sha1(bencodepy.encode(
         content[b'info'])).digest()
Beispiel #41
0
    def get_peers_ips(self):
        root_url = self.torrent_dict[b'announce'].decode()
        if validators.url(root_url):
            request_params = self.create_tracker_params()
            response = make_get_request(root_url, request_params)
            if response.code == 200:
                response_body = response.read()
                if b'failure reason' not in response_body:
                    response_dict = bencodepy.decode(response_body)
                    return calculate_peers(response_dict[b'peers'])
                else:
                    raise Exception("Failure connecting to Tracker")
            else:
                raise Exception("Can't connect to Tracker")

        else:
            raise Exception("Not valid tracker url in torrent file.\n"
                            "Can't connect to Tracker!")
Beispiel #42
0
def initialise_variables(torrent_file_name):
    modules.multi_torrent_flag = False
    modules.temp_name = ""
    torr = open(torrent_file_name, "rb")
    _dic = decode(torr.read())
    modules.hash_string = _dic[b"info"][b"pieces"]
    modules.file_name = _dic[b"info"][b"name"].decode()
    modules.total_size = 0
    if b"files" in _dic[b"info"].keys():
        modules.multi_torrent_flag = True
        modules.temp_name = "TEMP"
        ls = _dic[b"info"][b"files"]
        # input(ls)
        files_details = []
        for e in ls:
            modules.total_size += e[b"length"]
            files_details.append((e[b"path"][0].decode(), e[b"length"]))
        modules.files_details = files_details
        # input(modules.files_details)
    else:
        modules.total_size = _dic[b"info"][b"length"]

    modules.total_pieces = len(modules.hash_string) // 20
    modules.piece_len = _dic[b"info"][b"piece length"]
    tr = encode(_dic[b"info"])
    modules.hashes = [hashlib.sha1(tr).hexdigest()]

    ty = _dic[b"announce-list"]
    modules.trackers = []
    for i in range(len(ty)):
        a = []
        url = ty[i][0].decode()
        a.append(url)
        modules.trackers.append(a)

    modules.recieved_data = [0 for _ in range(modules.total_pieces)]
    modules.bitfield = [0 for _ in range(modules.total_pieces)]
    while len(modules.bitfield) % 8 != 0:
        modules.bitfield.append(0)

    modules.connected_peers = []
    modules.download_rates = defaultdict(lambda: 0)
    modules.upload_rates = defaultdict(lambda: 0)
    modules.end_all_threads = False
Beispiel #43
0
 def datagramReceived(self, data, addressPort):
     (address, port) = addressPort
     print("Datagram %s received from %s" % (repr(data), repr((address, port))))
     
     data = bencodepy.decode(data)
     if data[b'y'] == b'r' and data[b't'] == b'42':
         token = data[b'r'][b'token']
         newData = {
             'y': 'q',
             'q': 'announce_peer',
             'a': {
                 'id': hashlib.sha1(b'bla').digest(),
                 'info_hash': hashlib.sha1(b'someTorrent').digest(),
                 'port': 8046,
                 'token': token
             },
             't': b'43'
         }
         
         self.transport.write(bencodepy.encode(newData), ('127.0.0.1', 8043))
         
         print("Sent announce")
Beispiel #44
0
def fetch_metadata(nid, infohash, address, timeout=5):
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.settimeout(timeout)
        s.connect(address)

        # handshake
        handshake(s, nid, infohash)
        msg = s.recv(4096)

        # verification
        if not check_handshake_response(msg, infohash):
            return

        # advertize to support ut_metadata(BEP-09)
        ext_handshake(s)
        msg = s.recv(4096)

        ut_metadata, metadata_size = decode_ext_handshake_msg(msg)
        #print("ut_metadata", ut_metadata, "metadata_size", metadata_size)

        metadata = []
        piece_tot = int(ceil(metadata_size / (1024 * 16)))
        for i in range(piece_tot):
            send_request_metadata(s, ut_metadata, i)
            piece = recv_piece(s, timeout)
            metadata.append(piece)

        metadata = bencodepy.decode(b"".join(metadata))
        print(metadata[b"name"].decode(), "size", get_length(metadata))
    except socket.timeout:
        pass
    except Exception as e:
        #print(e)
        pass
    finally:
        if s:
            s.close()
Beispiel #45
0
def get_hash(binary):
	decoded_data = bencodepy.decode(binary)
	decoded_info = decoded_data[b'info']
	encoded_info = bencodepy.encode(decoded_info)
	torrent_hash = hashlib.sha1(encoded_info).hexdigest()
	return torrent_hash
def bdecode(data):
    return bencodepy.decode(data)
Beispiel #47
0
    def find_new(self):
        # find our shows
        builtins = ('daemon', 'transmission', 'defaults', 'tvdb')
        shows = [s for s in self.config.sections() if s not in builtins]
        defaults = self.config.items('defaults', SHOW_DEFAULTS)

        for cfg_name in shows:
            show = self.config.items(cfg_name, defaults)
            show['name'] = show.get('name', cfg_name)
            show['feed_search'] = show.get('feed_search', show['name'])
            log.debug('Looking up %s' % show['feed_search'])

            # if we're at downloading max_concurrent episodes, then stop
            # processing this show
            max_concurrent = int(show.get('max_concurrent'))
            c = self.db.cursor()
            c.execute(
                'select count(*) from shows where cfg_name=? and status=?',
                (cfg_name, STATUS_INCOMPLETE)
            )
            count = c.fetchone()[0]
            if count >= max_concurrent:
                log.debug(
                    'Reached maximum concurrent torrents (%d) for "%s".' % (
                        max_concurrent, cfg_name)
                )
                continue

            # Get the show data from TVDB
            if show.get('tvdb_id'):
                try:
                    tvdb_show = self.tvdb.get(show['tvdb_id'], self.tvdb_lang)
                except tvdb_error.TVDBIdError:
                    result = []
            else:
                result = self.tvdb.search(show['name'], self.tvdb_lang)
                if not len(result):
                    log.error('Show not found on tvdb: %s' % show['name'])
                    continue

                if len(result) > 1:
                    log.warning('Multiple matches found for "{r.search}"'
                                .format(r=result))

                tvdb_show = result[0]
            try:
                # if show has a season 0 (extras), don't count it in the total
                # number of seasons.
                tvdb_show[0]
            except tvdb_error.TVDBIndexError:
                num_seasons = len(tvdb_show)
            else:
                num_seasons = len(tvdb_show) - 1

            if num_seasons <= 0:
                log.error('No seasons found for "{r.search}"'.format(r=result))
                continue

            # Get last downloaded season from the database to see which season
            # to start with. If no downloads, use start_season
            c = self.db.cursor()
            c.execute(
                'select max(season) from shows where cfg_name=?', (cfg_name,))
            max = c.fetchone()[0]
            start_season = max or show['start_season']

            # load torrent feeds one season at a time, since the feed only
            # returns a max of 30 shows.
            entries = []
            for season in range(int(start_season), num_seasons + 1):
                # load rss feed:
                feed_params = {
                    'mode': 'rss',
                    'show_name': show['feed_search'],
                    'quality': show.get('quality'),
                    'season': season
                }
                if show.get('feed_search_exact', 'false').lower() != 'false':
                    feed_params['show_name_exact'] = 'true'

                show_feed_url = feed_url + '?' + urlencode(feed_params)
                log.debug('checking feed url: %s' % show_feed_url)
                feed = feedparser.parse(show_feed_url)

                log.debug('found %d entries for %s, season %s' %
                          (len(feed['entries']), show['name'], season))

                # assume that feed has given episodes sorted by seed quality,
                # and maintain that order.
                for i, e in enumerate(feed['entries']):
                    feed['entries'][i]['ord'] = i

                # sort feed entries by episode
                def ordkey(ep):
                    summary = self._parse_summary(ep['summary'])
                    return summary['episode'] * 100 + ep['ord']
                entries += sorted(feed['entries'], key=ordkey)

                eps = [self._parse_summary(e['summary'])['episode']
                       for e in entries]
                log.debug('   Found episodes: {}'
                          .format(str([int(s) for s in set(eps)])))

            added = 0
            for entry in entries:
                if count >= max_concurrent:
                    log.info(
                        'Reached maximum concurrent torrents (%d) for this '
                        'show "%s".' % (max_concurrent, cfg_name))
                    break

                link = entry['link']
                summary = entry['summary']

                # parse summary details (assuming ezrss keeps this consistent)
                # ex: 'Show Name: Dexter; Episode Title: My Bad; Season: 5;
                # Episode: 1'
                info = self._parse_summary(summary)
                log.debug(
                    'Found: %(show_name)s: Season: %(season)s; '
                    'Episode: %(episode)s; Title: %(title)s' % info
                )

                season = int(info['season'])
                episode = int(info['episode'])

                # skip if less than start_episode. eg, s04e06 would be 406
                e2n = lambda s, e: int(s) * 100 + int(e)
                start_ssn = show['start_season']
                start_ep = show['start_episode']
                if (e2n(season, episode) < e2n(start_ssn, start_ep)):
                    log.debug(
                        'Skipping, s%02de%02d is earlier than start_episode'
                        % (season, episode))
                    continue

                # Check and see if we need this episode
                c = self.db.cursor()
                c.execute(
                    'SELECT COUNT() FROM shows WHERE cfg_name=? '
                    'AND season=? AND episode=?', (cfg_name, season, episode)
                )
                if c.fetchone()[0] > 0:
                    # already have this one, or are already downloading it.
                    log.debug(
                        '"%(show_name)s-%(season)s-%(episode)s" has already '
                        'been downloaded or is currently downloading' % info
                    )
                    continue

                # Get torrent file so that we can parse info out of it
                log.debug('Decoding torrent...')
                try:
                    request = Request(link)
                    request.add_header('Accept-encoding', 'gzip')
                    response = urlopen(request)
                except HTTPError as e:
                    log.debug('Could not download torrent: %s, %s' % (link, e))
                    continue

                if response.info().get('Content-Encoding') == 'gzip':
                    buf = io.BytesIO(response.read())
                    f = gzip.GzipFile(fileobj=buf)
                    data = f.read()
                else:
                    data = response.read()

                try:
                    torrent = bencodepy.decode(data)
                except DecodingError as e:
                    log.debug(str(e))
                    log.error('Could not parse torrent: %s' % link)
                    continue

                filename = torrent[b'info'].get(b'name').decode()
                if not filename:
                    files = torrent[b'info'][b'files']
                    # get largest file
                    files = sorted(
                        files, key=lambda f: f['length'], reverse=True)
                    filename = files[0]['path']

                ext = os.path.splitext(filename)[1][1:]
                if ext in show['exclude_extensions'].split(','):
                    log.debug(
                        'Skipping %s, file extension blacklisted' % filename)
                    continue

                # Add the show
                added += 1
                log.info(
                    'Adding %(show_name)s-%(season)s-%(episode)s to '
                    'transmission queue' % info)
                log.debug(link)
                b64_data = base64.b64encode(data).decode()
                try:
                    trans_info = self.transmission.add_torrent(b64_data)
                except transmissionrpc.error.TransmissionError as e:
                    if '"duplicate torrent"' in str(e):
                        log.info('Torrent already exists. Resuming.')
                        # TODO: Find the duplicate torrent
                        binfo = bencodepy.encode(torrent[b'info'])
                        hash = hashlib.sha1(binfo)
                        trans_info = self.transmission.inf(hash.hexdigest())
                        self.transmission.start(trans_info.id)
                    else:
                        raise

                # Record in db
                c = self.db.cursor()
                show_name = tvdb_show.SeriesName
                try:
                    title = tvdb_show[season][episode].EpisodeName
                except (tvdb_error.TVDBIndexError, KeyError):
                    title = info.get('title', '(no title)')
                c.execute(
                    'INSERT INTO shows (name, season, episode, title, status, '
                    'url, transid, cfg_name) VALUES (?, ?, ? ,? ,? ,?, ?, ?)',
                    (show_name, season, episode, title, STATUS_INCOMPLETE,
                     link, trans_info.id, cfg_name)
                )
                self.db.commit()
                count += 1

            if added == 0:
                log.info('No new episodes found for %s' % cfg_name)
Beispiel #48
0
    def get_torrent(self, url):
        """Downloads a torrent file, if it hasn't already been d/led

        Note that this function does NOT check in the DB for existence!
        Verification of that should be done prior, by calling
        start_process().  This function assumes you know you want to
        try to download the torrent file, and only checks for existence
        on disk of the path specified in the torrent.  The reason for this
        is to allow for logic between checking if the URL was processed
        and actually downloading the torrent file, on a per-caller
        basis.  If these two steps were combined, every torrent would
        be downloaded from every tracker RSS feed every time this is
        called, which generates far too many useless, duplicate requests

        url - `string` with URL of the torrent file to get

        Returns `bool` indicating whether torrent was downloaded (true)
        or skipped due to pre-existence (false)
        """
        headers = {'User-Agent':'Mozilla/4.0 (compatible;MSIE 5.5;Windows NT)'}

        req = urllib.request.Request(url, headers=headers)
        resp = urllib.request.urlopen(req)
        torrent = resp.read()
        torrent_data = decode(torrent)

        # Extract the base directory from the torrent file to check for
        # duplicates.
        #
        # Per the torrent spec, the 'name' field in multi-file
        # torrents is advised to contain the name of the directory
        # containing all of the data files.
        #
        # https://wiki.theory.org/BitTorrentSpecification
        torrent_path = torrent_data[b'info'][b'name'].decode(encoding='UTF-8')

        # Check incomplete and complete dirs for path
        # Slight TOCTOU race condition here...  But I don't care
        found = False
        if self.check_dupey:
            for d in self.dupey_dirs:
                if os.path.exists('%s%s%s' % (d, os.sep, torrent_path)):
                    found = True

        # Now check the DB for this path.... This can happen if two
        # torrents exist on the same server with the same path...
        cursor = self.db.cursor()
        cursor.execute("SELECT path FROM dls WHERE path=?", (torrent_path,))
        res = cursor.fetchone()
        if res:
            found = True

        if not found:
            # Drop the torrent file into the torrent_dir
            fn = '%s%s%s.torrent' % (os.path.abspath(self.torrent_dir),
                                     os.sep,
                                     re.sub(r'[^\w\.\-]', '_', torrent_path))

            try:
                #pylint:disable=locally-disabled, bad-open-mode
                torfile = open(fn, 'xb')
                torfile.write(torrent)
                torfile.close()
            except FileExistsError:
                found = True

        if found:
            # We found either the torrent or the path, so mark it as
            # processed for the future
            self.skip_torrent(url)
            return False
        else:
            # It was new, so update the DB to reflect success
            cursor = self.db.cursor()
            cursor.execute("""
                UPDATE dls SET path=?, downloaded=1, finished=1
                WHERE url=?
            """, (torrent_path, url))
            self.db.commit()
            return True
Beispiel #49
0
with open(rss, "w") as xml:
    xml.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
    xml.write("<rss version=\"2.0\">\n")
    xml.write("\t<channel>\n")
    xml.write("\t\t<title>Plailect Guide Feed</title>\n")
    xml.write("\t\t<lastBuildDate>{0}</lastBuildDate>\n".format(datetime.datetime.utcnow().strftime("%a, %d %b %Y %X +0000")))
    xml.write("\t\t<link>https://github.com/Plailect/Guide_3DS/</link>\n")

    for filename in os.listdir(dir):
        if filename.endswith(".torrent"):
            filepath = os.path.join(dir, filename)

            with open(filepath, "rb") as a:
                raw = a.read()
                tor = bencodepy.decode(raw)
                trackers = []
                infohash = hashlib.sha1(bencodepy.encode(tor[b"info"])).hexdigest().upper()
                magp = {"xt": "urn:btih:{0}".format(infohash), "dn": tor[b"info"][b"name"], "xl": tor[b"info"][b"length"]}
                magstr = urllib.parse.urlencode(magp)
                for anncl in tor[b"announce-list"]:
                    if isinstance(anncl, list):
                        for annc in anncl:
                            trackers.append(annc.decode("utf-8"))
                    else:
                        trackers.append(anncl.decode("utf-8"))
                length = tor[b"info"][b"length"]
                name = tor[b"info"][b"name"].decode("utf-8")
                ts = tor[b"creation date"]

            pubdate = datetime.datetime.utcfromtimestamp(int(ts))
Beispiel #50
0
 def datagramReceived(self, data, addressPort):
     (address, port) = addressPort
     print("Datagram %s received from %s" % (repr(data), repr((address, port))))
     
     print(bencodepy.decode(data))
Beispiel #51
0
 def message_extended(self, payload):
     extension, payload = unpack('>B', payload)
     payload = bencodepy.decode(payload)
     logging.info('Extension {}: {}'.format(extension, payload))
     return extension, payload