mirror of
https://github.com/NohamR/Ratio.py.git
synced 2025-05-23 16:28:58 +00:00
first commit
This commit is contained in:
commit
363aafe901
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
*.swp
|
||||
*.swo
|
||||
*.pyc
|
||||
*.torrent
|
||||
venv
|
||||
*.pdf
|
||||
*.pcapng
|
||||
__pycache__
|
||||
*.pyc
|
0
code/__init__.py
Normal file
0
code/__init__.py
Normal file
90
code/decoding_bencoded.py
Normal file
90
code/decoding_bencoded.py
Normal file
@ -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
|
28
code/pretty.py
Normal file
28
code/pretty.py
Normal file
@ -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)
|
103
code/torrent.py
Normal file
103
code/torrent.py
Normal file
@ -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<len(raw_peers)-6:
|
||||
peer = raw_peers[i:i+6]
|
||||
i+=6
|
||||
unpacked_ip = unpack('BBBB', peer[0:4])
|
||||
ip = ".".join(str(i) for i in unpacked_ip)
|
||||
unpacked_port = unpack('!H', peer[4:6])
|
||||
port = unpacked_port[0]
|
||||
peers.append((ip, port))
|
||||
self.interval = response['interval']
|
||||
|
||||
def wait(self):
|
||||
pbar = tqdm(total=self.interval)
|
||||
print('sleep: {}'.format(self.interval))
|
||||
t = 0
|
||||
while t < self.interval:
|
||||
t += 1
|
||||
pbar.update(1)
|
||||
sleep(1)
|
||||
pbar.close()
|
||||
|
||||
def tracker_process(self):
|
||||
while True:
|
||||
print('----------- Sending Command to Tracker --------')
|
||||
min_up = self.interval-(self.interval*0.1)
|
||||
max_up = self.interval
|
||||
uploaded = 500000*random.randint(min_up, max_up)
|
||||
|
||||
tc = self.torrentclient
|
||||
headers = tc.get_headers()
|
||||
params = tc.get_query(uploaded=uploaded,
|
||||
downloaded=0,
|
||||
left=0,
|
||||
event='stopped')
|
||||
content = self.send_request(params, headers)
|
||||
self.tracker_response_parser(content)
|
||||
self.wait()
|
60
code/torrentclientfactory.py
Normal file
60
code/torrentclientfactory.py
Normal file
@ -0,0 +1,60 @@
|
||||
import random
|
||||
import string
|
||||
|
||||
class Transmission292():
|
||||
def __init__(self, info_hash):
|
||||
self.name = "Transmission 2.92 (14714)"
|
||||
parameters = {}
|
||||
# urlencoded 20-byte SHA1 hash of the value of the info key from the Metainfo file
|
||||
parameters['info_hash'] = info_hash
|
||||
# urlencoded 20-byte string used as a unique ID for the client
|
||||
parameters["peer_id"] = self.generate_peer_id()
|
||||
# The port number that the client is listening on
|
||||
parameters["port"] = random.randint(1025, 65535)
|
||||
# Number of peers that the client would like to receive from the tracker
|
||||
parameters["numwant"] = 80
|
||||
# An additional identification that is not shared with any other peers
|
||||
parameters["key"] = self.generate_key()
|
||||
# Setting this to 1 indicates that the client accepts a compact response
|
||||
parameters["compact"] = 0
|
||||
# Setting this to 1 indicates that the client accepts crypto
|
||||
parameters["supportcrypto"] = 1
|
||||
self.parameters = parameters
|
||||
|
||||
def get_headers(self):
|
||||
headers = {}
|
||||
headers['User-Agent'] = 'Transmission/2.92'
|
||||
headers['Accept'] = '*/*'
|
||||
headers['Accept-Encoding'] = 'Accept-Encoding: gzip;q=1.0, deflate, identity'
|
||||
return headers
|
||||
|
||||
def get_query(self, uploaded, downloaded, left, event=None):
|
||||
# The total amount uploaded (since the client sent the 'started' event)
|
||||
self.parameters["uploaded"] = uploaded
|
||||
# The total amount downloaded (since the client sent the 'started' event)
|
||||
self.parameters["downloaded"] = downloaded
|
||||
# The number of bytes this client still has to download
|
||||
self.parameters["left"] = left
|
||||
# If specified, must be one of started, completed, stopped
|
||||
if event:
|
||||
self.parameters["event"] = event
|
||||
params = '&'.join('{}={}'.format(k, v)
|
||||
for k, v in self.parameters.items())
|
||||
return params
|
||||
|
||||
def id_generator(self, chars, size):
|
||||
id = ''
|
||||
for _ in range(size):
|
||||
id += random.choice(chars)
|
||||
return id
|
||||
|
||||
def generate_peer_id(self):
|
||||
chars = string.ascii_lowercase + string.digits
|
||||
rand_id = self.id_generator(chars, 12)
|
||||
peer_id = "-TR2920-" + rand_id
|
||||
return peer_id
|
||||
|
||||
def generate_key(self):
|
||||
chars = 'ABCDEF' + string.digits
|
||||
key = self.id_generator(chars, 8)
|
||||
return key
|
6
main.py
Normal file
6
main.py
Normal file
@ -0,0 +1,6 @@
|
||||
from code.torrent import torrent
|
||||
|
||||
to = torrent('test.torrent')
|
||||
rep = to.tracker_start_request()
|
||||
to.tracker_process()
|
||||
|
2
requirements.txt
Normal file
2
requirements.txt
Normal file
@ -0,0 +1,2 @@
|
||||
requests
|
||||
tqdm
|
Loading…
x
Reference in New Issue
Block a user