Merge pull request #250 from ralexstokes/add-secio-groundwork
Add secio groundwork
This commit is contained in:
commit
dbdbcf7440
@ -1,6 +1,7 @@
|
||||
import asyncio
|
||||
from typing import Mapping, Sequence
|
||||
|
||||
from libp2p.crypto.keys import KeyPair
|
||||
from libp2p.crypto.rsa import create_new_key_pair
|
||||
from libp2p.host.basic_host import BasicHost
|
||||
from libp2p.kademlia.network import KademliaServer
|
||||
@ -12,7 +13,7 @@ from libp2p.peer.peerstore import PeerStore
|
||||
from libp2p.peer.peerstore_interface import IPeerStore
|
||||
from libp2p.routing.interfaces import IPeerRouting
|
||||
from libp2p.routing.kademlia.kademlia_peer_router import KadmeliaPeerRouter
|
||||
from libp2p.security.insecure_security import InsecureTransport
|
||||
from libp2p.security.insecure.transport import InsecureTransport
|
||||
from libp2p.security.secure_transport_interface import ISecureTransport
|
||||
from libp2p.transport.tcp.tcp import TCP
|
||||
from libp2p.transport.upgrader import TransportUpgrader
|
||||
@ -33,11 +34,15 @@ async def cleanup_done_tasks() -> None:
|
||||
await asyncio.sleep(3)
|
||||
|
||||
|
||||
def generate_peer_id_from_rsa_identity() -> ID:
|
||||
new_key_pair = create_new_key_pair()
|
||||
new_public_key = new_key_pair.public_key
|
||||
new_id = ID.from_pubkey(new_public_key)
|
||||
return new_id
|
||||
def generate_new_rsa_identity() -> KeyPair:
|
||||
return create_new_key_pair()
|
||||
|
||||
|
||||
def generate_peer_id_from_rsa_identity(key_pair: KeyPair = None) -> ID:
|
||||
if not key_pair:
|
||||
key_pair = generate_new_rsa_identity()
|
||||
public_key = key_pair.public_key
|
||||
return ID.from_pubkey(public_key)
|
||||
|
||||
|
||||
def initialize_default_kademlia_router(
|
||||
@ -64,6 +69,7 @@ def initialize_default_kademlia_router(
|
||||
|
||||
|
||||
def initialize_default_swarm(
|
||||
key_pair: KeyPair,
|
||||
id_opt: ID = None,
|
||||
transport_opt: Sequence[str] = None,
|
||||
muxer_opt: Sequence[str] = None,
|
||||
@ -83,7 +89,7 @@ def initialize_default_swarm(
|
||||
"""
|
||||
|
||||
if not id_opt:
|
||||
id_opt = generate_peer_id_from_rsa_identity()
|
||||
id_opt = generate_peer_id_from_rsa_identity(key_pair)
|
||||
|
||||
# TODO parse transport_opt to determine transport
|
||||
transport_opt = transport_opt or ["/ip4/127.0.0.1/tcp/8001"]
|
||||
@ -92,8 +98,10 @@ def initialize_default_swarm(
|
||||
# TODO TransportUpgrader is not doing anything really
|
||||
# TODO parse muxer and sec to pass into TransportUpgrader
|
||||
muxer = muxer_opt or ["mplex/6.7.0"]
|
||||
sec = sec_opt or {TProtocol("insecure/1.0.0"): InsecureTransport("insecure")}
|
||||
upgrader = TransportUpgrader(sec, muxer)
|
||||
security_transports_by_protocol = sec_opt or {
|
||||
TProtocol("insecure/1.0.0"): InsecureTransport(key_pair)
|
||||
}
|
||||
upgrader = TransportUpgrader(security_transports_by_protocol, muxer)
|
||||
|
||||
peerstore = peerstore_opt or PeerStore()
|
||||
# TODO: Initialize discovery if not presented
|
||||
@ -103,6 +111,7 @@ def initialize_default_swarm(
|
||||
|
||||
|
||||
async def new_node(
|
||||
key_pair: KeyPair = None,
|
||||
swarm_opt: INetwork = None,
|
||||
id_opt: ID = None,
|
||||
transport_opt: Sequence[str] = None,
|
||||
@ -113,6 +122,7 @@ async def new_node(
|
||||
) -> BasicHost:
|
||||
"""
|
||||
create new libp2p node
|
||||
:param key_pair: key pair for deriving an identity
|
||||
:param swarm_opt: optional swarm
|
||||
:param id_opt: optional id for host
|
||||
:param transport_opt: optional choice of transport upgrade
|
||||
@ -123,11 +133,15 @@ async def new_node(
|
||||
:return: return a host instance
|
||||
"""
|
||||
|
||||
if not key_pair:
|
||||
key_pair = generate_new_rsa_identity()
|
||||
|
||||
if not id_opt:
|
||||
id_opt = generate_peer_id_from_rsa_identity()
|
||||
id_opt = generate_peer_id_from_rsa_identity(key_pair)
|
||||
|
||||
if not swarm_opt:
|
||||
swarm_opt = initialize_default_swarm(
|
||||
key_pair=key_pair,
|
||||
id_opt=id_opt,
|
||||
transport_opt=transport_opt,
|
||||
muxer_opt=muxer_opt,
|
||||
|
@ -46,11 +46,9 @@ class PublicKey(Key):
|
||||
...
|
||||
|
||||
def serialize_to_protobuf(self) -> protobuf.PublicKey:
|
||||
_type = self.get_type()
|
||||
key_type = self.get_type().value
|
||||
data = self.to_bytes()
|
||||
protobuf_key = protobuf.PublicKey()
|
||||
protobuf_key.key_type = _type.value
|
||||
protobuf_key.data = data
|
||||
protobuf_key = protobuf.PublicKey(key_type=key_type, data=data)
|
||||
return protobuf_key
|
||||
|
||||
|
||||
@ -68,11 +66,9 @@ class PrivateKey(Key):
|
||||
...
|
||||
|
||||
def serialize_to_protobuf(self) -> protobuf.PrivateKey:
|
||||
_type = self.get_type()
|
||||
key_type = self.get_type().value
|
||||
data = self.to_bytes()
|
||||
protobuf_key = protobuf.PrivateKey()
|
||||
protobuf_key.key_type = _type.value
|
||||
protobuf_key.data = data
|
||||
protobuf_key = protobuf.PrivateKey(key_type=key_type, data=data)
|
||||
return protobuf_key
|
||||
|
||||
|
||||
|
@ -34,11 +34,7 @@ class RawConnection(IRawConnection):
|
||||
|
||||
async def read(self) -> bytes:
|
||||
line = await self.reader.readline()
|
||||
adjusted_line = line.decode().rstrip("\n")
|
||||
|
||||
# TODO: figure out a way to remove \n without going back and forth with
|
||||
# encoding and decoding
|
||||
return adjusted_line.encode()
|
||||
return line.rstrip(b"\n")
|
||||
|
||||
def close(self) -> None:
|
||||
self.writer.close()
|
||||
|
@ -15,7 +15,6 @@ def _serialize_public_key(key: PublicKey) -> bytes:
|
||||
|
||||
|
||||
class ID:
|
||||
|
||||
_bytes: bytes
|
||||
_xor_id: int = None
|
||||
_b58_str: str = None
|
||||
|
52
libp2p/security/base_session.py
Normal file
52
libp2p/security/base_session.py
Normal file
@ -0,0 +1,52 @@
|
||||
from typing import Optional
|
||||
|
||||
from libp2p.crypto.keys import PrivateKey, PublicKey
|
||||
from libp2p.network.connection.raw_connection_interface import IRawConnection
|
||||
from libp2p.peer.id import ID
|
||||
from libp2p.security.base_transport import BaseSecureTransport
|
||||
from libp2p.security.secure_conn_interface import ISecureConn
|
||||
|
||||
|
||||
class BaseSession(ISecureConn, IRawConnection):
|
||||
"""
|
||||
``BaseSession`` is not fully instantiated from its abstract classes as it
|
||||
is only meant to be used in clases that derive from it.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, transport: BaseSecureTransport, conn: IRawConnection, peer_id: ID
|
||||
) -> None:
|
||||
self.local_peer = transport.local_peer
|
||||
self.local_private_key = transport.local_private_key
|
||||
self.conn = conn
|
||||
self.remote_peer_id = peer_id
|
||||
self.remote_permanent_pubkey = None
|
||||
|
||||
self.initiator = self.conn.initiator
|
||||
self.writer = self.conn.writer
|
||||
self.reader = self.conn.reader
|
||||
|
||||
# TODO clean up how this is passed around?
|
||||
def next_stream_id(self) -> int:
|
||||
return self.conn.next_stream_id()
|
||||
|
||||
async def write(self, data: bytes) -> None:
|
||||
await self.conn.write(data)
|
||||
|
||||
async def read(self) -> bytes:
|
||||
return await self.conn.read()
|
||||
|
||||
def close(self) -> None:
|
||||
self.conn.close()
|
||||
|
||||
def get_local_peer(self) -> ID:
|
||||
return self.local_peer
|
||||
|
||||
def get_local_private_key(self) -> PrivateKey:
|
||||
return self.local_private_key
|
||||
|
||||
def get_remote_peer(self) -> ID:
|
||||
return self.remote_peer_id
|
||||
|
||||
def get_remote_public_key(self) -> Optional[PublicKey]:
|
||||
return self.remote_permanent_pubkey
|
14
libp2p/security/base_transport.py
Normal file
14
libp2p/security/base_transport.py
Normal file
@ -0,0 +1,14 @@
|
||||
from libp2p.crypto.keys import KeyPair
|
||||
from libp2p.peer.id import ID
|
||||
from libp2p.security.secure_transport_interface import ISecureTransport
|
||||
|
||||
|
||||
class BaseSecureTransport(ISecureTransport):
|
||||
"""
|
||||
``BaseSecureTransport`` is not fully instantiated from its abstract classes as it
|
||||
is only meant to be used in clases that derive from it.
|
||||
"""
|
||||
|
||||
def __init__(self, local_key_pair: KeyPair) -> None:
|
||||
self.local_private_key = local_key_pair.private_key
|
||||
self.local_peer = ID.from_pubkey(local_key_pair.public_key)
|
32
libp2p/security/insecure/transport.py
Normal file
32
libp2p/security/insecure/transport.py
Normal file
@ -0,0 +1,32 @@
|
||||
from libp2p.network.connection.raw_connection_interface import IRawConnection
|
||||
from libp2p.peer.id import ID
|
||||
from libp2p.security.base_session import BaseSession
|
||||
from libp2p.security.base_transport import BaseSecureTransport
|
||||
from libp2p.security.secure_conn_interface import ISecureConn
|
||||
|
||||
|
||||
class InsecureSession(BaseSession):
|
||||
pass
|
||||
|
||||
|
||||
class InsecureTransport(BaseSecureTransport):
|
||||
"""
|
||||
``InsecureTransport`` provides the "identity" upgrader for a ``IRawConnection``,
|
||||
i.e. the upgraded transport does not add any additional security.
|
||||
"""
|
||||
|
||||
async def secure_inbound(self, conn: IRawConnection) -> ISecureConn:
|
||||
"""
|
||||
Secure the connection, either locally or by communicating with opposing node via conn,
|
||||
for an inbound connection (i.e. we are not the initiator)
|
||||
:return: secure connection object (that implements secure_conn_interface)
|
||||
"""
|
||||
return InsecureSession(self, conn, ID(b""))
|
||||
|
||||
async def secure_outbound(self, conn: IRawConnection, peer_id: ID) -> ISecureConn:
|
||||
"""
|
||||
Secure the connection, either locally or by communicating with opposing node via conn,
|
||||
for an inbound connection (i.e. we are the initiator)
|
||||
:return: secure connection object (that implements secure_conn_interface)
|
||||
"""
|
||||
return InsecureSession(self, conn, peer_id)
|
@ -1,60 +0,0 @@
|
||||
from typing import cast
|
||||
|
||||
from libp2p.network.connection.raw_connection_interface import IRawConnection
|
||||
from libp2p.peer.id import ID
|
||||
from libp2p.security.secure_conn_interface import ISecureConn
|
||||
from libp2p.security.secure_transport_interface import ISecureTransport
|
||||
|
||||
from .typing import TSecurityDetails
|
||||
|
||||
|
||||
class InsecureTransport(ISecureTransport):
|
||||
"""
|
||||
``InsecureTransport`` provides the "identity" upgrader for a ``IRawConnection``,
|
||||
i.e. the upgraded transport does not add any additional security.
|
||||
"""
|
||||
|
||||
transport_id: str
|
||||
|
||||
def __init__(self, transport_id: str) -> None:
|
||||
self.transport_id = transport_id
|
||||
|
||||
async def secure_inbound(self, conn: IRawConnection) -> ISecureConn:
|
||||
"""
|
||||
Secure the connection, either locally or by communicating with opposing node via conn,
|
||||
for an inbound connection (i.e. we are not the initiator)
|
||||
:return: secure connection object (that implements secure_conn_interface)
|
||||
"""
|
||||
insecure_conn = InsecureConn(conn, self.transport_id)
|
||||
return insecure_conn
|
||||
|
||||
async def secure_outbound(self, conn: IRawConnection, peer_id: ID) -> ISecureConn:
|
||||
"""
|
||||
Secure the connection, either locally or by communicating with opposing node via conn,
|
||||
for an inbound connection (i.e. we are the initiator)
|
||||
:return: secure connection object (that implements secure_conn_interface)
|
||||
"""
|
||||
insecure_conn = InsecureConn(conn, self.transport_id)
|
||||
return insecure_conn
|
||||
|
||||
|
||||
class InsecureConn(ISecureConn):
|
||||
conn: IRawConnection
|
||||
details: TSecurityDetails
|
||||
|
||||
def __init__(self, conn: IRawConnection, conn_id: str) -> None:
|
||||
self.conn = conn
|
||||
self.details = cast(TSecurityDetails, {})
|
||||
self.details["id"] = conn_id
|
||||
|
||||
def get_conn(self) -> IRawConnection:
|
||||
"""
|
||||
:return: connection object that has been made secure
|
||||
"""
|
||||
return self.conn
|
||||
|
||||
def get_security_details(self) -> TSecurityDetails:
|
||||
"""
|
||||
:return: map containing details about the connections security
|
||||
"""
|
||||
return self.details
|
0
libp2p/security/secio/__init__.py
Normal file
0
libp2p/security/secio/__init__.py
Normal file
@ -1,8 +1,8 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from libp2p.crypto.keys import PrivateKey, PublicKey
|
||||
from libp2p.network.connection.raw_connection_interface import IRawConnection
|
||||
|
||||
from .typing import TSecurityDetails
|
||||
from libp2p.peer.id import ID
|
||||
|
||||
|
||||
"""
|
||||
@ -13,15 +13,23 @@ Relevant go repo: https://github.com/libp2p/go-conn-security/blob/master/interfa
|
||||
"""
|
||||
|
||||
|
||||
class ISecureConn(ABC):
|
||||
class AbstractSecureConn(ABC):
|
||||
@abstractmethod
|
||||
def get_conn(self) -> IRawConnection:
|
||||
"""
|
||||
:return: the underlying raw connection
|
||||
"""
|
||||
def get_local_peer(self) -> ID:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_security_details(self) -> TSecurityDetails:
|
||||
"""
|
||||
:return: map containing details about the connections security
|
||||
"""
|
||||
def get_local_private_key(self) -> PrivateKey:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_remote_peer(self) -> ID:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_remote_public_key(self) -> PublicKey:
|
||||
pass
|
||||
|
||||
|
||||
class ISecureConn(AbstractSecureConn, IRawConnection):
|
||||
pass
|
||||
|
@ -2,8 +2,7 @@ from abc import ABC, abstractmethod
|
||||
|
||||
from libp2p.network.connection.raw_connection_interface import IRawConnection
|
||||
from libp2p.peer.id import ID
|
||||
|
||||
from .secure_conn_interface import ISecureConn
|
||||
from libp2p.security.secure_conn_interface import ISecureConn
|
||||
|
||||
|
||||
"""
|
||||
|
@ -1,15 +1,14 @@
|
||||
from abc import ABC
|
||||
from typing import Dict
|
||||
from typing import Dict, Mapping
|
||||
|
||||
from libp2p.network.connection.raw_connection_interface import IRawConnection
|
||||
from libp2p.peer.id import ID
|
||||
from libp2p.protocol_muxer.multiselect import Multiselect
|
||||
from libp2p.protocol_muxer.multiselect_client import MultiselectClient
|
||||
from libp2p.security.secure_conn_interface import ISecureConn
|
||||
from libp2p.security.secure_transport_interface import ISecureTransport
|
||||
from libp2p.typing import TProtocol
|
||||
|
||||
from .secure_conn_interface import ISecureConn
|
||||
from .secure_transport_interface import ISecureTransport
|
||||
|
||||
|
||||
"""
|
||||
Represents a secured connection object, which includes a connection and details about the security
|
||||
@ -24,21 +23,19 @@ class SecurityMultistream(ABC):
|
||||
multiselect: Multiselect
|
||||
multiselect_client: MultiselectClient
|
||||
|
||||
def __init__(self) -> None:
|
||||
# Map protocol to secure transport
|
||||
def __init__(
|
||||
self, secure_transports_by_protocol: Mapping[TProtocol, ISecureTransport]
|
||||
) -> None:
|
||||
self.transports = {}
|
||||
|
||||
# Create multiselect
|
||||
self.multiselect = Multiselect()
|
||||
|
||||
# Create multiselect client
|
||||
self.multiselect_client = MultiselectClient()
|
||||
|
||||
for protocol, transport in secure_transports_by_protocol.items():
|
||||
self.add_transport(protocol, transport)
|
||||
|
||||
def add_transport(self, protocol: TProtocol, transport: ISecureTransport) -> None:
|
||||
# Associate protocol with transport
|
||||
self.transports[protocol] = transport
|
||||
|
||||
# Add protocol and handler to multiselect
|
||||
# Note: None is added as the handler for the given protocol since
|
||||
# we only care about selecting the protocol, not any handler function
|
||||
self.multiselect.add_handler(protocol, None)
|
||||
@ -49,13 +46,8 @@ class SecurityMultistream(ABC):
|
||||
for an inbound connection (i.e. we are not the initiator)
|
||||
:return: secure connection object (that implements secure_conn_interface)
|
||||
"""
|
||||
|
||||
# Select a secure transport
|
||||
transport = await self.select_transport(conn, False)
|
||||
|
||||
# Create secured connection
|
||||
secure_conn = await transport.secure_inbound(conn)
|
||||
|
||||
return secure_conn
|
||||
|
||||
async def secure_outbound(self, conn: IRawConnection, peer_id: ID) -> ISecureConn:
|
||||
@ -64,13 +56,8 @@ class SecurityMultistream(ABC):
|
||||
for an inbound connection (i.e. we are the initiator)
|
||||
:return: secure connection object (that implements secure_conn_interface)
|
||||
"""
|
||||
|
||||
# Select a secure transport
|
||||
transport = await self.select_transport(conn, True)
|
||||
|
||||
# Create secured connection
|
||||
secure_conn = await transport.secure_outbound(conn, peer_id)
|
||||
|
||||
return secure_conn
|
||||
|
||||
async def select_transport(
|
||||
|
@ -1,18 +1,18 @@
|
||||
import asyncio
|
||||
from typing import cast
|
||||
|
||||
from libp2p.crypto.keys import KeyPair
|
||||
from libp2p.network.connection.raw_connection_interface import IRawConnection
|
||||
from libp2p.peer.id import ID
|
||||
from libp2p.security.base_transport import BaseSecureTransport
|
||||
from libp2p.security.insecure.transport import InsecureSession
|
||||
from libp2p.security.secure_conn_interface import ISecureConn
|
||||
from libp2p.security.secure_transport_interface import ISecureTransport
|
||||
|
||||
from .typing import TSecurityDetails
|
||||
|
||||
|
||||
class SimpleSecurityTransport(ISecureTransport):
|
||||
class SimpleSecurityTransport(BaseSecureTransport):
|
||||
key_phrase: str
|
||||
|
||||
def __init__(self, key_phrase: str) -> None:
|
||||
def __init__(self, local_key_pair: KeyPair, key_phrase: str) -> None:
|
||||
super().__init__(local_key_pair)
|
||||
self.key_phrase = key_phrase
|
||||
|
||||
async def secure_inbound(self, conn: IRawConnection) -> ISecureConn:
|
||||
@ -29,8 +29,12 @@ class SimpleSecurityTransport(ISecureTransport):
|
||||
"Key phrase differed between nodes. Expected " + self.key_phrase
|
||||
)
|
||||
|
||||
secure_conn = SimpleSecureConn(conn, self.key_phrase)
|
||||
return secure_conn
|
||||
session = InsecureSession(self, conn, ID(b""))
|
||||
# NOTE: this is abusing the abstraction we have here
|
||||
# but this code may be deprecated soon and this exists
|
||||
# mainly to satisfy a test that will go along w/ it
|
||||
session.key_phrase = self.key_phrase
|
||||
return session
|
||||
|
||||
async def secure_outbound(self, conn: IRawConnection, peer_id: ID) -> ISecureConn:
|
||||
"""
|
||||
@ -50,28 +54,9 @@ class SimpleSecurityTransport(ISecureTransport):
|
||||
"Key phrase differed between nodes. Expected " + self.key_phrase
|
||||
)
|
||||
|
||||
secure_conn = SimpleSecureConn(conn, self.key_phrase)
|
||||
return secure_conn
|
||||
|
||||
|
||||
class SimpleSecureConn(ISecureConn):
|
||||
conn: IRawConnection
|
||||
key_phrase: str
|
||||
details: TSecurityDetails
|
||||
|
||||
def __init__(self, conn: IRawConnection, key_phrase: str) -> None:
|
||||
self.conn = conn
|
||||
self.details = cast(TSecurityDetails, {})
|
||||
self.details["key_phrase"] = key_phrase
|
||||
|
||||
def get_conn(self) -> IRawConnection:
|
||||
"""
|
||||
:return: connection object that has been made secure
|
||||
"""
|
||||
return self.conn
|
||||
|
||||
def get_security_details(self) -> TSecurityDetails:
|
||||
"""
|
||||
:return: map containing details about the connections security
|
||||
"""
|
||||
return self.details
|
||||
session = InsecureSession(self, conn, peer_id)
|
||||
# NOTE: this is abusing the abstraction we have here
|
||||
# but this code may be deprecated soon and this exists
|
||||
# mainly to satisfy a test that will go along w/ it
|
||||
session.key_phrase = self.key_phrase
|
||||
return session
|
@ -39,11 +39,8 @@ class Mplex(IMuxedConn):
|
||||
for new muxed streams
|
||||
:param peer_id: peer_id of peer the connection is to
|
||||
"""
|
||||
super().__init__(secured_conn, generic_protocol_handler, peer_id)
|
||||
|
||||
self.secured_conn = secured_conn
|
||||
self.raw_conn = secured_conn.get_conn()
|
||||
self.initiator = self.raw_conn.initiator
|
||||
self.conn = secured_conn
|
||||
self.initiator = secured_conn.initiator
|
||||
|
||||
# Store generic protocol handler
|
||||
self.generic_protocol_handler = generic_protocol_handler
|
||||
@ -63,7 +60,7 @@ class Mplex(IMuxedConn):
|
||||
"""
|
||||
close the stream muxer and underlying raw connection
|
||||
"""
|
||||
self.raw_conn.close()
|
||||
self.conn.close()
|
||||
|
||||
def is_closed(self) -> bool:
|
||||
"""
|
||||
@ -99,7 +96,7 @@ class Mplex(IMuxedConn):
|
||||
:param multi_addr: multi_addr that stream connects to
|
||||
:return: a new stream
|
||||
"""
|
||||
stream_id = self.raw_conn.next_stream_id()
|
||||
stream_id = self.conn.next_stream_id()
|
||||
stream = MplexStream(stream_id, multi_addr, self)
|
||||
self.buffers[stream_id] = asyncio.Queue()
|
||||
await self.send_message(HeaderTags.NewStream, None, stream_id)
|
||||
@ -139,8 +136,8 @@ class Mplex(IMuxedConn):
|
||||
:param _bytes: byte array to write
|
||||
:return: length written
|
||||
"""
|
||||
self.raw_conn.writer.write(_bytes)
|
||||
await self.raw_conn.writer.drain()
|
||||
self.conn.writer.write(_bytes)
|
||||
await self.conn.writer.drain()
|
||||
return len(_bytes)
|
||||
|
||||
async def handle_incoming(self) -> None:
|
||||
@ -177,10 +174,10 @@ class Mplex(IMuxedConn):
|
||||
# loop in handle_incoming
|
||||
timeout = 0.1
|
||||
try:
|
||||
header = await decode_uvarint_from_stream(self.raw_conn.reader, timeout)
|
||||
length = await decode_uvarint_from_stream(self.raw_conn.reader, timeout)
|
||||
header = await decode_uvarint_from_stream(self.conn.reader, timeout)
|
||||
length = await decode_uvarint_from_stream(self.conn.reader, timeout)
|
||||
message = await asyncio.wait_for(
|
||||
self.raw_conn.reader.read(length), timeout=timeout
|
||||
self.conn.reader.read(length), timeout=timeout
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
return None, None, None
|
||||
|
@ -18,14 +18,11 @@ class TransportUpgrader:
|
||||
muxer: Sequence[str]
|
||||
|
||||
def __init__(
|
||||
self, secOpt: Mapping[TProtocol, ISecureTransport], muxerOpt: Sequence[str]
|
||||
) -> None:
|
||||
# Store security option
|
||||
self.security_multistream = SecurityMultistream()
|
||||
for key in secOpt:
|
||||
self.security_multistream.add_transport(key, secOpt[key])
|
||||
|
||||
# Store muxer option
|
||||
self,
|
||||
secure_transports_by_protocol: Mapping[TProtocol, ISecureTransport],
|
||||
muxerOpt: Sequence[str],
|
||||
):
|
||||
self.security_multistream = SecurityMultistream(secure_transports_by_protocol)
|
||||
self.muxer = muxerOpt
|
||||
|
||||
def upgrade_listener(self, transport: ITransport, listeners: IListener) -> None:
|
||||
@ -54,7 +51,5 @@ class TransportUpgrader:
|
||||
"""
|
||||
Upgrade raw connection to muxed connection
|
||||
"""
|
||||
|
||||
# For PoC, no security, default to mplex
|
||||
# TODO do exchange to determine multiplexer
|
||||
return Mplex(conn, generic_protocol_handler, peer_id)
|
||||
|
@ -13,6 +13,7 @@ import multiaddr
|
||||
import pytest
|
||||
|
||||
from libp2p import initialize_default_swarm, new_node
|
||||
from libp2p.crypto.rsa import create_new_key_pair
|
||||
from libp2p.host.basic_host import BasicHost
|
||||
from libp2p.network.notifee_interface import INotifee
|
||||
from tests.utils import (
|
||||
@ -172,14 +173,18 @@ async def test_one_notifier_on_two_nodes():
|
||||
async def test_one_notifier_on_two_nodes_with_listen():
|
||||
events_b = []
|
||||
|
||||
node_a_key_pair = create_new_key_pair()
|
||||
node_a_transport_opt = ["/ip4/127.0.0.1/tcp/0"]
|
||||
node_a = await new_node(transport_opt=node_a_transport_opt)
|
||||
node_a = await new_node(node_a_key_pair, transport_opt=node_a_transport_opt)
|
||||
await node_a.get_network().listen(multiaddr.Multiaddr(node_a_transport_opt[0]))
|
||||
|
||||
# Set up node_b swarm to pass into host
|
||||
node_b_key_pair = create_new_key_pair()
|
||||
node_b_transport_opt = ["/ip4/127.0.0.1/tcp/0"]
|
||||
node_b_multiaddr = multiaddr.Multiaddr(node_b_transport_opt[0])
|
||||
node_b_swarm = initialize_default_swarm(transport_opt=node_b_transport_opt)
|
||||
node_b_swarm = initialize_default_swarm(
|
||||
node_b_key_pair, transport_opt=node_b_transport_opt
|
||||
)
|
||||
node_b = BasicHost(node_b_swarm)
|
||||
|
||||
async def my_stream_handler(stream):
|
||||
|
@ -3,9 +3,13 @@ import asyncio
|
||||
import pytest
|
||||
|
||||
from tests.configs import LISTEN_MADDR
|
||||
|
||||
from .configs import GOSSIPSUB_PARAMS
|
||||
from .factories import FloodsubFactory, GossipsubFactory, HostFactory, PubsubFactory
|
||||
from tests.pubsub.configs import GOSSIPSUB_PARAMS
|
||||
from tests.pubsub.factories import (
|
||||
FloodsubFactory,
|
||||
GossipsubFactory,
|
||||
HostFactory,
|
||||
PubsubFactory,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
@ -1,17 +1,22 @@
|
||||
import factory
|
||||
|
||||
from libp2p import initialize_default_swarm
|
||||
from libp2p.crypto.rsa import create_new_key_pair
|
||||
from libp2p.host.basic_host import BasicHost
|
||||
from libp2p.pubsub.floodsub import FloodSub
|
||||
from libp2p.pubsub.gossipsub import GossipSub
|
||||
from libp2p.pubsub.pubsub import Pubsub
|
||||
from tests.configs import LISTEN_MADDR
|
||||
|
||||
from .configs import FLOODSUB_PROTOCOL_ID, GOSSIPSUB_PARAMS, GOSSIPSUB_PROTOCOL_ID
|
||||
from tests.pubsub.configs import (
|
||||
FLOODSUB_PROTOCOL_ID,
|
||||
GOSSIPSUB_PARAMS,
|
||||
GOSSIPSUB_PROTOCOL_ID,
|
||||
)
|
||||
|
||||
|
||||
def swarm_factory():
|
||||
return initialize_default_swarm(transport_opt=[str(LISTEN_MADDR)])
|
||||
private_key = create_new_key_pair()
|
||||
return initialize_default_swarm(private_key, transport_opt=[str(LISTEN_MADDR)])
|
||||
|
||||
|
||||
class HostFactory(factory.Factory):
|
||||
|
@ -189,6 +189,7 @@ async def test_set_then_send_from_diff_nodes_five_nodes_ring_topography():
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.slow
|
||||
async def test_set_then_send_from_five_diff_nodes_five_nodes_ring_topography():
|
||||
num_nodes = 5
|
||||
adj_map = {0: [1], 1: [2], 2: [3], 3: [4], 4: [0]}
|
||||
|
@ -87,5 +87,6 @@ async def test_lru_cache_two_nodes(pubsubs_fsub, monkeypatch):
|
||||
|
||||
@pytest.mark.parametrize("test_case_obj", floodsub_protocol_pytest_params)
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.slow
|
||||
async def test_gossipsub_run_with_floodsub_tests(test_case_obj):
|
||||
await perform_test_from_obj(test_case_obj, FloodsubFactory)
|
||||
|
@ -268,6 +268,7 @@ async def test_fanout(hosts, pubsubs_gsub):
|
||||
|
||||
@pytest.mark.parametrize("num_hosts", (10,))
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.slow
|
||||
async def test_fanout_maintenance(hosts, pubsubs_gsub):
|
||||
num_msgs = 5
|
||||
|
||||
|
@ -17,6 +17,7 @@ async def test_gossipsub_initialize_with_floodsub_protocol():
|
||||
|
||||
@pytest.mark.parametrize("test_case_obj", floodsub_protocol_pytest_params)
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.slow
|
||||
async def test_gossipsub_run_with_floodsub_tests(test_case_obj):
|
||||
await perform_test_from_obj(
|
||||
test_case_obj,
|
||||
|
@ -4,10 +4,11 @@ import multiaddr
|
||||
import pytest
|
||||
|
||||
from libp2p import new_node
|
||||
from libp2p.crypto.rsa import create_new_key_pair
|
||||
from libp2p.peer.peerinfo import info_from_p2p_addr
|
||||
from libp2p.protocol_muxer.multiselect_client import MultiselectClientError
|
||||
from libp2p.security.insecure_security import InsecureTransport
|
||||
from libp2p.security.simple_security import SimpleSecurityTransport
|
||||
from libp2p.security.insecure.transport import InsecureSession, InsecureTransport
|
||||
from libp2p.security.simple.transport import SimpleSecurityTransport
|
||||
from tests.utils import cleanup, connect
|
||||
|
||||
# TODO: Add tests for multiple streams being opened on different
|
||||
@ -20,6 +21,11 @@ def peer_id_for_node(node):
|
||||
return info.peer_id
|
||||
|
||||
|
||||
initiator_key_pair = create_new_key_pair()
|
||||
|
||||
noninitiator_key_pair = create_new_key_pair()
|
||||
|
||||
|
||||
async def perform_simple_test(
|
||||
assertion_func, transports_for_initiator, transports_for_noninitiator
|
||||
):
|
||||
@ -50,8 +56,8 @@ async def perform_simple_test(
|
||||
node2_conn = node2.get_network().connections[peer_id_for_node(node1)]
|
||||
|
||||
# Perform assertion
|
||||
assertion_func(node1_conn.secured_conn.get_security_details())
|
||||
assertion_func(node2_conn.secured_conn.get_security_details())
|
||||
assertion_func(node1_conn.conn)
|
||||
assertion_func(node2_conn.conn)
|
||||
|
||||
# Success, terminate pending tasks.
|
||||
await cleanup()
|
||||
@ -59,11 +65,11 @@ async def perform_simple_test(
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_single_insecure_security_transport_succeeds():
|
||||
transports_for_initiator = {"foo": InsecureTransport("foo")}
|
||||
transports_for_noninitiator = {"foo": InsecureTransport("foo")}
|
||||
transports_for_initiator = {"foo": InsecureTransport(initiator_key_pair)}
|
||||
transports_for_noninitiator = {"foo": InsecureTransport(noninitiator_key_pair)}
|
||||
|
||||
def assertion_func(details):
|
||||
assert details["id"] == "foo"
|
||||
def assertion_func(conn):
|
||||
assert isinstance(conn, InsecureSession)
|
||||
|
||||
await perform_simple_test(
|
||||
assertion_func, transports_for_initiator, transports_for_noninitiator
|
||||
@ -72,11 +78,15 @@ async def test_single_insecure_security_transport_succeeds():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_single_simple_test_security_transport_succeeds():
|
||||
transports_for_initiator = {"tacos": SimpleSecurityTransport("tacos")}
|
||||
transports_for_noninitiator = {"tacos": SimpleSecurityTransport("tacos")}
|
||||
transports_for_initiator = {
|
||||
"tacos": SimpleSecurityTransport(initiator_key_pair, "tacos")
|
||||
}
|
||||
transports_for_noninitiator = {
|
||||
"tacos": SimpleSecurityTransport(noninitiator_key_pair, "tacos")
|
||||
}
|
||||
|
||||
def assertion_func(details):
|
||||
assert details["key_phrase"] == "tacos"
|
||||
def assertion_func(conn):
|
||||
assert conn.key_phrase == "tacos"
|
||||
|
||||
await perform_simple_test(
|
||||
assertion_func, transports_for_initiator, transports_for_noninitiator
|
||||
@ -86,13 +96,15 @@ async def test_single_simple_test_security_transport_succeeds():
|
||||
@pytest.mark.asyncio
|
||||
async def test_two_simple_test_security_transport_for_initiator_succeeds():
|
||||
transports_for_initiator = {
|
||||
"tacos": SimpleSecurityTransport("tacos"),
|
||||
"shleep": SimpleSecurityTransport("shleep"),
|
||||
"tacos": SimpleSecurityTransport(initiator_key_pair, "tacos"),
|
||||
"shleep": SimpleSecurityTransport(initiator_key_pair, "shleep"),
|
||||
}
|
||||
transports_for_noninitiator = {
|
||||
"shleep": SimpleSecurityTransport(noninitiator_key_pair, "shleep")
|
||||
}
|
||||
transports_for_noninitiator = {"shleep": SimpleSecurityTransport("shleep")}
|
||||
|
||||
def assertion_func(details):
|
||||
assert details["key_phrase"] == "shleep"
|
||||
def assertion_func(conn):
|
||||
assert conn.key_phrase == "shleep"
|
||||
|
||||
await perform_simple_test(
|
||||
assertion_func, transports_for_initiator, transports_for_noninitiator
|
||||
@ -101,14 +113,16 @@ async def test_two_simple_test_security_transport_for_initiator_succeeds():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_two_simple_test_security_transport_for_noninitiator_succeeds():
|
||||
transports_for_initiator = {"tacos": SimpleSecurityTransport("tacos")}
|
||||
transports_for_initiator = {
|
||||
"tacos": SimpleSecurityTransport(initiator_key_pair, "tacos")
|
||||
}
|
||||
transports_for_noninitiator = {
|
||||
"shleep": SimpleSecurityTransport("shleep"),
|
||||
"tacos": SimpleSecurityTransport("tacos"),
|
||||
"shleep": SimpleSecurityTransport(noninitiator_key_pair, "shleep"),
|
||||
"tacos": SimpleSecurityTransport(noninitiator_key_pair, "tacos"),
|
||||
}
|
||||
|
||||
def assertion_func(details):
|
||||
assert details["key_phrase"] == "tacos"
|
||||
def assertion_func(conn):
|
||||
assert conn.key_phrase == "tacos"
|
||||
|
||||
await perform_simple_test(
|
||||
assertion_func, transports_for_initiator, transports_for_noninitiator
|
||||
@ -118,16 +132,16 @@ async def test_two_simple_test_security_transport_for_noninitiator_succeeds():
|
||||
@pytest.mark.asyncio
|
||||
async def test_two_simple_test_security_transport_for_both_succeeds():
|
||||
transports_for_initiator = {
|
||||
"a": SimpleSecurityTransport("a"),
|
||||
"b": SimpleSecurityTransport("b"),
|
||||
"a": SimpleSecurityTransport(initiator_key_pair, "a"),
|
||||
"b": SimpleSecurityTransport(initiator_key_pair, "b"),
|
||||
}
|
||||
transports_for_noninitiator = {
|
||||
"c": SimpleSecurityTransport("c"),
|
||||
"b": SimpleSecurityTransport("b"),
|
||||
"b": SimpleSecurityTransport(noninitiator_key_pair, "b"),
|
||||
"c": SimpleSecurityTransport(noninitiator_key_pair, "c"),
|
||||
}
|
||||
|
||||
def assertion_func(details):
|
||||
assert details["key_phrase"] == "b"
|
||||
def assertion_func(conn):
|
||||
assert conn.key_phrase == "b"
|
||||
|
||||
await perform_simple_test(
|
||||
assertion_func, transports_for_initiator, transports_for_noninitiator
|
||||
@ -137,12 +151,12 @@ async def test_two_simple_test_security_transport_for_both_succeeds():
|
||||
@pytest.mark.asyncio
|
||||
async def test_multiple_security_none_the_same_fails():
|
||||
transports_for_initiator = {
|
||||
"a": SimpleSecurityTransport("a"),
|
||||
"b": SimpleSecurityTransport("b"),
|
||||
"a": SimpleSecurityTransport(initiator_key_pair, "a"),
|
||||
"b": SimpleSecurityTransport(initiator_key_pair, "b"),
|
||||
}
|
||||
transports_for_noninitiator = {
|
||||
"c": SimpleSecurityTransport("c"),
|
||||
"d": SimpleSecurityTransport("d"),
|
||||
"d": SimpleSecurityTransport(noninitiator_key_pair, "d"),
|
||||
"c": SimpleSecurityTransport(noninitiator_key_pair, "c"),
|
||||
}
|
||||
|
||||
def assertion_func(_):
|
||||
@ -161,18 +175,18 @@ async def test_default_insecure_security():
|
||||
transports_for_initiator = None
|
||||
transports_for_noninitiator = None
|
||||
|
||||
details1 = None
|
||||
details2 = None
|
||||
conn1 = None
|
||||
conn2 = None
|
||||
|
||||
def assertion_func(details):
|
||||
nonlocal details1
|
||||
nonlocal details2
|
||||
if not details1:
|
||||
details1 = details
|
||||
elif not details2:
|
||||
details2 = details
|
||||
def assertion_func(conn):
|
||||
nonlocal conn1
|
||||
nonlocal conn2
|
||||
if not conn1:
|
||||
conn1 = conn
|
||||
elif not conn2:
|
||||
conn2 = conn
|
||||
else:
|
||||
assert details1 == details2
|
||||
assert conn1 == conn2
|
||||
|
||||
await perform_simple_test(
|
||||
assertion_func, transports_for_initiator, transports_for_noninitiator
|
||||
|
Loading…
x
Reference in New Issue
Block a user