Skip to main content

openvpn_mgmt_codec/
client_event.rs

1use std::fmt;
2
3/// The sub-type of a `>CLIENT:` notification.
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub enum ClientEvent {
6    /// A new client is connecting (`>CLIENT:CONNECT`).
7    Connect,
8
9    /// An existing client is re-authenticating (`>CLIENT:REAUTH`).
10    Reauth,
11
12    /// A client connection has been fully established (`>CLIENT:ESTABLISHED`).
13    Established,
14
15    /// A client has disconnected (`>CLIENT:DISCONNECT`).
16    Disconnect,
17
18    /// A client challenge-response (`>CLIENT:CR_RESPONSE,{CID},{KID},{base64}`).
19    ///
20    /// The base64-encoded response is carried inline because it appears as
21    /// the third comma-separated field on the header line (after CID and KID),
22    /// not in the ENV block. Both cedws/openvpn-mgmt-go and
23    /// jkroepke/openvpn-auth-oauth2 handle this as a distinct event type.
24    CrResponse(String),
25
26    /// An unrecognized event type (forward compatibility).
27    Custom(String),
28}
29
30impl ClientEvent {
31    /// Parse a wire event string into a typed variant.
32    ///
33    /// Note: `CR_RESPONSE` is handled separately in the codec's CLIENT
34    /// parser because it carries an extra trailing field (the base64
35    /// response). This method maps it to [`Custom`](Self::Custom) as a
36    /// fallback; the codec never calls `parse("CR_RESPONSE")`.
37    pub(crate) fn parse(s: &str) -> Self {
38        match s {
39            "CONNECT" => Self::Connect,
40            "REAUTH" => Self::Reauth,
41            "ESTABLISHED" => Self::Established,
42            "DISCONNECT" => Self::Disconnect,
43            other => Self::Custom(other.to_string()),
44        }
45    }
46}
47
48impl fmt::Display for ClientEvent {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        match self {
51            Self::Connect => f.write_str("CONNECT"),
52            Self::Reauth => f.write_str("REAUTH"),
53            Self::Established => f.write_str("ESTABLISHED"),
54            Self::Disconnect => f.write_str("DISCONNECT"),
55            Self::CrResponse(_) => f.write_str("CR_RESPONSE"),
56            Self::Custom(s) => f.write_str(s),
57        }
58    }
59}