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);
    }
}