From 363aafe901fcbe2410ed931cf41ec9ad5e159a29 Mon Sep 17 00:00:00 2001 From: MisterDaneel Date: Sat, 16 Feb 2019 16:20:15 +0100 Subject: [PATCH] first commit --- .gitignore | 9 +++ code/__init__.py | 0 code/decoding_bencoded.py | 90 ++++++++++++++++++++++++++++++ code/pretty.py | 28 ++++++++++ code/torrent.py | 103 +++++++++++++++++++++++++++++++++++ code/torrentclientfactory.py | 60 ++++++++++++++++++++ main.py | 6 ++ requirements.txt | 2 + 8 files changed, 298 insertions(+) create mode 100644 .gitignore create mode 100644 code/__init__.py create mode 100644 code/decoding_bencoded.py create mode 100644 code/pretty.py create mode 100644 code/torrent.py create mode 100644 code/torrentclientfactory.py create mode 100644 main.py create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..206066b --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*.swp +*.swo +*.pyc +*.torrent +venv +*.pdf +*.pcapng +__pycache__ +*.pyc diff --git a/code/__init__.py b/code/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/code/decoding_bencoded.py b/code/decoding_bencoded.py new file mode 100644 index 0000000..75be291 --- /dev/null +++ b/code/decoding_bencoded.py @@ -0,0 +1,90 @@ +import re +import logging +import binascii +class bencoding(): + + def __init__(self): + self.decimal_match = re.compile('\d') + self.data = b'' + self.dict = {} + + def get_dict(self, key): + if key not in self.dict: + return '' + start = self.dict[key][0] + end = self.dict[key][1] + return self.data[start:end] + + def get_item(self, chunks): + item = chunks[self.i] + self.i += 1 + if not type(item) == str: + item = bytes([item]) + try: + item = item.decode('utf-8') + except: + item = '\\x{}'.format(binascii.hexlify(item)) + return item + + def decoding_byte_string(self, chunks, item): + # logging.debug('decoding string') + num = '' + while self.decimal_match.search(item): + num += item + item = self.get_item(chunks) + line = '' + for i in range(int(num)): + line += self.get_item(chunks) + return line + + def decoding_integer(self, chunks): + # logging.debug('decoding integer') + item = self.get_item(chunks) + num = '' + while item != 'e': + num += item + item = self.get_item(chunks) + return int(num) + + def decoding_list(self, chunks): + # logging.debug('decoding list') + item = self.get_item(chunks) + list = [] + while item != 'e': + self.i -= 1 + list.append(self._dechunk(chunks)) + item = self.get_item(chunks) + return list + + def decoding_dictionnary(self, chunks): + # logging.debug('decoding dictionnary') + item = self.get_item(chunks) + hash = {} + while item != 'e': + self.i -= 1 + key = self._dechunk(chunks) + start = self.i + hash[key] = self._dechunk(chunks) + end = self.i + self.dict[key] = (start, end) + item = self.get_item(chunks) + return hash + + def _dechunk(self, chunks): + item = self.get_item(chunks) + if item == 'd': + return self.decoding_dictionnary(chunks) + elif item == 'l': + return self.decoding_list(chunks) + elif item == 'i': + return self.decoding_integer(chunks) + elif self.decimal_match.search(item): + return self.decoding_byte_string(chunks, item) + raise "Invalid input!" + + def bdecode(self, data): + self.data = data + chunks = list(self.data) + self.i = 0 + root = self._dechunk(chunks) + return root diff --git a/code/pretty.py b/code/pretty.py new file mode 100644 index 0000000..e5c8a39 --- /dev/null +++ b/code/pretty.py @@ -0,0 +1,28 @@ +import requests +from pprint import pformat + + +def get_headers(headers): + res = '' + for k, v in headers.items(): + res += '{}: {}\n'.format(k, v) + return res + + +def pretty_GET(url, headers, params): + req = requests.Request('GET', url, headers=headers, params=params) + s = requests.Session() + prepared = s.prepare_request(req) + p = '-----START-----\n' + p +=('{} {}\n{}'.format(prepared.method, prepared.url, + get_headers(prepared.headers), + ) + ) + if prepared.body: + pi += prepared.body + p += '------END------' + return p + + +def pretty_data(data): + return pformat(data) diff --git a/code/torrent.py b/code/torrent.py new file mode 100644 index 0000000..a3abf34 --- /dev/null +++ b/code/torrent.py @@ -0,0 +1,103 @@ +from code.decoding_bencoded import bencoding +from code.torrentclientfactory import Transmission292 +from code.pretty import pretty_data, pretty_GET + +from hashlib import sha1 +from urllib.parse import quote_plus +import requests +import logging +import random +from tqdm import tqdm +from time import sleep + +from struct import unpack + +logging.basicConfig(level=logging.DEBUG) + +class torrent(): + + def __init__(self, torrent_tile): + with open(torrent_tile, 'rb') as tf: + data = tf.read() + self.b_enc = bencoding() + self.metainfo = self.b_enc.bdecode(data) + self.info = self.metainfo['info'] + print(pretty_data(self.info)) + self.torrentclient = Transmission292(self.tracker_info_hash()) + + def tracker_info_hash(self): + raw_info = self.b_enc.get_dict('info') + hash_factory = sha1() + hash_factory.update(raw_info) + hashed = hash_factory.hexdigest() + sha = bytearray.fromhex(hashed) + return str(quote_plus(sha)) + + def send_request(self, params, headers): + url = self.metainfo['announce'] + print(pretty_GET(url, headers, params)) + while True: + try: + r = requests.get(url, params=params, headers=headers) + except requests.exceptions.ConnectionError as e: + sleep(1) + continue + break + return r.content + + def tracker_start_request(self): + tc = self.torrentclient + headers = tc.get_headers() + params = tc.get_query(uploaded=0, + downloaded=0, + left=self.info['length'], + event='started') + + print('----------- First Command to Tracker --------') + content = self.send_request(params, headers) + self.tracker_response_parser(content) + + def tracker_response_parser(self, tr_response): + b_enc = bencoding() + response = b_enc.bdecode(tr_response) + print('----------- Received Tracker Response --------') + print(pretty_data(response)) + raw_peers = b_enc.get_dict('peers') + i = 0 + peers = [] + while i