def bep44_insert(index_key, desc_link, desc_inline, priv_key): """Return a signed BEP44 mutable data item (as bytes).""" # It is not safe to assume that storing more than 1000 bytes will succeed, # according to <http://bittorrent.org/beps/bep_0044.html#messages>. v = desc_inline if len(bencoder.bencode(desc_inline)) > 1000: v = desc_link salt = hashlib.sha1(index_key.encode()).digest() # SHA1 hash of the index key seq = int(time.time()) # integer Unix time stamp # Low-level signature buffer computation is mandated by # <http://bittorrent.org/beps/bep_0044.html#signature-verification>. sigbuf = b'' sigbuf += b'4:salt%d:%s' % (len(salt), salt) sigbuf += b'3:seqi%de' % seq sigbuf += b'1:v%d:%s' % (len(v), v) # Sign, build exported message fields and encode the result. # We follow the names used in the BEP44 document. sig = priv_key.sign(sigbuf).signature return bencoder.bencode(dict( # cas is not compulsory # id depends on the publishing node k=priv_key.verify_key.encode(), salt=salt, seq=seq, # token depends on the insertion sig=sig, v=v ))
def test_encode_large_int(benchmark): assert bencode(1455189890) == b'i1455189890e' assert bencode(25735241490) == b'i25735241490e' MAX_SIZE = sys.maxsize + 1 BENCODED_MAXSIZE = ('i%de' % MAX_SIZE).encode() assert benchmark(bencode, MAX_SIZE) == BENCODED_MAXSIZE
def sendHello(self): # global REG_IPV4, REG_PORT helloTime = time.time() firstHello = True while True: if (time.time() - helloTime) > 10 or firstHello: # Create a UDP socket sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # print(REG_IPV4, REG_PORT) server_address = (REG_IPV4, int(REG_PORT)) firstHello = False data = self.prepareData() bencoded = bencode(data) try: # Send data # print('sending {!r}'.format(bencoded)) # print("to") # print(server_address) # print(bencoded) sent = sock.sendto(bencoded, server_address) # Receive response # print('waiting to receive') # data, server = sock.recvfrom(4096) # print('received {!r}'.format(data)) finally: # print('closing socket') sock.close() helloTime = time.time()
def __init__(self, sock): print("Peer started ...") # Start RPC daemon for listening to his messages RPCThread = threading.Thread(target=self.RPCHandler, args=()) RPCThread.daemon = True RPCThread.start() helloThread = threading.Thread(target=self.sendHello, args=()) helloThread.daemon = True helloThread.start() # Get some time variable out of while loop helloTime = time.time() while True: # print('\nwaiting to receive message') data, address = sock.recvfrom(4096) # print('received {} bytes from {}'.format( # len(data), address)) data = data.decode("utf-8") dataDecoded = bdecode(data) message = self.parseMessage(dataDecoded) for line in message: if line == 'type': if message[line] == 'message': print("[SERVER] I got message from someone") print(message) bencoded = bencode(b'ACK') sent = sock.sendto(bencoded, address)
def send_krpc(self, data, address): """发送 krpc 信息""" self.logger.debug("I'm sending to {}".format(address)) try: self.udp_socket.sendto(bencode(data), address) except Exception: self.logger.exception(Exception)
def send_message(self, data, addr): data.setdefault("t", b"tt") try: print(addr, data['q']) except Exception: print(addr) self.transport.sendto(bencoder.bencode(data), addr)
def sendGetList(self): # Create a UDP socket sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) server_address = (REG_IPV4, int(REG_PORT)) data = { "type":"getlist", "txid": TXID } while True: bencoded = bencode(data) try: # Send data # print('sending {!r}'.format(bencoded)) sent = sock.sendto(bencoded, server_address) # Receive response # print('waiting to receive') data, server = sock.recvfrom(4096) decodedData = bdecode(data) # print('received {!r}'.format(decodedData)) self.sendACK() finally: # print('closing socket') sock.close() return decodedData
def send_krpc(self, msg, address): # print(address, msg['q']) # print(msg) # print(bencode(msg)) try: self.transport.sendto(bencode(msg), address) except Exception as e: print(address, e)
def test_encode_complex(): od = dict() od['KeyA'] = ['listitemA', {'k': 'v'}, 3] od['KeyB'] = {'k': 'v'} od['KeyC'] = 3 od['KeyD'] = 'AString' expected_result = b'd4:KeyAl9:listitemAd1:k1:vei3ee4:KeyBd1:k1:ve4:KeyCi3e4:KeyD7:AStringe' assert bencode(od) == expected_result
def save_dtorrent(self, files, comment=None): dtor = files.dtors[0].as_dict if comment: dtor[b'comment'] = comment.encode() file_path = os.path.join(self.dtor_save_dir, self.tor_info.folder_name) + ".torrent" with open(file_path, "wb") as f: f.write(bencode(dtor))
def test_validate_missing_info(): data = OrderedDict([ (b'foo', b'bar'), ]) fo = io.BytesIO(bencode(data)) with pytest.raises(torf.MetainfoError) as excinfo: torf.Torrent.read_stream(fo, validate=True) assert excinfo.match("^Invalid metainfo: Missing 'info'$")
def test_single_tracker(valid_singlefile_metainfo): valid_singlefile_metainfo[b'announce'] = b'http://lonelyhost/announce' valid_singlefile_metainfo.pop(b'announce-list', None) fo = io.BytesIO(bencode(valid_singlefile_metainfo)) t = torf.Torrent.read_stream(fo) assert t.trackers == [[ str(valid_singlefile_metainfo[b'announce'], encoding='utf-8') ]]
def test_encode_dict_subclass(): class AAA(dict): pass od = AAA() od['ka'] = 'va' od['kb'] = 2 assert bencode(od) == b'd2:ka2:va2:kbi2ee'
def test_read_from_unreadable_file(valid_singlefile_metainfo, tmpdir): f = tmpdir.join('a.torrent') f.write_binary(bencode(valid_singlefile_metainfo)) f.chmod(mode=0o222) with pytest.raises(torf.ReadError) as excinfo: torf.Torrent.read(str(f)) assert excinfo.match(f'^{str(f)}: Permission denied$')
def send_krpc(message, node, sock): ''' sends bencoded krpc to node ip address and node port ''' try: sock.sendto(bencode(message), (node[1], node[2])) except (IndexError, TypeError): pass
def infohash_alt(filename, source=None): '''Calculate infohash for the same torrent with different source tag''' torrent, info = _parse_torrent(filename) if source is None: # delete source tag if SOURCE in info: del info[SOURCE] else: info[SOURCE] = source return sha1(bencode(info)).hexdigest()
def test_multiple_trackers(valid_singlefile_metainfo, tmpdir): valid_singlefile_metainfo[b'announce-list'] = [[ b'http://localhost', b'http://foohost' ], [b'http://bazhost']] valid_singlefile_metainfo.pop(b'announce', None) fo = io.BytesIO(bencode(valid_singlefile_metainfo)) t = torf.Torrent.read_stream(fo) assert t.trackers == [[ str(url, encoding='utf-8') for url in tier ] for tier in valid_singlefile_metainfo[b'announce-list']]
def test_successful_read(valid_singlefile_metainfo): fo = io.BytesIO(bencode(valid_singlefile_metainfo)) t = torf.Torrent.read_stream(fo) assert t.path is None assert tuple(t.files) == (str(valid_singlefile_metainfo[b'info'][b'name'], encoding='utf-8'), ) assert tuple(t.filepaths) == () assert t.name == str(valid_singlefile_metainfo[b'info'][b'name'], encoding='utf-8') assert t.size == valid_singlefile_metainfo[b'info'][b'length'] assert t.infohash == sha1(bencode( valid_singlefile_metainfo[b'info'])).hexdigest() assert t.comment == str(valid_singlefile_metainfo[b'comment'], encoding='utf-8') assert t.creation_date == datetime.fromtimestamp( valid_singlefile_metainfo[b'creation date']) assert t.created_by == str(valid_singlefile_metainfo[b'created by'], encoding='utf-8') assert t.private is bool(valid_singlefile_metainfo[b'info'][b'private']) assert t.piece_size == valid_singlefile_metainfo[b'info'][b'piece length']
def info_hash(self): """ :return: The SHA-1 info hash of the torrent. Useful for generating magnet links. .. note:: ``generate()`` must be called first. """ if getattr(self, '_data', None): return sha1(bencode(self._data['info'])).hexdigest() else: raise exceptions.TorrentNotGeneratedException
def dump(self): """ :return: The bencoded torrent data as a byte string. .. note:: ``generate()`` must be called first. """ if getattr(self, '_data', None): return bencode(self._data) else: raise exceptions.TorrentNotGeneratedException
def info_hash_base32(self): """ Returns the base32 info hash of the torrent. Useful for generating magnet links. .. note:: ``generate()`` must be called first. """ if getattr(self, '_data', None): return b32encode(sha1(bencode(self._data['info'])).digest()) else: raise exceptions.TorrentNotGeneratedException
def test_read_from_proper_torrent_file(valid_multifile_metainfo, tmpdir): f = tmpdir.join('a.torrent') f.write_binary(bencode(valid_multifile_metainfo)) t = torf.Torrent.read(str(f)) exp_info = valid_multifile_metainfo[b'info'] assert t.path is None assert tuple(t.files) == tuple( str(b'/'.join([exp_info[b'name']] + f[b'path']), encoding='utf-8') for f in exp_info[b'files']) assert tuple(t.filepaths) == () assert t.name == str(exp_info[b'name'], encoding='utf-8') assert t.size == sum(f[b'length'] for f in exp_info[b'files']) assert t.infohash == sha1(bencode(exp_info)).hexdigest() assert t.comment == str(valid_multifile_metainfo[b'comment'], encoding='utf-8') assert t.creation_date == datetime.fromtimestamp( valid_multifile_metainfo[b'creation date']) assert t.created_by == str(valid_multifile_metainfo[b'created by'], encoding='utf-8') assert t.private is bool(exp_info[b'private']) assert t.piece_size == exp_info[b'piece length']
def send_krpc(self, msg, address): """ 发送 krpc 协议 :param msg: 发送 UDP 报文信息 :param address: 发送地址,(ip, port) 元组 """ try: # msg 要经过 bencode 编码 self.udp.sendto(bencoder.bencode(msg), address) except: pass
def test_read_nonstandard_data_without_validation(): data = OrderedDict([(b'foo', b'bar'), (b'number', 17), (b'list', [1, b'two']), (b'dict', OrderedDict([ (b'yes', 1), (b'no', 0), ]))]) fo = io.BytesIO(bencode(data)) t = torf.Torrent.read_stream(fo, validate=False) assert t.metainfo['foo'] == 'bar' assert t.metainfo['number'] == 17 assert t.metainfo['list'] == [1, 'two'] assert t.metainfo['dict'] == {'yes': 1, 'no': 0}
def parse_dtorrent(self, path): with open(path, "rb") as f: torbytes = f.read() self.dtor_dict = bdecode(torbytes) announce = self.dtor_dict[b'announce'].decode() tr_domain = re.search(r"https?://(.+?)/.+", announce).group(1) for t, data in tr_data.items(): if tr_domain in data['tracker']: self.src_tr = t break info = self.dtor_dict[b'info'] self.info_hash = sha1(bencode(info)).hexdigest()
async def get_metainfo(self, infohash, addr): fail = False async with self.fetch_metainfo_semaphore: filename = '{}{}{}.torrent'.format(cfg.get('torrent', 'save_path'), os.sep, infohash.lower()) if len(glob.glob(filename)) == 0: try: metainfo = await asyncio.wait_for( get_metadata( infohash, addr[0], addr[1], loop=self.loop ), timeout=self.interval * 20) except: fail = True if fail or (isinstance(metainfo, bool) and metainfo is False): async with self.database_semaphore: async with self.connection_pool.acquire() as connect: cursor = await connect.cursor() await cursor.execute(base_sql.remove_from_announce_queue.format(info_hash=infohash)) await connect.commit() await cursor.close() return if metainfo is not None: # hash error if infohash != get_meta_hash(metainfo): return name = get_filename(metainfo) size = get_file_size(metainfo) logging.info( 'Hash: {}. Name: {}. Size: {}'.format( infohash, name, size ) ) file_content = bencoder.bencode({b'info': metainfo}) async with aiofiles.open(filename, mode='wb') as f: await f.write(file_content) async with self.database_semaphore: async with self.connection_pool.acquire() as connect: cursor = await connect.cursor() try: await cursor.execute(base_sql.insert_into_torrent.format( name=aiomysql.escape_string(name), info_hash=infohash, size=size)) except pymysql.err.IntegrityError: await cursor.rollback() finally: await cursor.execute(base_sql.remove_from_announce_queue.format(info_hash=infohash)) await connect.commit() await cursor.close()
def sendMessage(self, data): print("[INFO] Send message") data2 = data.decode("utf-8") data2 = data2.replace("'", '"') data3 = json.loads(data2) to = data3['to'] message = data3['message'] users = self.sendGetList() for item in users: if item == "peers": for entry in users[item]: user = (users['peers'][str(entry)]) if user['username'].decode("utf-8") == to: ("here2") ip = (user['ipv4']).decode("utf-8") port = (user['port']) # Create a UDP socket sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) server_address = (ip, int(port)) next_id() data = { "type":"message", "txid": TXID, "from": str(USERNAME), "to": str(to), "message":str(message) } while True: bencoded = bencode(data) try: # Send data # print('sending {!r}'.format(bencoded)) sent = sock.sendto(bencoded, server_address) # Receive response # print('waiting to receive') data, server = sock.recvfrom(4096) print('received {!r}'.format(data)) finally: # print('closing socket') sock.close() return
def create(self, target_path=None): self.validate() if not target_path: target_path = os.getcwd() torrent_info = { "announce": self.announce, "creation date": self.creation_date, "encoding": self.encoding, "info": self.info } if self.announce_list: torrent_info['announce-list'] = self.announce_list if self.created_by: torrent_info['created by'] = self.created_by encode_info = bencoder.bencode(torrent_info) file_name = os.path.join(target_path, self.info['name'] + ".torrent") with open(file_name, "wb") as f: f.write(encode_info)
def sendACK(self): # Create a UDP socket sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) server_address = (REG_IPV4, int(REG_PORT)) next_id() data = { "type":"ack", "txid": TXID } while True: bencoded = bencode(data) try: # Send data # print('sending {!r}'.format(bencoded)) sent = sock.sendto(bencoded, server_address) finally: # print('closing socket') sock.close() return
def __init__(self): print("[INFO] init") print("Server is starting ...") # Start RPC daemon for listening to his messages RPCThread = threading.Thread(target=self.RPCHandler, args=()) RPCThread.daemon = True RPCThread.start() # Create a UDP socket sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Bind the socket to the port server_address = (REG_IPV4, int(REG_PORT)) print('Serverstarting up socket on {} port {}'.format(*server_address)) sock.bind(server_address) while True: # print('\nwaiting to receive message') data, address = sock.recvfrom(4096) # print('received {} bytes from {}'.format( # len(data), address)) data = data.decode("utf-8") dataDecoded = bdecode(data) message = self.parseMessage(dataDecoded) # print(message) for line in message: self.checkPeerHelloInterval() if line == 'type': if message[line] == 'getlist': print("[SERVER] I got GETLIST") data = self.preparePeersData() bencoded = bencode(data) sent = sock.sendto(bencoded, address) elif message[line] == 'hello': print("[SERVER] I got HELO") self.checkPeer(message) elif message[line] == 'ack': print("ACK")
def send_message(self, data, addr): data.setdefault("t", b"tt") self.transport.sendto(bencoder.bencode(data), addr)
def test_infohash(): import hashlib with open(TORRENT_PATH, "rb") as f: torrent = bdecode(f.read()) infohash = hashlib.sha1(bencode(torrent[b'info'])).hexdigest() assert infohash == "4194e473d6c49630e1c6247d6716076809bb96ae"
def test_encode_false(benchmark): assert benchmark(bencode, False) == bencode(0)
def test_encode_true(benchmark): assert benchmark(bencode, True) == bencode(1)