1use crate::proto;
4use crate::tls::ServerCert;
5use crate::version::MumbleVersion;
6
7#[derive(Debug, thiserror::Error)]
9pub enum ProtocolError {
10 #[error("frame of {0} bytes exceeds the size limit")]
11 FrameTooLarge(usize),
12 #[error("cannot decode {kind} message: {source}")]
13 Decode {
14 kind: &'static str,
15 #[source]
16 source: prost::DecodeError,
17 },
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum RejectReason {
23 None,
24 WrongVersion,
25 InvalidUsername,
26 WrongUserPassword,
27 WrongServerPassword,
28 UsernameInUse,
29 ServerFull,
30 NoCertificate,
31 AuthenticatorFail,
32 Unknown(i32),
33}
34
35impl RejectReason {
36 pub(crate) fn from_wire(value: Option<i32>) -> Self {
37 use proto::reject::RejectType as T;
38 let Some(value) = value else {
39 return Self::None;
40 };
41 match T::try_from(value) {
42 Ok(T::None) => Self::None,
43 Ok(T::WrongVersion) => Self::WrongVersion,
44 Ok(T::InvalidUsername) => Self::InvalidUsername,
45 Ok(T::WrongUserPw) => Self::WrongUserPassword,
46 Ok(T::WrongServerPw) => Self::WrongServerPassword,
47 Ok(T::UsernameInUse) => Self::UsernameInUse,
48 Ok(T::ServerFull) => Self::ServerFull,
49 Ok(T::NoCertificate) => Self::NoCertificate,
50 Ok(T::AuthenticatorFail) => Self::AuthenticatorFail,
51 Err(_) => Self::Unknown(value),
52 }
53 }
54}
55
56#[derive(Debug, thiserror::Error)]
58pub enum ConnectError {
59 #[error("address lookup failed: {0}")]
61 Resolve(std::io::Error),
62 #[error("network error: {0}")]
63 Io(#[from] std::io::Error),
64 #[error("invalid server address: {0}")]
65 InvalidAddress(String),
66 #[error("server certificate not trusted (SHA-1 {})", .0.sha1_hex)]
69 CertificateRejected(Box<ServerCert>),
70 #[error("TLS error: {0}")]
71 Tls(#[from] rustls::Error),
72 #[error("server rejected the login ({reason:?}): {message}")]
73 Rejected {
74 reason: RejectReason,
75 message: String,
76 },
77 #[error(transparent)]
78 Protocol(#[from] ProtocolError),
79 #[error("server closed the connection during login")]
80 Closed,
81 #[error("login timed out")]
82 Timeout,
83}
84
85#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
87pub enum CommandError {
88 #[error("not connected")]
89 NotConnected,
90 #[error("{feature} needs server {required} or newer (server is {server})")]
91 Unsupported {
92 feature: &'static str,
93 required: MumbleVersion,
94 server: MumbleVersion,
95 },
96}
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq)]
100pub enum DenyKind {
101 Text,
103 Permission,
105 SuperUser,
106 ChannelName,
107 TextTooLong,
108 H9K,
109 TemporaryChannel,
110 MissingCertificate,
111 UserName,
112 ChannelFull,
113 NestingLimit,
114 ChannelCountLimit,
115 ChannelListenerLimit,
117 UserListenerLimit,
119 Unknown(i32),
120}
121
122impl DenyKind {
123 fn from_wire(value: Option<i32>) -> Self {
124 use proto::permission_denied::DenyType as T;
125 let Some(value) = value else {
127 return Self::Text;
128 };
129 match T::try_from(value) {
130 Ok(T::Text) => Self::Text,
131 Ok(T::Permission) => Self::Permission,
132 Ok(T::SuperUser) => Self::SuperUser,
133 Ok(T::ChannelName) => Self::ChannelName,
134 Ok(T::TextTooLong) => Self::TextTooLong,
135 Ok(T::H9k) => Self::H9K,
136 Ok(T::TemporaryChannel) => Self::TemporaryChannel,
137 Ok(T::MissingCertificate) => Self::MissingCertificate,
138 Ok(T::UserName) => Self::UserName,
139 Ok(T::ChannelFull) => Self::ChannelFull,
140 Ok(T::NestingLimit) => Self::NestingLimit,
141 Ok(T::ChannelCountLimit) => Self::ChannelCountLimit,
142 Ok(T::ChannelListenerLimit) => Self::ChannelListenerLimit,
143 Ok(T::UserListenerLimit) => Self::UserListenerLimit,
144 Err(_) => Self::Unknown(value),
145 }
146 }
147}
148
149#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
151#[error("denied by server: {kind:?}")]
152pub struct PermissionDenied {
153 pub kind: DenyKind,
154 pub permission: Option<u32>,
156 pub channel_id: Option<u32>,
157 pub session: Option<u32>,
158 pub reason: Option<String>,
160 pub name: Option<String>,
162}
163
164impl From<proto::PermissionDenied> for PermissionDenied {
165 fn from(m: proto::PermissionDenied) -> Self {
166 Self {
167 kind: DenyKind::from_wire(m.r#type),
168 permission: m.permission,
169 channel_id: m.channel_id,
170 session: m.session,
171 reason: m.reason,
172 name: m.name,
173 }
174 }
175}
176
177#[cfg(test)]
178mod tests {
179 use super::*;
180
181 #[test]
182 fn deny_mapping() {
183 let m = proto::PermissionDenied {
184 r#type: Some(12),
185 channel_id: Some(2),
186 ..Default::default()
187 };
188 let d = PermissionDenied::from(m);
189 assert_eq!(d.kind, DenyKind::ChannelListenerLimit);
190 assert_eq!(d.channel_id, Some(2));
191 assert_eq!(DenyKind::from_wire(None), DenyKind::Text);
192 assert_eq!(DenyKind::from_wire(Some(77)), DenyKind::Unknown(77));
193 }
194
195 #[test]
196 fn reject_mapping() {
197 assert_eq!(
198 RejectReason::from_wire(Some(4)),
199 RejectReason::WrongServerPassword
200 );
201 assert_eq!(
202 RejectReason::from_wire(Some(5)),
203 RejectReason::UsernameInUse
204 );
205 assert_eq!(RejectReason::from_wire(Some(99)), RejectReason::Unknown(99));
206 }
207}