turn_rs/router/nonces.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
use super::ports::capacity;
use std::{
net::SocketAddr,
sync::{Arc, RwLock},
time::Instant,
};
use ahash::AHashMap;
use rand::{distributions::Alphanumeric, thread_rng, Rng};
/// Session nonce.
///
/// The NONCE attribute may be present in requests and responses. It
/// contains a sequence of qdtext or quoted-pair, which are defined in
/// [RFC3261](https://datatracker.ietf.org/doc/html/rfc3261).
/// Note that this means that the NONCE attribute will not
/// contain the actual surrounding quote characters. The NONCE attribute
/// MUST be fewer than 128 characters (which can be as long as 509 bytes
/// when encoding them and a long as 763 bytes when decoding them). See
/// Section 5.4 of [RFC7616](https://datatracker.ietf.org/doc/html/rfc7616#section-5.4)
/// for guidance on selection of nonce values in a server.
pub struct Nonce {
raw: Arc<String>,
timer: Instant,
}
impl Default for Nonce {
fn default() -> Self {
Self::new()
}
}
impl Nonce {
pub fn new() -> Self {
Self {
raw: Arc::new(Self::create_nonce()),
timer: Instant::now(),
}
}
/// whether the nonce is dead.
///
/// # Examples
///
/// ```
/// use turn_rs::router::nonces::*;
///
/// let nonce = Nonce::new();
/// assert!(!nonce.is_death());
/// ```
pub fn is_death(&self) -> bool {
self.timer.elapsed().as_secs() >= 3600
}
/// unwind nonce random string.
///
/// # Examples
///
/// ```
/// use turn_rs::router::nonces::*;
///
/// let nonce = Nonce::new();
/// assert_eq!(nonce.unwind().len(), 16);
/// ```
pub fn unwind(&self) -> Arc<String> {
self.raw.clone()
}
/// generate nonce string.
fn create_nonce() -> String {
let mut rng = thread_rng();
std::iter::repeat(())
.map(|_| rng.sample(Alphanumeric) as char)
.take(16)
.collect::<String>()
.to_lowercase()
}
}
/// nonce table.
pub struct Nonces {
map: RwLock<AHashMap<SocketAddr, Nonce>>,
}
impl Default for Nonces {
fn default() -> Self {
Self::new()
}
}
impl Nonces {
pub fn new() -> Self {
Self {
map: RwLock::new(AHashMap::with_capacity(capacity())),
}
}
/// get session nonce string.
///
/// each node is assigned a random string valid for 1 hour.
///
/// # Examples
///
/// ```
/// use std::net::SocketAddr;
/// use turn_rs::router::nonces::*;
///
/// let addr = "127.0.0.1:1080".parse::<SocketAddr>().unwrap();
/// let nonce_table = Nonces::new();
///
/// assert_eq!(nonce_table.get(&addr).len(), 16);
/// ```
pub fn get(&self, a: &SocketAddr) -> Arc<String> {
if let Some(n) = self.map.read().unwrap().get(a) {
if !n.is_death() {
return n.unwind();
}
}
self.map
.write()
.unwrap()
.entry(*a)
.or_insert_with(Nonce::new)
.unwind()
}
/// remove session nonce string.
///
/// # Examples
///
/// ```
/// use std::net::SocketAddr;
/// use turn_rs::router::nonces::*;
///
/// let addr = "127.0.0.1:1080".parse::<SocketAddr>().unwrap();
/// let nonce_table = Nonces::new();
///
/// let nonce = nonce_table.get(&addr);
/// nonce_table.remove(&addr);
///
/// let new_nonce = nonce_table.get(&addr);
/// assert!(nonce.as_str() != new_nonce.as_str());
/// ```
pub fn remove(&self, a: &SocketAddr) {
self.map.write().unwrap().remove(a);
}
}