diff --git a/libp2p/__init__.py b/libp2p/__init__.py index af72cb81..a69f6f61 100644 --- a/libp2p/__init__.py +++ b/libp2p/__init__.py @@ -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, diff --git a/libp2p/crypto/keys.py b/libp2p/crypto/keys.py index 4a43b41f..b0dec3d9 100644 --- a/libp2p/crypto/keys.py +++ b/libp2p/crypto/keys.py @@ -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 diff --git a/libp2p/network/connection/raw_connection.py b/libp2p/network/connection/raw_connection.py index abde0066..3d12f0d5 100644 --- a/libp2p/network/connection/raw_connection.py +++ b/libp2p/network/connection/raw_connection.py @@ -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() diff --git a/libp2p/peer/id.py b/libp2p/peer/id.py index bfb78d0e..26029b62 100644 --- a/libp2p/peer/id.py +++ b/libp2p/peer/id.py @@ -15,7 +15,6 @@ def _serialize_public_key(key: PublicKey) -> bytes: class ID: - _bytes: bytes _xor_id: int = None _b58_str: str = None diff --git a/libp2p/security/base_session.py b/libp2p/security/base_session.py new file mode 100644 index 00000000..8fc4dabe --- /dev/null +++ b/libp2p/security/base_session.py @@ -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 diff --git a/libp2p/security/base_transport.py b/libp2p/security/base_transport.py new file mode 100644 index 00000000..0f096bfc --- /dev/null +++ b/libp2p/security/base_transport.py @@ -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) diff --git a/libp2p/security/insecure/transport.py b/libp2p/security/insecure/transport.py new file mode 100644 index 00000000..2d8a5a83 --- /dev/null +++ b/libp2p/security/insecure/transport.py @@ -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) diff --git a/libp2p/security/insecure_security.py b/libp2p/security/insecure_security.py deleted file mode 100644 index ce3f018b..00000000 --- a/libp2p/security/insecure_security.py +++ /dev/null @@ -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 diff --git a/libp2p/security/secio/__init__.py b/libp2p/security/secio/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/libp2p/security/secure_conn_interface.py b/libp2p/security/secure_conn_interface.py index 46bb83c1..ab69a6d0 100644 --- a/libp2p/security/secure_conn_interface.py +++ b/libp2p/security/secure_conn_interface.py @@ -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 diff --git a/libp2p/security/secure_transport_interface.py b/libp2p/security/secure_transport_interface.py index bf6dfd31..3b3e6256 100644 --- a/libp2p/security/secure_transport_interface.py +++ b/libp2p/security/secure_transport_interface.py @@ -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 """ diff --git a/libp2p/security/security_multistream.py b/libp2p/security/security_multistream.py index b2fd2bde..fcb85a73 100644 --- a/libp2p/security/security_multistream.py +++ b/libp2p/security/security_multistream.py @@ -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( diff --git a/libp2p/security/simple_security.py b/libp2p/security/simple/transport.py similarity index 60% rename from libp2p/security/simple_security.py rename to libp2p/security/simple/transport.py index 4fb0a3cf..5ff07cdd 100644 --- a/libp2p/security/simple_security.py +++ b/libp2p/security/simple/transport.py @@ -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 diff --git a/libp2p/stream_muxer/mplex/mplex.py b/libp2p/stream_muxer/mplex/mplex.py index 16d36134..95336d94 100644 --- a/libp2p/stream_muxer/mplex/mplex.py +++ b/libp2p/stream_muxer/mplex/mplex.py @@ -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 diff --git a/libp2p/transport/upgrader.py b/libp2p/transport/upgrader.py index 28d4a51b..f727767c 100644 --- a/libp2p/transport/upgrader.py +++ b/libp2p/transport/upgrader.py @@ -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) diff --git a/tests/libp2p/test_notify.py b/tests/libp2p/test_notify.py index 7dd3ccbc..f4bd2efc 100644 --- a/tests/libp2p/test_notify.py +++ b/tests/libp2p/test_notify.py @@ -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): diff --git a/tests/pubsub/conftest.py b/tests/pubsub/conftest.py index 3c4a34b5..82b77828 100644 --- a/tests/pubsub/conftest.py +++ b/tests/pubsub/conftest.py @@ -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 diff --git a/tests/pubsub/factories.py b/tests/pubsub/factories.py index 5572ce12..b57c29bc 100644 --- a/tests/pubsub/factories.py +++ b/tests/pubsub/factories.py @@ -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): diff --git a/tests/pubsub/test_dummyaccount_demo.py b/tests/pubsub/test_dummyaccount_demo.py index 6a604e54..b365134f 100644 --- a/tests/pubsub/test_dummyaccount_demo.py +++ b/tests/pubsub/test_dummyaccount_demo.py @@ -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]} diff --git a/tests/pubsub/test_floodsub.py b/tests/pubsub/test_floodsub.py index c6599293..0a67c654 100644 --- a/tests/pubsub/test_floodsub.py +++ b/tests/pubsub/test_floodsub.py @@ -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) diff --git a/tests/pubsub/test_gossipsub.py b/tests/pubsub/test_gossipsub.py index 83ab7868..e091f669 100644 --- a/tests/pubsub/test_gossipsub.py +++ b/tests/pubsub/test_gossipsub.py @@ -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 diff --git a/tests/pubsub/test_gossipsub_backward_compatibility.py b/tests/pubsub/test_gossipsub_backward_compatibility.py index 05b6c402..e76ce049 100644 --- a/tests/pubsub/test_gossipsub_backward_compatibility.py +++ b/tests/pubsub/test_gossipsub_backward_compatibility.py @@ -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, diff --git a/tests/security/test_security_multistream.py b/tests/security/test_security_multistream.py index 070f29dd..ddbae8e3 100644 --- a/tests/security/test_security_multistream.py +++ b/tests/security/test_security_multistream.py @@ -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