1use std::collections::VecDeque;
45
46use async_trait::async_trait;
47
48use crate::{
49 command::Command,
50 error::{err, ErrorKind, Result},
51 request::Request,
52 response::{types::message::Text, Response},
53 runtime::io::{Read, Write},
54 stream::PopStream,
55};
56
57pub struct PlainAuthenticator {
59 username: String,
60 password: String,
61}
62
63impl Authenticator for PlainAuthenticator {
64 fn mechanism(&self) -> &str {
65 "PLAIN"
66 }
67
68 fn auth(&self) -> Option<String> {
69 Some(format!("\x00{}\x00{}", self.username, self.password))
70 }
71}
72
73impl PlainAuthenticator {
74 pub fn new<U: Into<String>, P: Into<String>>(username: U, password: P) -> Self {
75 Self {
76 username: username.into(),
77 password: password.into(),
78 }
79 }
80}
81
82pub struct OAuth2Authenticator {
84 user: String,
85 access_token: String,
86}
87
88impl OAuth2Authenticator {
89 pub fn new<U: Into<String>, A: Into<String>>(user: U, access_token: A) -> Self {
90 Self {
91 user: user.into(),
92 access_token: access_token.into(),
93 }
94 }
95}
96
97#[async_trait]
98impl Authenticator for OAuth2Authenticator {
99 fn mechanism(&self) -> &str {
100 "XOAUTH2"
101 }
102
103 fn auth(&self) -> Option<String> {
104 let secret = format!(
105 "user={}\x01auth=Bearer {}\x01\x01",
106 self.user, self.access_token
107 );
108
109 Some(secret)
110 }
111}
112
113#[async_trait]
114pub trait Authenticator {
115 fn mechanism(&self) -> &str;
117
118 fn auth(&self) -> Option<String> {
122 None
123 }
124
125 async fn handle<'a, S: Read + Write + Unpin + Send>(
129 &self,
130 _communicator: Communicator<'a, S>,
131 ) -> Result<()> {
132 Ok(())
133 }
134}
135
136pub struct Communicator<'a, S: Read + Write + Unpin + Send> {
137 stream: &'a mut PopStream<S>,
138 requests: VecDeque<Request>,
139}
140
141impl<'a, S: Read + Write + Unpin + Send> Communicator<'a, S> {
142 pub fn new(stream: &'a mut PopStream<S>) -> Self {
143 Self {
144 stream,
145 requests: VecDeque::new(),
146 }
147 }
148
149 pub async fn send<A: Into<String>>(&mut self, secret: A) -> Result<()> {
150 let request: Request = Command::Base64(secret.into()).into();
151
152 self.stream.encode(&request).await?;
153
154 self.requests.push_back(request);
155
156 Ok(())
157 }
158
159 pub async fn next_challenge(&mut self) -> Result<Text> {
160 let command: Command = match self.requests.pop_front() {
161 Some(request) => request.into(),
162 None => Command::Base64(String::new()),
163 };
164
165 let response = self.stream.read_response(command).await?;
166
167 match response {
168 Response::Challenge(challenge) => Ok(challenge),
169 _ => err!(
170 ErrorKind::UnexpectedResponse,
171 "Did not get a challenge as a response"
172 ),
173 }
174 }
175
176 pub async fn stop(&mut self) -> Result<()> {
177 self.stream.send_bytes("*").await
178 }
179}