commit
2f7323043f
4 changed files with 183 additions and 5 deletions
|
@ -3,7 +3,7 @@ import urllib.request
|
||||||
import struct
|
import struct
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
import bencode
|
import bencode_open
|
||||||
from lib.subtl.subtl import UdpTrackerClient
|
from lib.subtl.subtl import UdpTrackerClient
|
||||||
import socks
|
import socks
|
||||||
import sockshandler
|
import sockshandler
|
||||||
|
@ -133,9 +133,7 @@ class SiteAnnouncerPlugin(object):
|
||||||
|
|
||||||
# Decode peers
|
# Decode peers
|
||||||
try:
|
try:
|
||||||
peer_data = bencode.decode(response)["peers"]
|
peer_data = bencode_open.loads(response)[b"peers"]
|
||||||
if type(peer_data) is not bytes:
|
|
||||||
peer_data = peer_data.encode()
|
|
||||||
response = None
|
response = None
|
||||||
peer_count = int(len(peer_data) / 6)
|
peer_count = int(len(peer_data) / 6)
|
||||||
peers = []
|
peers = []
|
||||||
|
|
|
@ -7,6 +7,5 @@ PySocks>=1.6.8
|
||||||
pyasn1
|
pyasn1
|
||||||
websocket_client
|
websocket_client
|
||||||
gevent-websocket
|
gevent-websocket
|
||||||
bencode.py
|
|
||||||
coincurve
|
coincurve
|
||||||
maxminddb
|
maxminddb
|
||||||
|
|
21
src/lib/bencode_open/LICENSE
Normal file
21
src/lib/bencode_open/LICENSE
Normal 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.
|
160
src/lib/bencode_open/__init__.py
Normal file
160
src/lib/bencode_open/__init__.py
Normal 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)
|
Loading…
Reference in a new issue