p2p/webrtc/
signal.rs

1use binprot_derive::{BinProtRead, BinProtWrite};
2use derive_more::From;
3use malloc_size_of_derive::MallocSizeOf;
4use openmina_core::ChainId;
5use serde::{Deserialize, Serialize};
6
7use crate::identity::{EncryptableType, PeerId, PublicKey};
8
9use super::{ConnectionAuth, Host};
10
11#[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone, MallocSizeOf)]
12pub struct Offer {
13    pub sdp: String,
14    #[ignore_malloc_size_of = "doesn't allocate"]
15    pub chain_id: ChainId,
16    /// Offerer's identity public key.
17    #[ignore_malloc_size_of = "doesn't allocate"]
18    pub identity_pub_key: PublicKey,
19    /// Peer id that the offerer wants to connect to.
20    pub target_peer_id: PeerId,
21    // TODO(binier): remove host and get ip from ice candidates instead
22    /// Host name or IP of the signaling server of the offerer.
23    #[ignore_malloc_size_of = "neglectible"]
24    pub host: Host,
25    /// Port of the signaling server of the offerer.
26    pub listen_port: Option<u16>,
27}
28
29#[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone, MallocSizeOf)]
30pub struct Answer {
31    pub sdp: String,
32    /// Offerer's identity public key.
33    #[ignore_malloc_size_of = "doesn't allocate"]
34    pub identity_pub_key: PublicKey,
35    /// Peer id that the offerer wants to connect to.
36    pub target_peer_id: PeerId,
37}
38
39#[derive(Serialize, Deserialize, From, Eq, PartialEq, Debug, Clone)]
40pub enum Signal {
41    Offer(Offer),
42    Answer(Answer),
43}
44
45#[derive(
46    Serialize, Deserialize, Eq, PartialEq, Debug, Clone, Copy, thiserror::Error, MallocSizeOf,
47)]
48pub enum RejectionReason {
49    #[error("peer is on a different chain")]
50    ChainIdMismatch,
51    #[error("peer_id does not match peer's public key")]
52    PeerIdAndPublicKeyMismatch,
53    #[error("target peer_id is not local node's peer_id")]
54    TargetPeerIdNotMe,
55    #[error("too many peers")]
56    PeerCapacityFull,
57    #[error("peer already connected")]
58    AlreadyConnected,
59    #[error("self connection detected")]
60    ConnectingToSelf,
61}
62
63#[derive(Serialize, Deserialize, Debug, Clone)]
64pub enum P2pConnectionResponse {
65    Accepted(Box<Answer>),
66    Rejected(RejectionReason),
67    SignalDecryptionFailed,
68    InternalError,
69}
70
71fn sdp_hash(sdp: &str) -> [u8; 32] {
72    use sha2::{Digest, Sha256};
73    let mut hasher = Sha256::new();
74    hasher.update(sdp);
75    hasher.finalize().into()
76}
77
78impl Offer {
79    pub fn sdp_hash(&self) -> [u8; 32] {
80        sdp_hash(&self.sdp)
81    }
82
83    pub fn conn_auth(&self, answer: &Answer) -> ConnectionAuth {
84        ConnectionAuth::new(self, answer)
85    }
86}
87
88impl Answer {
89    pub fn sdp_hash(&self) -> [u8; 32] {
90        sdp_hash(&self.sdp)
91    }
92}
93
94impl RejectionReason {
95    pub fn is_bad(&self) -> bool {
96        match self {
97            Self::ChainIdMismatch => false,
98            Self::PeerIdAndPublicKeyMismatch => true,
99            Self::TargetPeerIdNotMe => true,
100            Self::PeerCapacityFull => false,
101            Self::AlreadyConnected => true,
102            Self::ConnectingToSelf => false,
103        }
104    }
105}
106
107impl P2pConnectionResponse {
108    pub fn internal_error_str() -> &'static str {
109        "InternalError"
110    }
111
112    pub fn internal_error_json_str() -> &'static str {
113        "\"InternalError\""
114    }
115}
116
117/// Encrypted `webrtc::Offer`.
118#[derive(BinProtWrite, BinProtRead, Serialize, Deserialize, From, Debug, Clone)]
119pub struct EncryptedOffer(Vec<u8>);
120
121/// Encrypted `P2pConnectionResponse`.
122#[derive(BinProtWrite, BinProtRead, Serialize, Deserialize, From, Debug, Clone)]
123pub struct EncryptedAnswer(Vec<u8>);
124
125impl AsRef<[u8]> for EncryptedOffer {
126    fn as_ref(&self) -> &[u8] {
127        self.0.as_ref()
128    }
129}
130
131impl AsRef<[u8]> for EncryptedAnswer {
132    fn as_ref(&self) -> &[u8] {
133        self.0.as_ref()
134    }
135}
136
137impl EncryptableType for Offer {
138    type Encrypted = EncryptedOffer;
139}
140
141impl EncryptableType for P2pConnectionResponse {
142    type Encrypted = EncryptedAnswer;
143}