diff --git a/libp2p/security/__init__.py b/libp2p/security/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/libp2p/security/secure_conn_interface.py b/libp2p/security/secure_conn_interface.py new file mode 100644 index 0000000..946d4f5 --- /dev/null +++ b/libp2p/security/secure_conn_interface.py @@ -0,0 +1,21 @@ +from abc import ABC, abstractmethod + +""" +Represents a secured connection object, which includes a connection and details about the security +involved in the secured connection + +Relevant go repo: https://github.com/libp2p/go-conn-security/blob/master/interface.go +""" +class ISecureConn(ABC): + + @abstractmethod + def get_conn(self): + """ + :return: connection object that has been made secure + """ + + def get_security_details(self): + """ + :return: map containing details about the connections security + """ + diff --git a/libp2p/security/secure_transport_interface.py b/libp2p/security/secure_transport_interface.py new file mode 100644 index 0000000..3e49719 --- /dev/null +++ b/libp2p/security/secure_transport_interface.py @@ -0,0 +1,27 @@ +import asyncio + +from abc import ABC, abstractmethod + +""" +Transport that is used to secure a connection. This transport is +chosen by a security transport multistream module. + +Relevant go repo: https://github.com/libp2p/go-conn-security/blob/master/interface.go +""" +class ISecureTransport(ABC): + + @abstractmethod + async def secure_inbound(self, conn): + """ + 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) + """ + + @abstractmethod + async def secure_outbound(self, conn, peer_id): + """ + 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) + """ diff --git a/libp2p/security/security_multistream.py b/libp2p/security/security_multistream.py new file mode 100644 index 0000000..6fe4539 --- /dev/null +++ b/libp2p/security/security_multistream.py @@ -0,0 +1,87 @@ +import asyncio + +from abc import ABC, abstractmethod +from libp2p.protocol_muxer.multiselect_client import MultiselectClient +from libp2p.protocol_muxer.multiselect import Multiselect + +""" +Represents a secured connection object, which includes a connection and details about the security +involved in the secured connection + +Relevant go repo: https://github.com/libp2p/go-conn-security/blob/master/interface.go +""" +class SecurityMultistream(ABC): + + def __init__(): + # Map protocol to secure transport + self.transports = {} + + # Create multiselect + self.multiselect = Multiselect() + + # Create multiselect client + self.multiselect_client = MultiselectClient() + + def add_transport(self, protocol, transport): + # 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) + + + async def secure_inbound(self, conn): + """ + 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) + """ + + # Select a secure transport + transport = await self.select_transport(conn, True) + + # Create secured connection + secure_conn = await transport.secure_inbound(conn) + + return secure_conn + + + async def secure_outbound(self, conn, peer_id): + """ + 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) + """ + + # 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(self, conn, initiator): + """ + Select a transport that both us and the node on the + other end of conn support and agree on + :param conn: conn to choose a transport over + :param initiator: true if we are the initiator, false otherwise + :return: selected secure transport + """ + # TODO: Is conn acceptable to multiselect/multiselect_client instead of stream? In go repo, + # they pass in a raw conn (https://raw.githubusercontent.com/libp2p/go-conn-security-multistream/master/ssms.go) + + protocol = None + if initiator: + # Select protocol if initiator + protocol = await self.multiselect_client.select_one_of(list(self.transports.keys()), conn) + else: + # Select protocol if non-initiator + protocol = await self.multiselect.negotiate(conn) + + # Return transport from protocol + return self.transports[protocol]