Switch to bencode_open

This commit is contained in:
Ivanq 2019-12-09 22:13:38 +03:00
parent 28fcf3c1ea
commit 3178b69172
4 changed files with 183 additions and 5 deletions

View File

@ -3,7 +3,7 @@ import urllib.request
import struct
import socket
import bencode
import bencode_open
from lib.subtl.subtl import UdpTrackerClient
import socks
import sockshandler
@ -133,9 +133,7 @@ class SiteAnnouncerPlugin(object):
# Decode peers
try:
peer_data = bencode.decode(response)["peers"]
if type(peer_data) is not bytes:
peer_data = peer_data.encode()
peer_data = bencode_open.loads(response)[b"peers"]
response = None
peer_count = int(len(peer_data) / 6)
peers = []

View File

@ -7,7 +7,6 @@ PySocks>=1.6.8
pyasn1
websocket_client
gevent-websocket
bencode.py
coincurve
python-bitcoinlib
maxminddb

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Ivan Machugovskiy
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,160 @@
def loads(data):
if not isinstance(data, bytes):
raise TypeError("Expected 'bytes' object, got {}".format(type(data)))
offset = 0
def parseInteger():
nonlocal offset
offset += 1
had_digit = False
abs_value = 0
sign = 1
if data[offset] == ord("-"):
sign = -1
offset += 1
while offset < len(data):
if data[offset] == ord("e"):
# End of string
offset += 1
if not had_digit:
raise ValueError("Integer without value")
break
if ord("0") <= data[offset] <= ord("9"):
abs_value = abs_value * 10 + int(chr(data[offset]))
had_digit = True
offset += 1
else:
raise ValueError("Invalid integer")
else:
raise ValueError("Unexpected EOF, expected integer")
if not had_digit:
raise ValueError("Empty integer")
return sign * abs_value
def parseString():
nonlocal offset
length = int(chr(data[offset]))
offset += 1
while offset < len(data):
if data[offset] == ord(":"):
offset += 1
break
if ord("0") <= data[offset] <= ord("9"):
length = length * 10 + int(chr(data[offset]))
offset += 1
else:
raise ValueError("Invalid string length")
else:
raise ValueError("Unexpected EOF, expected string contents")
if offset + length > len(data):
raise ValueError("Unexpected EOF, expected string contents")
offset += length
return data[offset - length:offset]
def parseList():
nonlocal offset
offset += 1
values = []
while offset < len(data):
if data[offset] == ord("e"):
# End of list
offset += 1
return values
else:
values.append(parse())
raise ValueError("Unexpected EOF, expected list contents")
def parseDict():
nonlocal offset
offset += 1
items = {}
while offset < len(data):
if data[offset] == ord("e"):
# End of list
offset += 1
return items
else:
key, value = parse(), parse()
if not isinstance(key, bytes):
raise ValueError("A dict key must be a byte string")
if key in items:
raise ValueError("Duplicate dict key: {}".format(key))
items[key] = value
raise ValueError("Unexpected EOF, expected dict contents")
def parse():
nonlocal offset
if data[offset] == ord("i"):
return parseInteger()
elif data[offset] == ord("l"):
return parseList()
elif data[offset] == ord("d"):
return parseDict()
elif ord("0") <= data[offset] <= ord("9"):
return parseString()
raise ValueError("Unknown type specifier: '{}'".format(chr(data[offset])))
result = parse()
if offset != len(data):
raise ValueError("Expected EOF, got {} bytes left".format(len(data) - offset))
return result
def dumps(data):
result = bytearray()
def convert(data):
nonlocal result
if isinstance(data, str):
raise ValueError("bencode only supports bytes, not str. Use encode")
if isinstance(data, bytes):
result += str(len(data)).encode() + b":" + data
elif isinstance(data, int):
result += b"i" + str(data).encode() + b"e"
elif isinstance(data, list):
result += b"l"
for val in data:
convert(val)
result += b"e"
elif isinstance(data, dict):
result += b"d"
for key in sorted(data.keys()):
if not isinstance(key, bytes):
raise ValueError("Dict key can only be bytes, not {}".format(type(key)))
convert(key)
convert(data[key])
result += b"e"
else:
raise ValueError("bencode only supports bytes, int, list and dict")
convert(data)
return bytes(result)