#[cfg(feature = "base64")]
mod handler;
pub mod sasl;
mod secret;
#[cfg(test)]
mod tests;
#[cfg(feature = "base64")]
pub use handler::*;
pub use secret::*;
use crate::{
ircmsg::ClientMsg,
string::{Arg, SecretBuf},
};
pub fn msg_abort() -> ClientMsg<'static> {
use crate::names::cmd::AUTHENTICATE;
let mut msg = ClientMsg::new(AUTHENTICATE);
msg.args.edit().add_word(crate::names::STAR);
msg
}
pub trait SaslLogic: Send + 'static {
fn name(&self) -> Arg<'static>;
fn reply(
&mut self,
input: &[u8],
output: &mut SecretBuf,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
fn size_hint(&self) -> usize {
0
}
}
pub trait Sasl {
fn logic(&self) -> Vec<Box<dyn SaslLogic>>;
}
#[derive(Default)]
pub struct SaslQueue {
queue: std::collections::VecDeque<Box<dyn SaslLogic>>,
}
impl SaslQueue {
pub const fn new() -> Self {
SaslQueue { queue: std::collections::VecDeque::new() }
}
pub fn is_empty(&self) -> bool {
self.queue.is_empty()
}
pub fn len(&self) -> usize {
self.queue.len()
}
pub fn push(&mut self, sasl: &(impl Sasl + ?Sized)) {
let mut vec_deque: std::collections::VecDeque<_> = sasl.logic().into();
self.queue.append(&mut vec_deque);
}
pub fn pop(&mut self) -> Option<Box<dyn SaslLogic>> {
self.queue.pop_front()
}
pub fn retain(&mut self, supported: &(impl Fn(&Arg<'_>) -> bool + ?Sized)) {
self.queue.retain(|l| supported(&l.name()));
}
pub fn clear(&mut self) {
self.queue.clear();
}
}
impl<'a, S: Sasl + ?Sized> std::iter::FromIterator<&'a S> for SaslQueue {
fn from_iter<T: IntoIterator<Item = &'a S>>(iter: T) -> Self {
let iter = iter.into_iter();
let mut retval = Self::new();
retval.queue.reserve(iter.size_hint().0);
for sasl in iter {
retval.push(sasl);
}
retval
}
}
impl From<Vec<Box<dyn SaslLogic>>> for SaslQueue {
fn from(value: Vec<Box<dyn SaslLogic>>) -> Self {
SaslQueue { queue: value.into() }
}
}
#[derive(Clone)]
#[cfg_attr(feature = "serde", derive(serde_derive::Deserialize))]
#[cfg_attr(
feature = "serde",
serde(bound(deserialize = "S: LoadSecret + serde::Deserialize<'de>"))
)]
#[allow(missing_docs)]
#[non_exhaustive]
pub enum AnySasl<S: LoadSecret> {
External(sasl::External),
Password(sasl::Password<S>),
}
impl<S: LoadSecret + std::fmt::Debug> std::fmt::Debug for AnySasl<S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AnySasl::External(s) => s.fmt(f),
AnySasl::Password(s) => s.fmt(f),
}
}
}
impl<S: LoadSecret + 'static> Sasl for AnySasl<S> {
fn logic(&self) -> Vec<Box<dyn SaslLogic>> {
match self {
AnySasl::External(s) => s.logic(),
AnySasl::Password(s) => s.logic(),
}
}
}
impl<S: LoadSecret> From<sasl::External> for AnySasl<S> {
fn from(value: sasl::External) -> Self {
AnySasl::External(value)
}
}
impl<S: LoadSecret> From<sasl::Password<S>> for AnySasl<S> {
fn from(value: sasl::Password<S>) -> Self {
AnySasl::Password(value)
}
}