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
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue