ultrafast_mcp_core/utils/
identifiers.rs

1//! Identifier generation utilities
2//!
3//! This module consolidates all identifier generation functions that were
4//! previously scattered across different crates.
5
6use uuid::Uuid;
7
8/// Generate a new session ID for MCP connections
9///
10/// Consolidates implementations from:
11/// - ultrafast-mcp-auth/src/pkce.rs
12/// - ultrafast-mcp-transport/src/streamable_http/server.rs
13pub fn generate_session_id() -> String {
14    Uuid::new_v4().to_string()
15}
16
17/// Generate a new state parameter for OAuth flows
18///
19/// Consolidates implementation from ultrafast-mcp-auth/src/pkce.rs
20pub fn generate_state() -> String {
21    use rand::Rng;
22    let mut rng = rand::rng();
23    (0..32)
24        .map(|_| {
25            let idx = rng.random_range(0..62);
26            match idx {
27                0..=25 => (b'A' + idx) as char,
28                26..=51 => (b'a' + (idx - 26)) as char,
29                _ => (b'0' + (idx - 52)) as char,
30            }
31        })
32        .collect()
33}
34
35/// Generate a new event ID for Server-Sent Events
36///
37/// Consolidates implementation from ultrafast-mcp-transport/src/streamable_http/server.rs
38pub fn generate_event_id() -> String {
39    Uuid::new_v4().to_string()
40}
41
42/// Generate a new request ID for JSON-RPC requests
43pub fn generate_request_id() -> u64 {
44    use std::sync::atomic::{AtomicU64, Ordering};
45    static COUNTER: AtomicU64 = AtomicU64::new(1);
46    COUNTER.fetch_add(1, Ordering::SeqCst)
47}
48
49/// Generate a cryptographically secure random string of specified length
50pub fn generate_secure_random(length: usize) -> String {
51    use rand::Rng;
52    let charset = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
53    let mut rng = rand::rng();
54    (0..length)
55        .map(|_| {
56            let idx = rng.random_range(0..charset.len());
57            charset[idx] as char
58        })
59        .collect()
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn test_generate_session_id() {
68        let id1 = generate_session_id();
69        let id2 = generate_session_id();
70
71        assert_ne!(id1, id2);
72        assert_eq!(id1.len(), 36); // UUID format
73        assert!(id1.contains('-'));
74    }
75
76    #[test]
77    fn test_generate_state() {
78        let state1 = generate_state();
79        let state2 = generate_state();
80
81        assert_ne!(state1, state2);
82        assert_eq!(state1.len(), 32);
83        assert!(state1.chars().all(|c| c.is_ascii_alphanumeric()));
84    }
85
86    #[test]
87    fn test_generate_event_id() {
88        let id1 = generate_event_id();
89        let id2 = generate_event_id();
90
91        assert_ne!(id1, id2);
92        assert_eq!(id1.len(), 36); // UUID format
93    }
94
95    #[test]
96    fn test_generate_request_id() {
97        let id1 = generate_request_id();
98        let id2 = generate_request_id();
99
100        assert_ne!(id1, id2);
101        assert!(id2 > id1);
102    }
103
104    #[test]
105    fn test_generate_secure_random() {
106        let random1 = generate_secure_random(16);
107        let random2 = generate_secure_random(16);
108
109        assert_ne!(random1, random2);
110        assert_eq!(random1.len(), 16);
111        assert_eq!(random2.len(), 16);
112        assert!(random1.chars().all(|c| c.is_ascii_alphanumeric()));
113    }
114}