feat: include crate version in peer_id
This commit is contained in:
parent
e83da0b194
commit
610140cff6
8 changed files with 164 additions and 18 deletions
|
|
@ -20,7 +20,7 @@ tokio = { version = "1", features = ["rt-multi-thread", "macros", "time"] }
|
|||
hex = "0.4"
|
||||
anyhow = "1"
|
||||
url = { version = "2", default-features = false }
|
||||
uuid = { version = "1", features = ["v4"] }
|
||||
rand = "0.8"
|
||||
parking_lot = "0.12"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
buffers = { path = "../buffers", package = "librqbit-buffers", version = "4.2" }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,18 @@
|
|||
use crate::hash_id::Id20;
|
||||
use rand::{self, RngCore};
|
||||
|
||||
/// Return the version of the invoking crate as a tuple
|
||||
#[macro_export]
|
||||
macro_rules! crate_version {
|
||||
() => {
|
||||
(
|
||||
env!("CARGO_PKG_VERSION_MAJOR").parse::<u8>().unwrap_or(0),
|
||||
env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap_or(0),
|
||||
env!("CARGO_PKG_VERSION_PATCH").parse::<u8>().unwrap_or(0),
|
||||
env!("CARGO_PKG_VERSION_PRE").parse::<u8>().unwrap_or(0),
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AzureusStyleKind {
|
||||
|
|
@ -8,13 +22,13 @@ pub enum AzureusStyleKind {
|
|||
QBittorrent,
|
||||
UTorrent,
|
||||
RQBit,
|
||||
Other([char; 2]),
|
||||
Other([u8; 2]),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AzureusStyle {
|
||||
pub kind: AzureusStyleKind,
|
||||
pub version: [char; 4],
|
||||
pub version: [u8; 4],
|
||||
}
|
||||
|
||||
impl AzureusStyleKind {
|
||||
|
|
@ -26,7 +40,7 @@ impl AzureusStyleKind {
|
|||
b"qB" => AzureusStyleKind::QBittorrent,
|
||||
b"UT" => AzureusStyleKind::UTorrent,
|
||||
b"rQ" => AzureusStyleKind::RQBit,
|
||||
_ => AzureusStyleKind::Other([b1 as char, b2 as char]),
|
||||
other => AzureusStyleKind::Other(*other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -36,9 +50,9 @@ fn try_decode_azureus_style(p: &Id20) -> Option<AzureusStyle> {
|
|||
if !(p[0] == b'-' && p[7] == b'-') {
|
||||
return None;
|
||||
}
|
||||
let mut version = ['0'; 4];
|
||||
let mut version = [b'0'; 4];
|
||||
for (i, c) in p[3..7].iter().copied().enumerate() {
|
||||
version[i] = c as char;
|
||||
version[i] = version_digit_from_id(c)?;
|
||||
}
|
||||
let kind = AzureusStyleKind::from_bytes(p[1], p[2]);
|
||||
Some(AzureusStyle { kind, version })
|
||||
|
|
@ -53,13 +67,62 @@ pub fn try_decode_peer_id(p: Id20) -> Option<PeerId> {
|
|||
Some(PeerId::AzureusStyle(try_decode_azureus_style(&p)?))
|
||||
}
|
||||
|
||||
pub fn generate_peer_id() -> Id20 {
|
||||
/// Returns `None` for bytes greater than 64
|
||||
fn version_digit_to_id(d: u8) -> Option<u8> {
|
||||
let version_map = b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-";
|
||||
version_map.get(d as usize).copied()
|
||||
}
|
||||
|
||||
/// Returns `None` for bytes that aren't alphanumeric, `.` or `-`.
|
||||
fn version_digit_from_id(d: u8) -> Option<u8> {
|
||||
match d {
|
||||
b'0'..=b'9' => Some(d - b'0'),
|
||||
b'A'..=b'Z' => Some(d - b'0' - 10),
|
||||
b'a'..=b'z' => Some(d - b'0' - 10 - 26),
|
||||
b'.' => Some(62),
|
||||
b'-' => Some(63),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a client fingerprint in the Azereus format, where `b"-xx1234-"` corresponds to version `1.2.3.4`` of the torrent client abbreviated by `xx`
|
||||
pub fn generate_azereus_style(client: [u8; 2], version: (u8, u8, u8, u8)) -> Id20 {
|
||||
let mut fingerprint = [b'-'; 8];
|
||||
|
||||
fingerprint[1..3].copy_from_slice(&client);
|
||||
fingerprint[3] = version_digit_to_id(version.0).unwrap();
|
||||
fingerprint[4] = version_digit_to_id(version.1).unwrap();
|
||||
fingerprint[5] = version_digit_to_id(version.2).unwrap();
|
||||
fingerprint[6] = version_digit_to_id(version.3).unwrap();
|
||||
generate_peer_id(&fingerprint)
|
||||
}
|
||||
|
||||
/// Panics if the `fingerprint` slice isn't eight bytes long
|
||||
pub fn generate_peer_id(fingerprint: &[u8]) -> Id20 {
|
||||
let mut peer_id = [0u8; 20];
|
||||
|
||||
let u = uuid::Uuid::new_v4();
|
||||
peer_id[4..20].copy_from_slice(&u.as_bytes()[..]);
|
||||
|
||||
peer_id[..8].copy_from_slice(b"-rQ7000-");
|
||||
peer_id[..8].copy_from_slice(fingerprint);
|
||||
rand::thread_rng().fill_bytes(&mut peer_id[8..]);
|
||||
|
||||
Id20::new(peer_id)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::peer_id::generate_azereus_style;
|
||||
|
||||
#[test]
|
||||
fn test_azereus_peer_id_generation() {
|
||||
for (client, version, correct_fingerprint) in [
|
||||
(*b"xx", (1, 2, 3, 4), *b"-xx1234-"),
|
||||
(*b"00", (10, 0, 0, 0), *b"-00A000-"),
|
||||
(*b"\xFF\xFF", (36, 37, 62, 63), *b"-\xFF\xFFab.--"),
|
||||
] {
|
||||
let id1 = generate_azereus_style(client, version);
|
||||
let id2 = generate_azereus_style(client, version);
|
||||
assert_ne!(id1, id2);
|
||||
assert_eq!(id1.0[..8], id2.0[..8]);
|
||||
assert_eq!(id1.0[..8], correct_fingerprint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue