Skip to content

Commit c57fb9b

Browse files
authored
Merge pull request #53 from ricott1/onion3_address
added onion3 codec
2 parents bea0191 + 2d5bc2f commit c57fb9b

File tree

4 files changed

+53
-0
lines changed

4 files changed

+53
-0
lines changed

multiaddr/codecs/onion3.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from __future__ import absolute_import
2+
import base64
3+
import struct
4+
5+
import six
6+
7+
8+
SIZE = 296
9+
IS_PATH = False
10+
11+
12+
def to_bytes(proto, string):
13+
addr = string.split(":")
14+
if len(addr) != 2:
15+
raise ValueError("Does not contain a port number")
16+
17+
# onion3 address without the ".onion" substring
18+
if len(addr[0]) != 56:
19+
raise ValueError("Invalid onion3 host address length (must be 56 characters)")
20+
try:
21+
onion3_host_bytes = base64.b32decode(addr[0].upper())
22+
except Exception as exc:
23+
six.raise_from(ValueError("Cannot decode {0!r} as base32: {1}".format(addr[0], exc)), exc)
24+
25+
# onion3 port number
26+
try:
27+
port = int(addr[1], 10)
28+
except ValueError as exc:
29+
six.raise_from(ValueError("Port number is not a base 10 integer"), exc)
30+
if port not in range(1, 65536):
31+
raise ValueError("Port number is not in range(1, 65536)")
32+
33+
return b''.join((onion3_host_bytes, struct.pack('>H', port)))
34+
35+
36+
def to_string(proto, buf):
37+
addr_bytes, port_bytes = (buf[:-2], buf[-2:])
38+
addr = base64.b32encode(addr_bytes).decode('ascii').lower()
39+
port = six.text_type(struct.unpack('>H', port_bytes)[0])
40+
return u':'.join([addr, port])

multiaddr/protocols.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
P_WS = 0x01DD
2828
P_WSS = 0x01DE
2929
P_ONION = 0x01BC
30+
P_ONION3 = 0x01BD
3031
P_P2P_CIRCUIT = 0x0122
3132
P_DNS = 0x35
3233
P_DNS4 = 0x36
@@ -54,6 +55,7 @@
5455
P_WS,
5556
P_WSS,
5657
P_ONION,
58+
P_ONION3,
5759
P_P2P_CIRCUIT,
5860
P_DNS,
5961
P_DNS4,
@@ -134,6 +136,7 @@ def __repr__(self):
134136
Protocol(P_UTP, 'utp', None),
135137
Protocol(P_P2P, 'p2p', 'p2p'),
136138
Protocol(P_ONION, 'onion', 'onion'),
139+
Protocol(P_ONION3, 'onion3', 'onion3'),
137140
Protocol(P_QUIC, 'quic', None),
138141
Protocol(P_HTTP, 'http', None),
139142
Protocol(P_HTTPS, 'https', None),

tests/test_multiaddr.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@
4343
"/onion/timaq4ygg2iegci7:-1",
4444
"/onion/timaq4ygg2iegci7",
4545
"/onion/timaq4ygg2iegci@:666",
46+
"/onion3/9ww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:80",
47+
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd7:80",
48+
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:0",
49+
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:-1",
50+
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd",
51+
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyy@:666",
4652
"/udp/1234/sctp",
4753
"/udp/1234/udt/1234",
4854
"/udp/1234/utp/1234",
@@ -75,6 +81,8 @@ def test_invalid(addr_str):
7581
"/ip6zone/x%y/ip6/::",
7682
"/onion/timaq4ygg2iegci7:1234",
7783
"/onion/timaq4ygg2iegci7:80/http",
84+
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:1234",
85+
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:80/http",
7886
"/udp/0",
7987
"/tcp/0",
8088
"/sctp/0",

tests/test_protocols.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,11 @@ def test_protocol_equality():
9494
proto1 = protocols.protocol_with_name('ip4')
9595
proto2 = protocols.protocol_with_code(protocols.P_IP4)
9696
proto3 = protocols.protocol_with_name('onion')
97+
proto4 = protocols.protocol_with_name('onion3')
9798

9899
assert proto1 == proto2
99100
assert proto1 != proto3
101+
assert proto3 != proto4
100102
assert proto1 is not None
101103
assert proto2 != str(proto2)
102104

0 commit comments

Comments
 (0)