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
//! The core crate for shared code used in the sshx application.

#![forbid(unsafe_code)]
#![warn(missing_docs)]

use std::fmt::Display;
use std::sync::atomic::{AtomicU32, Ordering};

use serde::{Deserialize, Serialize};

/// Protocol buffer and gRPC definitions, automatically generated by Tonic.
#[allow(missing_docs, non_snake_case)]
#[allow(clippy::derive_partial_eq_without_eq)]
pub mod proto {
    tonic::include_proto!("sshx");

    /// File descriptor set used for gRPC reflection.
    pub const FILE_DESCRIPTOR_SET: &[u8] = tonic::include_file_descriptor_set!("sshx");
}

/// Generate a cryptographically-secure, random alphanumeric value.
pub fn rand_alphanumeric(len: usize) -> String {
    use rand::{distributions::Alphanumeric, thread_rng, Rng};
    thread_rng()
        .sample_iter(Alphanumeric)
        .take(len)
        .map(char::from)
        .collect()
}

/// Unique identifier for a shell within the session.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(transparent)]
pub struct Sid(pub u32);

impl Display for Sid {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.0)
    }
}

/// Unique identifier for a user within the session.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(transparent)]
pub struct Uid(pub u32);

impl Display for Uid {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.0)
    }
}

/// A counter for generating unique identifiers.
#[derive(Debug)]
pub struct IdCounter {
    next_sid: AtomicU32,
    next_uid: AtomicU32,
}

impl Default for IdCounter {
    fn default() -> Self {
        Self {
            next_sid: AtomicU32::new(1),
            next_uid: AtomicU32::new(1),
        }
    }
}

impl IdCounter {
    /// Returns the next unique shell ID.
    pub fn next_sid(&self) -> Sid {
        Sid(self.next_sid.fetch_add(1, Ordering::Relaxed))
    }

    /// Returns the next unique user ID.
    pub fn next_uid(&self) -> Uid {
        Uid(self.next_uid.fetch_add(1, Ordering::Relaxed))
    }

    /// Return the current internal values of the counter.
    pub fn get_current_values(&self) -> (Sid, Uid) {
        (
            Sid(self.next_sid.load(Ordering::Relaxed)),
            Uid(self.next_uid.load(Ordering::Relaxed)),
        )
    }

    /// Set the internal values of the counter.
    pub fn set_current_values(&self, sid: Sid, uid: Uid) {
        self.next_sid.store(sid.0, Ordering::Relaxed);
        self.next_uid.store(uid.0, Ordering::Relaxed);
    }
}