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]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.10.2"
|
version = "1.10.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
|
checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
@ -3288,9 +3288,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-automata"
|
name = "regex-automata"
|
||||||
version = "0.4.3"
|
version = "0.4.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
|
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
@ -4357,6 +4357,7 @@ dependencies = [
|
||||||
"i2p",
|
"i2p",
|
||||||
"itertools 0.12.0",
|
"itertools 0.12.0",
|
||||||
"jsonwebtoken",
|
"jsonwebtoken",
|
||||||
|
"regex",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|
|
@ -10,6 +10,7 @@ axum = { version = "0.7.2", features = [ "macros" ] }
|
||||||
chrono = "0.4.31"
|
chrono = "0.4.31"
|
||||||
itertools = "0.12.0"
|
itertools = "0.12.0"
|
||||||
jsonwebtoken = "9.2.0"
|
jsonwebtoken = "9.2.0"
|
||||||
|
regex = "1.10.4"
|
||||||
reqwest = "0.11.23"
|
reqwest = "0.11.23"
|
||||||
serde = { version = "1.0.166", features = [ "derive" ] }
|
serde = { version = "1.0.166", features = [ "derive" ] }
|
||||||
serde_json = "1.0.99"
|
serde_json = "1.0.99"
|
||||||
|
|
|
@ -1,89 +1,78 @@
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
|
||||||
use anyhow::{anyhow, bail};
|
use anyhow::{anyhow, bail, Error};
|
||||||
use i2p::net::{I2pAddr, I2pSocketAddr, ToI2pSocketAddrs};
|
use i2p::net::{I2pAddr, I2pSocketAddr, ToI2pSocketAddrs};
|
||||||
|
use regex::Regex;
|
||||||
use serde::{Deserialize, Serialize};
|
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 {
|
pub struct PeerId {
|
||||||
i2p_dest: I2pSocketAddr,
|
addr: I2pSocketAddr,
|
||||||
i2p_b32: Option<I2pAddr>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PeerId {
|
impl PeerId {
|
||||||
pub fn addr(&self) -> I2pSocketAddr {
|
pub fn try_from_b32(addr: &str, port: Option<u16>) -> anyhow::Result<Self> {
|
||||||
self.i2p_dest.to_owned()
|
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."))
|
||||||
}
|
}
|
||||||
pub fn addr_ref(&self) -> &I2pSocketAddr {
|
|
||||||
&self.i2p_dest
|
|
||||||
}
|
}
|
||||||
pub fn b32_addr(&mut self) -> anyhow::Result<I2pAddr> {
|
pub fn try_from_dest(dest: &str, port: Option<u16>) -> anyhow::Result<Self> {
|
||||||
let result = I2pAddr::from_b64(&self.i2p_dest.dest().string());
|
let b32 = I2pAddr::from_b64(dest).map_err(|e| anyhow!(e))?;
|
||||||
if let Ok(addr) = &result {
|
Ok(PeerId {
|
||||||
self.i2p_b32 = Some(addr.to_owned());
|
addr: I2pSocketAddr::new(b32, port.unwrap_or(0)),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The identity of the PeerId only depends on the i2p_dest (which is unique),
|
pub fn addr(&self) -> I2pSocketAddr {
|
||||||
// and not on whether the b32 address has been computed before
|
self.addr.to_owned()
|
||||||
impl Hash for PeerId {
|
}
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
||||||
self.i2p_dest.hash(state);
|
pub fn addr_ref(&self) -> &I2pSocketAddr {
|
||||||
|
&self.addr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for PeerId {
|
impl ToString for PeerId {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
self.i2p_dest.to_string()
|
self.addr.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 }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<PeerId> for I2pSocketAddr {
|
impl From<PeerId> for I2pSocketAddr {
|
||||||
fn from(value: PeerId) -> Self {
|
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 {
|
impl Default for PeerId {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
PeerId {
|
PeerId {
|
||||||
i2p_dest: I2pSocketAddr::new(I2pAddr::new(""), 0),
|
addr: I2pSocketAddr::new(I2pAddr::new(""), 0),
|
||||||
i2p_b32: None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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) {
|
pub fn handle(state: &CommState, peer: &PeerId, message: Message) {
|
||||||
debug!(
|
debug!(
|
||||||
"Received message.\nFrom: {:?} (dest: {:?})\nTo: {:?} (dest: {:?})\nMessage: {message:?}",
|
"Received message.\nFrom: {:?} (dest: {:?})\nTo: {:?} (dest: {:?})\nMessage: {message:?}",
|
||||||
peer.b32_addr_nocache(),
|
peer.addr(),
|
||||||
peer,
|
peer,
|
||||||
state.own_peer_id().unwrap().b32_addr_nocache(),
|
state.own_peer_id().unwrap().addr(),
|
||||||
state.own_peer_id().unwrap()
|
state.own_peer_id().unwrap()
|
||||||
);
|
);
|
||||||
match message.content() {
|
match message.content() {
|
||||||
|
|
|
@ -40,7 +40,6 @@ impl CommHandle {
|
||||||
|
|
||||||
let listener = listener_builder.build().unwrap();
|
let listener = listener_builder.build().unwrap();
|
||||||
let mut own_peer_id: PeerId = (&listener).local_addr().map_err(|e| anyhow!(e))?.into();
|
let mut own_peer_id: PeerId = (&listener).local_addr().map_err(|e| anyhow!(e))?.into();
|
||||||
own_peer_id.b32_addr();
|
|
||||||
|
|
||||||
Ok(CommHandle {
|
Ok(CommHandle {
|
||||||
state: Arc::new(state),
|
state: Arc::new(state),
|
||||||
|
@ -96,7 +95,7 @@ impl CommHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send(&self, dest: &I2pSocketAddr, msg: Message) -> anyhow::Result<()> {
|
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) {
|
match serde_json::to_string(&msg) {
|
||||||
Ok(msg_string) => {
|
Ok(msg_string) => {
|
||||||
self.send_to_addr(dest, msg_string.as_bytes()).await?;
|
self.send_to_addr(dest, msg_string.as_bytes()).await?;
|
||||||
|
@ -150,8 +149,8 @@ impl CommHandle {
|
||||||
self.peer_id.addr()
|
self.peer_id.addr()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn i2p_b32_address(&self) -> anyhow::Result<I2pAddr> {
|
pub fn i2p_b32_address(&self) -> I2pAddr {
|
||||||
self.peer_id.b32_addr_nocache()
|
self.peer_id.addr().dest()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn own_peer_id(&self) -> anyhow::Result<PeerId> {
|
pub fn own_peer_id(&self) -> anyhow::Result<PeerId> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue