libp2prs_plaintext/
lib.rs

1// Copyright 2019 Parity Technologies (UK) Ltd.
2// Copyright 2020 Netwarps Ltd.
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20// DEALINGS IN THE SOFTWARE.
21
22mod error;
23mod handshake;
24// mod secure_stream;
25
26use crate::error::PlaintextError;
27use crate::handshake::handshake_plaintext::Remote;
28// use crate::secure_stream::{SecureStream, SecureStreamReader, SecureStreamWriter};
29use futures::{AsyncRead, AsyncWrite};
30use libp2prs_core::identity::Keypair;
31use libp2prs_core::secure_io::SecureInfo;
32use libp2prs_core::transport::{ConnectionInfo, TransportError};
33use libp2prs_core::upgrade::{UpgradeInfo, Upgrader};
34use libp2prs_core::{Multiaddr, PeerId, PublicKey};
35use std::{
36    io,
37    pin::Pin,
38    task::{Context, Poll},
39};
40
41use async_trait::async_trait;
42
43pub mod structs_proto {
44    include!(concat!(env!("OUT_DIR"), "/structs_proto.rs"));
45}
46
47const MAX_FRAME_SIZE: usize = 1024 * 1024 * 8;
48
49/// Config for PlainText
50#[derive(Clone)]
51pub struct PlainTextConfig {
52    pub(crate) key: Keypair,
53    pub(crate) max_frame_length: usize,
54}
55
56impl PlainTextConfig {
57    /// Create new config
58    pub fn new(key: Keypair) -> Self {
59        PlainTextConfig {
60            key,
61            max_frame_length: MAX_FRAME_SIZE,
62        }
63    }
64
65    /// Attempts to perform a handshake on the given socket.
66    ///
67    /// On success, produces a `SecureStream` that can then be used to encode/decode
68    /// communications, plus the remote info that contains public key and peer_id
69    pub async fn handshake<T>(self, socket: T) -> Result<(T, Remote), PlaintextError>
70    where
71        T: AsyncRead + AsyncWrite + Send + Unpin + 'static,
72    {
73        handshake::handshake_plaintext::handshake(socket, self).await
74    }
75}
76
77impl UpgradeInfo for PlainTextConfig {
78    type Info = &'static [u8];
79
80    fn protocol_info(&self) -> Vec<Self::Info> {
81        vec![b"/plaintext/1.0.0"]
82    }
83}
84
85#[async_trait]
86impl<T> Upgrader<T> for PlainTextConfig
87where
88    T: ConnectionInfo + AsyncRead + AsyncWrite + Send + Unpin + 'static,
89{
90    type Output = PlainTextOutput<T>;
91
92    async fn upgrade_inbound(self, socket: T, _info: <Self as UpgradeInfo>::Info) -> Result<Self::Output, TransportError> {
93        make_secure_output(self, socket).await
94    }
95
96    async fn upgrade_outbound(self, socket: T, _info: <Self as UpgradeInfo>::Info) -> Result<Self::Output, TransportError> {
97        make_secure_output(self, socket).await
98    }
99}
100
101async fn make_secure_output<T>(config: PlainTextConfig, socket: T) -> Result<PlainTextOutput<T>, TransportError>
102where
103    T: ConnectionInfo + AsyncRead + AsyncWrite + Send + Unpin + 'static,
104{
105    let pri_key = config.key.clone();
106    let la = socket.local_multiaddr();
107    let ra = socket.remote_multiaddr();
108    let (secure_stream, remote) = config.handshake(socket).await?;
109    let output = PlainTextOutput {
110        stream: secure_stream,
111        local_priv_key: pri_key.clone(),
112        local_peer_id: pri_key.public().into_peer_id(),
113        remote_pub_key: remote.public_key,
114        remote_peer_id: remote.peer_id,
115        la,
116        ra,
117    };
118    Ok(output)
119}
120
121/// Output of the plaintext protocol. It implements the SecureStream trait
122#[pin_project::pin_project]
123pub struct PlainTextOutput<T> {
124    /// The encrypted stream, actually not any encrypt action.
125    #[pin]
126    pub stream: T,
127    /// The private key of the local
128    pub local_priv_key: Keypair,
129    /// For convenience, the local peer ID, generated from local pub key
130    pub local_peer_id: PeerId,
131    /// The public key of the remote.
132    pub remote_pub_key: PublicKey,
133    /// For convenience, put a PeerId here, which is actually calculated from remote_key
134    pub remote_peer_id: PeerId,
135    /// The local multiaddr of this connection
136    la: Multiaddr,
137    /// The remote multiaddr of this connection
138    ra: Multiaddr,
139}
140
141impl<T> SecureInfo for PlainTextOutput<T> {
142    fn local_peer(&self) -> PeerId {
143        self.local_peer_id
144    }
145
146    fn remote_peer(&self) -> PeerId {
147        self.remote_peer_id
148    }
149
150    fn local_priv_key(&self) -> Keypair {
151        self.local_priv_key.clone()
152    }
153
154    fn remote_pub_key(&self) -> PublicKey {
155        self.remote_pub_key.clone()
156    }
157}
158
159impl<T: Send> ConnectionInfo for PlainTextOutput<T> {
160    fn local_multiaddr(&self) -> Multiaddr {
161        self.la.clone()
162    }
163    fn remote_multiaddr(&self) -> Multiaddr {
164        self.ra.clone()
165    }
166}
167
168impl<T: AsyncRead + AsyncWrite + Send + Unpin + 'static> AsyncRead for PlainTextOutput<T> {
169    fn poll_read(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
170        let this = self.project();
171        this.stream.poll_read(cx, buf)
172    }
173}
174
175impl<T: AsyncRead + AsyncWrite + Send + Unpin + 'static> AsyncWrite for PlainTextOutput<T> {
176    fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
177        let this = self.project();
178        this.stream.poll_write(cx, buf)
179    }
180
181    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
182        let this = self.project();
183        this.stream.poll_flush(cx)
184    }
185
186    fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
187        let this = self.project();
188        this.stream.poll_close(cx)
189    }
190}
191
192impl From<PlaintextError> for TransportError {
193    fn from(e: PlaintextError) -> Self {
194        TransportError::SecurityError(Box::new(e))
195    }
196}