PeerId rework: PeerId is now unique and enforces b32-encoded destination
This commit is contained in:
parent
636aff64b9
commit
a68c08292f
5 changed files with 57 additions and 67 deletions
9
Cargo.lock
generated
9
Cargo.lock
generated
|
@ -3276,9 +3276,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.2"
|
||||
version = "1.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
|
||||
checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
@ -3288,9 +3288,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.3"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
|
||||
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
@ -4357,6 +4357,7 @@ dependencies = [
|
|||
"i2p",
|
||||
"itertools 0.12.0",
|
||||
"jsonwebtoken",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
|
@ -10,6 +10,7 @@ axum = { version = "0.7.2", features = [ "macros" ] }
|
|||
chrono = "0.4.31"
|
||||
itertools = "0.12.0"
|
||||
jsonwebtoken = "9.2.0"
|
||||
regex = "1.10.4"
|
||||
reqwest = "0.11.23"
|
||||
serde = { version = "1.0.166", features = [ "derive" ] }
|
||||
serde_json = "1.0.99"
|
||||
|
|
|
@ -1,89 +1,78 @@
|
|||
use std::hash::Hash;
|
||||
|
||||
use anyhow::{anyhow, bail};
|
||||
use anyhow::{anyhow, bail, Error};
|
||||
use i2p::net::{I2pAddr, I2pSocketAddr, ToI2pSocketAddrs};
|
||||
use regex::Regex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
/// Uniquely identifies a peer. The I2pAddr inside `addr` MUST be the peer's b32 address.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct PeerId {
|
||||
i2p_dest: I2pSocketAddr,
|
||||
i2p_b32: Option<I2pAddr>,
|
||||
addr: I2pSocketAddr,
|
||||
}
|
||||
|
||||
impl PeerId {
|
||||
pub fn addr(&self) -> I2pSocketAddr {
|
||||
self.i2p_dest.to_owned()
|
||||
}
|
||||
pub fn addr_ref(&self) -> &I2pSocketAddr {
|
||||
&self.i2p_dest
|
||||
}
|
||||
pub fn b32_addr(&mut self) -> anyhow::Result<I2pAddr> {
|
||||
let result = I2pAddr::from_b64(&self.i2p_dest.dest().string());
|
||||
if let Ok(addr) = &result {
|
||||
self.i2p_b32 = Some(addr.to_owned());
|
||||
pub fn try_from_b32(addr: &str, port: Option<u16>) -> anyhow::Result<Self> {
|
||||
let b32_regex = Regex::new(r"[abcdefghijklmnopqrstuvwxyz234567]{52}.b32.i2p").unwrap();
|
||||
if b32_regex.is_match(addr) {
|
||||
Ok(PeerId {
|
||||
addr: I2pSocketAddr::new(I2pAddr::new(addr), port.unwrap_or(0)),
|
||||
})
|
||||
} else {
|
||||
Err(Error::msg("The supplied address was not b32-formatted."))
|
||||
}
|
||||
result.map_err(|e| anyhow!(e))
|
||||
}
|
||||
pub fn b32_addr_nocache(&self) -> anyhow::Result<I2pAddr> {
|
||||
I2pAddr::from_b64(&self.i2p_dest.dest().string()).map_err(|e| anyhow!(e))
|
||||
pub fn try_from_dest(dest: &str, port: Option<u16>) -> anyhow::Result<Self> {
|
||||
let b32 = I2pAddr::from_b64(dest).map_err(|e| anyhow!(e))?;
|
||||
Ok(PeerId {
|
||||
addr: I2pSocketAddr::new(b32, port.unwrap_or(0)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// The identity of the PeerId only depends on the i2p_dest (which is unique),
|
||||
// and not on whether the b32 address has been computed before
|
||||
impl Hash for PeerId {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.i2p_dest.hash(state);
|
||||
pub fn addr(&self) -> I2pSocketAddr {
|
||||
self.addr.to_owned()
|
||||
}
|
||||
|
||||
pub fn addr_ref(&self) -> &I2pSocketAddr {
|
||||
&self.addr
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for PeerId {
|
||||
fn to_string(&self) -> String {
|
||||
self.i2p_dest.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for PeerId {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self, anyhow::Error> {
|
||||
match ToI2pSocketAddrs::to_socket_addrs(&value) {
|
||||
Ok(addr_iter) => {
|
||||
for addr in addr_iter {
|
||||
return Ok(PeerId { i2p_dest: addr, i2p_b32: None });
|
||||
}
|
||||
return Err(anyhow::Error::msg("No valid I2P address found"));
|
||||
}
|
||||
Err(e) => bail!(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<String> for PeerId {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||
Self::try_from(value.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<I2pSocketAddr> for PeerId {
|
||||
fn from(value: I2pSocketAddr) -> Self {
|
||||
PeerId { i2p_dest: value, i2p_b32: None }
|
||||
self.addr.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PeerId> for I2pSocketAddr {
|
||||
fn from(value: PeerId) -> Self {
|
||||
value.i2p_dest
|
||||
value.addr
|
||||
}
|
||||
}
|
||||
|
||||
impl From<I2pSocketAddr> for PeerId {
|
||||
fn from(value: I2pSocketAddr) -> Self {
|
||||
PeerId { addr: value }
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for PeerId {
|
||||
fn default() -> Self {
|
||||
PeerId {
|
||||
i2p_dest: I2pSocketAddr::new(I2pAddr::new(""), 0),
|
||||
i2p_b32: None
|
||||
addr: I2pSocketAddr::new(I2pAddr::new(""), 0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::PeerId;
|
||||
|
||||
#[test]
|
||||
fn from_b32() {
|
||||
let addr = "abcdefghijklmnopqrstuvwxyz234567abcdefghijklmnopqrst.b32.i2p";
|
||||
let peer_id = PeerId::try_from_b32(addr, None);
|
||||
|
||||
assert!(peer_id.is_ok())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,9 @@ use crate::state::CommState;
|
|||
pub fn handle(state: &CommState, peer: &PeerId, message: Message) {
|
||||
debug!(
|
||||
"Received message.\nFrom: {:?} (dest: {:?})\nTo: {:?} (dest: {:?})\nMessage: {message:?}",
|
||||
peer.b32_addr_nocache(),
|
||||
peer.addr(),
|
||||
peer,
|
||||
state.own_peer_id().unwrap().b32_addr_nocache(),
|
||||
state.own_peer_id().unwrap().addr(),
|
||||
state.own_peer_id().unwrap()
|
||||
);
|
||||
match message.content() {
|
||||
|
|
|
@ -40,7 +40,6 @@ impl CommHandle {
|
|||
|
||||
let listener = listener_builder.build().unwrap();
|
||||
let mut own_peer_id: PeerId = (&listener).local_addr().map_err(|e| anyhow!(e))?.into();
|
||||
own_peer_id.b32_addr();
|
||||
|
||||
Ok(CommHandle {
|
||||
state: Arc::new(state),
|
||||
|
@ -96,7 +95,7 @@ impl CommHandle {
|
|||
}
|
||||
|
||||
pub async fn send(&self, dest: &I2pSocketAddr, msg: Message) -> anyhow::Result<()> {
|
||||
debug!("Sending message...\nFrom '{:?}' (dest: {:?})\nTo '{dest:?}'\n Message: '{msg:?}", self.own_peer_id().unwrap().b32_addr_nocache(), self.own_peer_id().unwrap());
|
||||
debug!("Sending message...\nFrom '{:?}' (dest: {:?})\nTo '{dest:?}'\n Message: '{msg:?}", self.own_peer_id().unwrap().addr(), self.own_peer_id().unwrap());
|
||||
match serde_json::to_string(&msg) {
|
||||
Ok(msg_string) => {
|
||||
self.send_to_addr(dest, msg_string.as_bytes()).await?;
|
||||
|
@ -150,8 +149,8 @@ impl CommHandle {
|
|||
self.peer_id.addr()
|
||||
}
|
||||
|
||||
pub fn i2p_b32_address(&self) -> anyhow::Result<I2pAddr> {
|
||||
self.peer_id.b32_addr_nocache()
|
||||
pub fn i2p_b32_address(&self) -> I2pAddr {
|
||||
self.peer_id.addr().dest()
|
||||
}
|
||||
|
||||
pub fn own_peer_id(&self) -> anyhow::Result<PeerId> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue