From ed59121c5da1279ecdd234555a445f9b5cc2b88a Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Thu, 17 Oct 2024 17:26:33 -0700 Subject: [PATCH] Bramify this... work around the stupidity that is BEP-52 in most cases, keys are us-ascii, but BEP-52 allows some keys to be binary data.. It does appear that it only applies to dictionaries that are under 'piece layer', so pass down the parent key, and don't do encoding for the dictionary that is under it. It also had a bug where if a dictionary key had code points >127, it'd encode the values incorrectly, because it'd take the length of the string and not the encoded string.. --- ui/medashare/btv/bencode.py | 37 +++++++++++++++--- .../btv/fixtures/bittorrent-v2-test.torrent | Bin 0 -> 13592 bytes 2 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 ui/medashare/btv/fixtures/bittorrent-v2-test.torrent diff --git a/ui/medashare/btv/bencode.py b/ui/medashare/btv/bencode.py index 34a4115..7385947 100644 --- a/ui/medashare/btv/bencode.py +++ b/ui/medashare/btv/bencode.py @@ -68,16 +68,23 @@ def decode_list(x, f): r.append(v) return (r, f + 1) -def decode_dict(x, f): +def decode_dict(x, f, parent=None): r, f = {}, f+1 lastkey = None while x[f] != b'e'[0]: k, f = decode_string(x, f) - k = k.decode('us-ascii') + if not parent or parent not in { 'piece layers' }: + k = k.decode('us-ascii') if lastkey is not None and lastkey >= k: raise ValueError lastkey = k - r[k], f = decode_func[x[f]](x, f) + + #decode value + fun = decode_func[x[f]] + kwargs = {} + if fun is decode_dict: + kwargs['parent'] = k + r[k], f = fun(x, f, **kwargs) return (r, f + 1) decode_func = {} @@ -285,11 +292,18 @@ def encode_list(x,r): encode_func[type(e)](e, r) r.append(b'e') -def encode_dict(x,r): +def encode_dict(x,r, parent=None): r.append(b'd') for k,v in sorted(x.items()): - r.extend((b'%d:' % len(k),k.encode('UTF-8'))) - encode_func[type(v)](v, r) + origk = k + if not parent or parent not in { 'piece layers' }: + k = k.encode('us-ascii') + r.extend((b'%d:' % len(k),k)) + efun = encode_func[type(v)] + kwargs = {} + if efun is encode_dict: + kwargs['parent'] = origk + efun(v, r, **kwargs) r.append(b'e') encode_func = {} @@ -341,6 +355,17 @@ class _TestCases(unittest.TestCase): self.assertEqual(bencode({'': 5}), b'd0:i5ee') + def test_round_trip_files(self): + import importlib + + fixtures = importlib.resources.files(__name__[:__name__.rindex('.')]) / 'fixtures' + + for i in fixtures.iterdir(): + with self.subTest(file=str(i)): + data = i.read_bytes() + + self.assertEqual(data, bencode(bdecode(data))) + def test_bdecode(self): test_bdecode() diff --git a/ui/medashare/btv/fixtures/bittorrent-v2-test.torrent b/ui/medashare/btv/fixtures/bittorrent-v2-test.torrent new file mode 100644 index 0000000000000000000000000000000000000000..8ad4c7eab07617e0c2b5c53df29c58d629cf3566 GIT binary patch literal 13592 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 literal 0 HcmV?d00001