Merge pull request #250 from ralexstokes/add-secio-groundwork

Add secio groundwork
This commit is contained in:
Alex Stokes
2019-08-15 19:32:17 -07:00
committed by GitHub
23 changed files with 270 additions and 224 deletions

View File

@ -1,6 +1,7 @@
import asyncio import asyncio
from typing import Mapping, Sequence from typing import Mapping, Sequence
from libp2p.crypto.keys import KeyPair
from libp2p.crypto.rsa import create_new_key_pair from libp2p.crypto.rsa import create_new_key_pair
from libp2p.host.basic_host import BasicHost from libp2p.host.basic_host import BasicHost
from libp2p.kademlia.network import KademliaServer 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.peer.peerstore_interface import IPeerStore
from libp2p.routing.interfaces import IPeerRouting from libp2p.routing.interfaces import IPeerRouting
from libp2p.routing.kademlia.kademlia_peer_router import KadmeliaPeerRouter 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.security.secure_transport_interface import ISecureTransport
from libp2p.transport.tcp.tcp import TCP from libp2p.transport.tcp.tcp import TCP
from libp2p.transport.upgrader import TransportUpgrader from libp2p.transport.upgrader import TransportUpgrader
@ -33,11 +34,15 @@ async def cleanup_done_tasks() -> None:
await asyncio.sleep(3) await asyncio.sleep(3)
def generate_peer_id_from_rsa_identity() -> ID: def generate_new_rsa_identity() -> KeyPair:
new_key_pair = create_new_key_pair() return 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_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( def initialize_default_kademlia_router(
@ -64,6 +69,7 @@ def initialize_default_kademlia_router(
def initialize_default_swarm( def initialize_default_swarm(
key_pair: KeyPair,
id_opt: ID = None, id_opt: ID = None,
transport_opt: Sequence[str] = None, transport_opt: Sequence[str] = None,
muxer_opt: Sequence[str] = None, muxer_opt: Sequence[str] = None,
@ -83,7 +89,7 @@ def initialize_default_swarm(
""" """
if not id_opt: 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 # TODO parse transport_opt to determine transport
transport_opt = transport_opt or ["/ip4/127.0.0.1/tcp/8001"] 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 TransportUpgrader is not doing anything really
# TODO parse muxer and sec to pass into TransportUpgrader # TODO parse muxer and sec to pass into TransportUpgrader
muxer = muxer_opt or ["mplex/6.7.0"] muxer = muxer_opt or ["mplex/6.7.0"]
sec = sec_opt or {TProtocol("insecure/1.0.0"): InsecureTransport("insecure")} security_transports_by_protocol = sec_opt or {
upgrader = TransportUpgrader(sec, muxer) TProtocol("insecure/1.0.0"): InsecureTransport(key_pair)
}
upgrader = TransportUpgrader(security_transports_by_protocol, muxer)
peerstore = peerstore_opt or PeerStore() peerstore = peerstore_opt or PeerStore()
# TODO: Initialize discovery if not presented # TODO: Initialize discovery if not presented
@ -103,6 +111,7 @@ def initialize_default_swarm(
async def new_node( async def new_node(
key_pair: KeyPair = None,
swarm_opt: INetwork = None, swarm_opt: INetwork = None,
id_opt: ID = None, id_opt: ID = None,
transport_opt: Sequence[str] = None, transport_opt: Sequence[str] = None,
@ -113,6 +122,7 @@ async def new_node(
) -> BasicHost: ) -> BasicHost:
""" """
create new libp2p node create new libp2p node
:param key_pair: key pair for deriving an identity
:param swarm_opt: optional swarm :param swarm_opt: optional swarm
:param id_opt: optional id for host :param id_opt: optional id for host
:param transport_opt: optional choice of transport upgrade :param transport_opt: optional choice of transport upgrade
@ -123,11 +133,15 @@ async def new_node(
:return: return a host instance :return: return a host instance
""" """
if not key_pair:
key_pair = generate_new_rsa_identity()
if not id_opt: 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: if not swarm_opt:
swarm_opt = initialize_default_swarm( swarm_opt = initialize_default_swarm(
key_pair=key_pair,
id_opt=id_opt, id_opt=id_opt,
transport_opt=transport_opt, transport_opt=transport_opt,
muxer_opt=muxer_opt, muxer_opt=muxer_opt,

View File

@ -46,11 +46,9 @@ class PublicKey(Key):
... ...
def serialize_to_protobuf(self) -> protobuf.PublicKey: def serialize_to_protobuf(self) -> protobuf.PublicKey:
_type = self.get_type() key_type = self.get_type().value
data = self.to_bytes() data = self.to_bytes()
protobuf_key = protobuf.PublicKey() protobuf_key = protobuf.PublicKey(key_type=key_type, data=data)
protobuf_key.key_type = _type.value
protobuf_key.data = data
return protobuf_key return protobuf_key
@ -68,11 +66,9 @@ class PrivateKey(Key):
... ...
def serialize_to_protobuf(self) -> protobuf.PrivateKey: def serialize_to_protobuf(self) -> protobuf.PrivateKey:
_type = self.get_type() key_type = self.get_type().value
data = self.to_bytes() data = self.to_bytes()
protobuf_key = protobuf.PrivateKey() protobuf_key = protobuf.PrivateKey(key_type=key_type, data=data)
protobuf_key.key_type = _type.value
protobuf_key.data = data
return protobuf_key return protobuf_key

View File

@ -34,11 +34,7 @@ class RawConnection(IRawConnection):
async def read(self) -> bytes: async def read(self) -> bytes:
line = await self.reader.readline() line = await self.reader.readline()
adjusted_line = line.decode().rstrip("\n") return line.rstrip(b"\n")
# TODO: figure out a way to remove \n without going back and forth with
# encoding and decoding
return adjusted_line.encode()
def close(self) -> None: def close(self) -> None:
self.writer.close() self.writer.close()

View File

@ -15,7 +15,6 @@ def _serialize_public_key(key: PublicKey) -> bytes:
class ID: class ID:
_bytes: bytes _bytes: bytes
_xor_id: int = None _xor_id: int = None
_b58_str: str = None _b58_str: str = None

View 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

View 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)

View 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)

View File

@ -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

View File

View File

@ -1,8 +1,8 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from libp2p.crypto.keys import PrivateKey, PublicKey
from libp2p.network.connection.raw_connection_interface import IRawConnection from libp2p.network.connection.raw_connection_interface import IRawConnection
from libp2p.peer.id import ID
from .typing import TSecurityDetails
""" """
@ -13,15 +13,23 @@ Relevant go repo: https://github.com/libp2p/go-conn-security/blob/master/interfa
""" """
class ISecureConn(ABC): class AbstractSecureConn(ABC):
@abstractmethod @abstractmethod
def get_conn(self) -> IRawConnection: def get_local_peer(self) -> ID:
""" pass
:return: the underlying raw connection
"""
@abstractmethod @abstractmethod
def get_security_details(self) -> TSecurityDetails: def get_local_private_key(self) -> PrivateKey:
""" pass
:return: map containing details about the connections security
""" @abstractmethod
def get_remote_peer(self) -> ID:
pass
@abstractmethod
def get_remote_public_key(self) -> PublicKey:
pass
class ISecureConn(AbstractSecureConn, IRawConnection):
pass

View File

@ -2,8 +2,7 @@ from abc import ABC, abstractmethod
from libp2p.network.connection.raw_connection_interface import IRawConnection from libp2p.network.connection.raw_connection_interface import IRawConnection
from libp2p.peer.id import ID from libp2p.peer.id import ID
from libp2p.security.secure_conn_interface import ISecureConn
from .secure_conn_interface import ISecureConn
""" """

View File

@ -1,15 +1,14 @@
from abc import ABC from abc import ABC
from typing import Dict from typing import Dict, Mapping
from libp2p.network.connection.raw_connection_interface import IRawConnection from libp2p.network.connection.raw_connection_interface import IRawConnection
from libp2p.peer.id import ID from libp2p.peer.id import ID
from libp2p.protocol_muxer.multiselect import Multiselect from libp2p.protocol_muxer.multiselect import Multiselect
from libp2p.protocol_muxer.multiselect_client import MultiselectClient 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 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 Represents a secured connection object, which includes a connection and details about the security
@ -24,21 +23,19 @@ class SecurityMultistream(ABC):
multiselect: Multiselect multiselect: Multiselect
multiselect_client: MultiselectClient multiselect_client: MultiselectClient
def __init__(self) -> None: def __init__(
# Map protocol to secure transport self, secure_transports_by_protocol: Mapping[TProtocol, ISecureTransport]
) -> None:
self.transports = {} self.transports = {}
# Create multiselect
self.multiselect = Multiselect() self.multiselect = Multiselect()
# Create multiselect client
self.multiselect_client = MultiselectClient() 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: def add_transport(self, protocol: TProtocol, transport: ISecureTransport) -> None:
# Associate protocol with transport
self.transports[protocol] = transport self.transports[protocol] = transport
# Add protocol and handler to multiselect
# Note: None is added as the handler for the given protocol since # Note: None is added as the handler for the given protocol since
# we only care about selecting the protocol, not any handler function # we only care about selecting the protocol, not any handler function
self.multiselect.add_handler(protocol, None) self.multiselect.add_handler(protocol, None)
@ -49,13 +46,8 @@ class SecurityMultistream(ABC):
for an inbound connection (i.e. we are not the initiator) for an inbound connection (i.e. we are not the initiator)
:return: secure connection object (that implements secure_conn_interface) :return: secure connection object (that implements secure_conn_interface)
""" """
# Select a secure transport
transport = await self.select_transport(conn, False) transport = await self.select_transport(conn, False)
# Create secured connection
secure_conn = await transport.secure_inbound(conn) secure_conn = await transport.secure_inbound(conn)
return secure_conn return secure_conn
async def secure_outbound(self, conn: IRawConnection, peer_id: ID) -> ISecureConn: 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) for an inbound connection (i.e. we are the initiator)
:return: secure connection object (that implements secure_conn_interface) :return: secure connection object (that implements secure_conn_interface)
""" """
# Select a secure transport
transport = await self.select_transport(conn, True) transport = await self.select_transport(conn, True)
# Create secured connection
secure_conn = await transport.secure_outbound(conn, peer_id) secure_conn = await transport.secure_outbound(conn, peer_id)
return secure_conn return secure_conn
async def select_transport( async def select_transport(

View File

@ -1,18 +1,18 @@
import asyncio import asyncio
from typing import cast
from libp2p.crypto.keys import KeyPair
from libp2p.network.connection.raw_connection_interface import IRawConnection from libp2p.network.connection.raw_connection_interface import IRawConnection
from libp2p.peer.id import ID 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_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 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 self.key_phrase = key_phrase
async def secure_inbound(self, conn: IRawConnection) -> ISecureConn: async def secure_inbound(self, conn: IRawConnection) -> ISecureConn:
@ -29,8 +29,12 @@ class SimpleSecurityTransport(ISecureTransport):
"Key phrase differed between nodes. Expected " + self.key_phrase "Key phrase differed between nodes. Expected " + self.key_phrase
) )
secure_conn = SimpleSecureConn(conn, self.key_phrase) session = InsecureSession(self, conn, ID(b""))
return secure_conn # 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: 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 "Key phrase differed between nodes. Expected " + self.key_phrase
) )
secure_conn = SimpleSecureConn(conn, self.key_phrase) session = InsecureSession(self, conn, peer_id)
return secure_conn # 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
class SimpleSecureConn(ISecureConn): session.key_phrase = self.key_phrase
conn: IRawConnection return session
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

View File

@ -39,11 +39,8 @@ class Mplex(IMuxedConn):
for new muxed streams for new muxed streams
:param peer_id: peer_id of peer the connection is to :param peer_id: peer_id of peer the connection is to
""" """
super().__init__(secured_conn, generic_protocol_handler, peer_id) self.conn = secured_conn
self.initiator = secured_conn.initiator
self.secured_conn = secured_conn
self.raw_conn = secured_conn.get_conn()
self.initiator = self.raw_conn.initiator
# Store generic protocol handler # Store generic protocol handler
self.generic_protocol_handler = 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 close the stream muxer and underlying raw connection
""" """
self.raw_conn.close() self.conn.close()
def is_closed(self) -> bool: def is_closed(self) -> bool:
""" """
@ -99,7 +96,7 @@ class Mplex(IMuxedConn):
:param multi_addr: multi_addr that stream connects to :param multi_addr: multi_addr that stream connects to
:return: a new stream :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) stream = MplexStream(stream_id, multi_addr, self)
self.buffers[stream_id] = asyncio.Queue() self.buffers[stream_id] = asyncio.Queue()
await self.send_message(HeaderTags.NewStream, None, stream_id) await self.send_message(HeaderTags.NewStream, None, stream_id)
@ -139,8 +136,8 @@ class Mplex(IMuxedConn):
:param _bytes: byte array to write :param _bytes: byte array to write
:return: length written :return: length written
""" """
self.raw_conn.writer.write(_bytes) self.conn.writer.write(_bytes)
await self.raw_conn.writer.drain() await self.conn.writer.drain()
return len(_bytes) return len(_bytes)
async def handle_incoming(self) -> None: async def handle_incoming(self) -> None:
@ -177,10 +174,10 @@ class Mplex(IMuxedConn):
# loop in handle_incoming # loop in handle_incoming
timeout = 0.1 timeout = 0.1
try: try:
header = 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.raw_conn.reader, timeout) length = await decode_uvarint_from_stream(self.conn.reader, timeout)
message = await asyncio.wait_for( message = await asyncio.wait_for(
self.raw_conn.reader.read(length), timeout=timeout self.conn.reader.read(length), timeout=timeout
) )
except asyncio.TimeoutError: except asyncio.TimeoutError:
return None, None, None return None, None, None

View File

@ -18,14 +18,11 @@ class TransportUpgrader:
muxer: Sequence[str] muxer: Sequence[str]
def __init__( def __init__(
self, secOpt: Mapping[TProtocol, ISecureTransport], muxerOpt: Sequence[str] self,
) -> None: secure_transports_by_protocol: Mapping[TProtocol, ISecureTransport],
# Store security option muxerOpt: Sequence[str],
self.security_multistream = SecurityMultistream() ):
for key in secOpt: self.security_multistream = SecurityMultistream(secure_transports_by_protocol)
self.security_multistream.add_transport(key, secOpt[key])
# Store muxer option
self.muxer = muxerOpt self.muxer = muxerOpt
def upgrade_listener(self, transport: ITransport, listeners: IListener) -> None: def upgrade_listener(self, transport: ITransport, listeners: IListener) -> None:
@ -54,7 +51,5 @@ class TransportUpgrader:
""" """
Upgrade raw connection to muxed connection Upgrade raw connection to muxed connection
""" """
# For PoC, no security, default to mplex
# TODO do exchange to determine multiplexer # TODO do exchange to determine multiplexer
return Mplex(conn, generic_protocol_handler, peer_id) return Mplex(conn, generic_protocol_handler, peer_id)

View File

@ -13,6 +13,7 @@ import multiaddr
import pytest import pytest
from libp2p import initialize_default_swarm, new_node 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.host.basic_host import BasicHost
from libp2p.network.notifee_interface import INotifee from libp2p.network.notifee_interface import INotifee
from tests.utils import ( 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(): async def test_one_notifier_on_two_nodes_with_listen():
events_b = [] events_b = []
node_a_key_pair = create_new_key_pair()
node_a_transport_opt = ["/ip4/127.0.0.1/tcp/0"] 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])) await node_a.get_network().listen(multiaddr.Multiaddr(node_a_transport_opt[0]))
# Set up node_b swarm to pass into host # 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_transport_opt = ["/ip4/127.0.0.1/tcp/0"]
node_b_multiaddr = multiaddr.Multiaddr(node_b_transport_opt[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) node_b = BasicHost(node_b_swarm)
async def my_stream_handler(stream): async def my_stream_handler(stream):

View File

@ -3,9 +3,13 @@ import asyncio
import pytest import pytest
from tests.configs import LISTEN_MADDR from tests.configs import LISTEN_MADDR
from tests.pubsub.configs import GOSSIPSUB_PARAMS
from .configs import GOSSIPSUB_PARAMS from tests.pubsub.factories import (
from .factories import FloodsubFactory, GossipsubFactory, HostFactory, PubsubFactory FloodsubFactory,
GossipsubFactory,
HostFactory,
PubsubFactory,
)
@pytest.fixture @pytest.fixture

View File

@ -1,17 +1,22 @@
import factory import factory
from libp2p import initialize_default_swarm from libp2p import initialize_default_swarm
from libp2p.crypto.rsa import create_new_key_pair
from libp2p.host.basic_host import BasicHost from libp2p.host.basic_host import BasicHost
from libp2p.pubsub.floodsub import FloodSub from libp2p.pubsub.floodsub import FloodSub
from libp2p.pubsub.gossipsub import GossipSub from libp2p.pubsub.gossipsub import GossipSub
from libp2p.pubsub.pubsub import Pubsub from libp2p.pubsub.pubsub import Pubsub
from tests.configs import LISTEN_MADDR from tests.configs import LISTEN_MADDR
from tests.pubsub.configs import (
from .configs import FLOODSUB_PROTOCOL_ID, GOSSIPSUB_PARAMS, GOSSIPSUB_PROTOCOL_ID FLOODSUB_PROTOCOL_ID,
GOSSIPSUB_PARAMS,
GOSSIPSUB_PROTOCOL_ID,
)
def swarm_factory(): 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): class HostFactory(factory.Factory):

View File

@ -189,6 +189,7 @@ async def test_set_then_send_from_diff_nodes_five_nodes_ring_topography():
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.slow
async def test_set_then_send_from_five_diff_nodes_five_nodes_ring_topography(): async def test_set_then_send_from_five_diff_nodes_five_nodes_ring_topography():
num_nodes = 5 num_nodes = 5
adj_map = {0: [1], 1: [2], 2: [3], 3: [4], 4: [0]} adj_map = {0: [1], 1: [2], 2: [3], 3: [4], 4: [0]}

View File

@ -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.parametrize("test_case_obj", floodsub_protocol_pytest_params)
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.slow
async def test_gossipsub_run_with_floodsub_tests(test_case_obj): async def test_gossipsub_run_with_floodsub_tests(test_case_obj):
await perform_test_from_obj(test_case_obj, FloodsubFactory) await perform_test_from_obj(test_case_obj, FloodsubFactory)

View File

@ -268,6 +268,7 @@ async def test_fanout(hosts, pubsubs_gsub):
@pytest.mark.parametrize("num_hosts", (10,)) @pytest.mark.parametrize("num_hosts", (10,))
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.slow
async def test_fanout_maintenance(hosts, pubsubs_gsub): async def test_fanout_maintenance(hosts, pubsubs_gsub):
num_msgs = 5 num_msgs = 5

View File

@ -17,6 +17,7 @@ async def test_gossipsub_initialize_with_floodsub_protocol():
@pytest.mark.parametrize("test_case_obj", floodsub_protocol_pytest_params) @pytest.mark.parametrize("test_case_obj", floodsub_protocol_pytest_params)
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.slow
async def test_gossipsub_run_with_floodsub_tests(test_case_obj): async def test_gossipsub_run_with_floodsub_tests(test_case_obj):
await perform_test_from_obj( await perform_test_from_obj(
test_case_obj, test_case_obj,

View File

@ -4,10 +4,11 @@ import multiaddr
import pytest import pytest
from libp2p import new_node 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.peer.peerinfo import info_from_p2p_addr
from libp2p.protocol_muxer.multiselect_client import MultiselectClientError from libp2p.protocol_muxer.multiselect_client import MultiselectClientError
from libp2p.security.insecure_security import InsecureTransport from libp2p.security.insecure.transport import InsecureSession, InsecureTransport
from libp2p.security.simple_security import SimpleSecurityTransport from libp2p.security.simple.transport import SimpleSecurityTransport
from tests.utils import cleanup, connect from tests.utils import cleanup, connect
# TODO: Add tests for multiple streams being opened on different # TODO: Add tests for multiple streams being opened on different
@ -20,6 +21,11 @@ def peer_id_for_node(node):
return info.peer_id return info.peer_id
initiator_key_pair = create_new_key_pair()
noninitiator_key_pair = create_new_key_pair()
async def perform_simple_test( async def perform_simple_test(
assertion_func, transports_for_initiator, transports_for_noninitiator 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)] node2_conn = node2.get_network().connections[peer_id_for_node(node1)]
# Perform assertion # Perform assertion
assertion_func(node1_conn.secured_conn.get_security_details()) assertion_func(node1_conn.conn)
assertion_func(node2_conn.secured_conn.get_security_details()) assertion_func(node2_conn.conn)
# Success, terminate pending tasks. # Success, terminate pending tasks.
await cleanup() await cleanup()
@ -59,11 +65,11 @@ async def perform_simple_test(
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_single_insecure_security_transport_succeeds(): async def test_single_insecure_security_transport_succeeds():
transports_for_initiator = {"foo": InsecureTransport("foo")} transports_for_initiator = {"foo": InsecureTransport(initiator_key_pair)}
transports_for_noninitiator = {"foo": InsecureTransport("foo")} transports_for_noninitiator = {"foo": InsecureTransport(noninitiator_key_pair)}
def assertion_func(details): def assertion_func(conn):
assert details["id"] == "foo" assert isinstance(conn, InsecureSession)
await perform_simple_test( await perform_simple_test(
assertion_func, transports_for_initiator, transports_for_noninitiator assertion_func, transports_for_initiator, transports_for_noninitiator
@ -72,11 +78,15 @@ async def test_single_insecure_security_transport_succeeds():
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_single_simple_test_security_transport_succeeds(): async def test_single_simple_test_security_transport_succeeds():
transports_for_initiator = {"tacos": SimpleSecurityTransport("tacos")} transports_for_initiator = {
transports_for_noninitiator = {"tacos": SimpleSecurityTransport("tacos")} "tacos": SimpleSecurityTransport(initiator_key_pair, "tacos")
}
transports_for_noninitiator = {
"tacos": SimpleSecurityTransport(noninitiator_key_pair, "tacos")
}
def assertion_func(details): def assertion_func(conn):
assert details["key_phrase"] == "tacos" assert conn.key_phrase == "tacos"
await perform_simple_test( await perform_simple_test(
assertion_func, transports_for_initiator, transports_for_noninitiator assertion_func, transports_for_initiator, transports_for_noninitiator
@ -86,13 +96,15 @@ async def test_single_simple_test_security_transport_succeeds():
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_two_simple_test_security_transport_for_initiator_succeeds(): async def test_two_simple_test_security_transport_for_initiator_succeeds():
transports_for_initiator = { transports_for_initiator = {
"tacos": SimpleSecurityTransport("tacos"), "tacos": SimpleSecurityTransport(initiator_key_pair, "tacos"),
"shleep": SimpleSecurityTransport("shleep"), "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): def assertion_func(conn):
assert details["key_phrase"] == "shleep" assert conn.key_phrase == "shleep"
await perform_simple_test( await perform_simple_test(
assertion_func, transports_for_initiator, transports_for_noninitiator 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 @pytest.mark.asyncio
async def test_two_simple_test_security_transport_for_noninitiator_succeeds(): 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 = { transports_for_noninitiator = {
"shleep": SimpleSecurityTransport("shleep"), "shleep": SimpleSecurityTransport(noninitiator_key_pair, "shleep"),
"tacos": SimpleSecurityTransport("tacos"), "tacos": SimpleSecurityTransport(noninitiator_key_pair, "tacos"),
} }
def assertion_func(details): def assertion_func(conn):
assert details["key_phrase"] == "tacos" assert conn.key_phrase == "tacos"
await perform_simple_test( await perform_simple_test(
assertion_func, transports_for_initiator, transports_for_noninitiator 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 @pytest.mark.asyncio
async def test_two_simple_test_security_transport_for_both_succeeds(): async def test_two_simple_test_security_transport_for_both_succeeds():
transports_for_initiator = { transports_for_initiator = {
"a": SimpleSecurityTransport("a"), "a": SimpleSecurityTransport(initiator_key_pair, "a"),
"b": SimpleSecurityTransport("b"), "b": SimpleSecurityTransport(initiator_key_pair, "b"),
} }
transports_for_noninitiator = { transports_for_noninitiator = {
"c": SimpleSecurityTransport("c"), "b": SimpleSecurityTransport(noninitiator_key_pair, "b"),
"b": SimpleSecurityTransport("b"), "c": SimpleSecurityTransport(noninitiator_key_pair, "c"),
} }
def assertion_func(details): def assertion_func(conn):
assert details["key_phrase"] == "b" assert conn.key_phrase == "b"
await perform_simple_test( await perform_simple_test(
assertion_func, transports_for_initiator, transports_for_noninitiator 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 @pytest.mark.asyncio
async def test_multiple_security_none_the_same_fails(): async def test_multiple_security_none_the_same_fails():
transports_for_initiator = { transports_for_initiator = {
"a": SimpleSecurityTransport("a"), "a": SimpleSecurityTransport(initiator_key_pair, "a"),
"b": SimpleSecurityTransport("b"), "b": SimpleSecurityTransport(initiator_key_pair, "b"),
} }
transports_for_noninitiator = { transports_for_noninitiator = {
"c": SimpleSecurityTransport("c"), "d": SimpleSecurityTransport(noninitiator_key_pair, "d"),
"d": SimpleSecurityTransport("d"), "c": SimpleSecurityTransport(noninitiator_key_pair, "c"),
} }
def assertion_func(_): def assertion_func(_):
@ -161,18 +175,18 @@ async def test_default_insecure_security():
transports_for_initiator = None transports_for_initiator = None
transports_for_noninitiator = None transports_for_noninitiator = None
details1 = None conn1 = None
details2 = None conn2 = None
def assertion_func(details): def assertion_func(conn):
nonlocal details1 nonlocal conn1
nonlocal details2 nonlocal conn2
if not details1: if not conn1:
details1 = details conn1 = conn
elif not details2: elif not conn2:
details2 = details conn2 = conn
else: else:
assert details1 == details2 assert conn1 == conn2
await perform_simple_test( await perform_simple_test(
assertion_func, transports_for_initiator, transports_for_noninitiator assertion_func, transports_for_initiator, transports_for_noninitiator