Added Connection and connection::Builder; Fixed a lot of Clippy lints;
This commit is contained in:
parent
c9eb30f4e7
commit
477de69ca3
13 changed files with 89 additions and 41 deletions
35
src/connection/builder.rs
Normal file
35
src/connection/builder.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
use super::verifier::Verifier;
|
||||
use crate::prelude::CertificateStore;
|
||||
use std::net::TcpStream;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Builder<S: CertificateStore> {
|
||||
pub stream: Option<TcpStream>,
|
||||
pub verifier: Option<Verifier<S>>,
|
||||
}
|
||||
|
||||
impl<S: CertificateStore> Default for Builder<S> {
|
||||
fn default() -> Self {
|
||||
Self { stream: None, verifier: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: CertificateStore> Builder<S> {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn stream(mut self, stream: TcpStream) -> Self {
|
||||
self.stream = Some(stream);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn verifier(mut self, verifier: Verifier<S>) -> Self {
|
||||
self.verifier = Some(verifier);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> super::Connection {
|
||||
todo!()
|
||||
}
|
||||
}
|
1
src/connection/error.rs
Normal file
1
src/connection/error.rs
Normal file
|
@ -0,0 +1 @@
|
|||
|
8
src/connection/mod.rs
Normal file
8
src/connection/mod.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
pub mod builder;
|
||||
pub mod error;
|
||||
pub mod verifier;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Connection {
|
||||
pub inner: rustls::ServerConnection,
|
||||
}
|
7
src/connection/verifier.rs
Normal file
7
src/connection/verifier.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
use crate::prelude::CertificateStore;
|
||||
use std::sync::Mutex;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Verifier<S: CertificateStore> {
|
||||
pub store: Mutex<S>,
|
||||
}
|
|
@ -31,7 +31,7 @@ impl GetFingerprint for Certificate {
|
|||
subject.iter_common_name().for_each(|n| {
|
||||
let mut val = n.attr_value().data;
|
||||
let mut name = String::new();
|
||||
if let Ok(_) = val.read_to_string(&mut name) {
|
||||
if val.read_to_string(&mut name).is_ok() {
|
||||
names.push(name);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -80,7 +80,7 @@ impl ToSocketAddrs for Host {
|
|||
type Iter = std::vec::IntoIter<SocketAddr>;
|
||||
|
||||
fn to_socket_addrs(&self) -> std::io::Result<Self::Iter> {
|
||||
format!("{}:1958", self).to_socket_addrs()
|
||||
format!("{self}:1958").to_socket_addrs()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#![warn(clippy::all, clippy::pedantic)]
|
||||
pub mod certificate;
|
||||
pub mod connection;
|
||||
pub mod fingerprint;
|
||||
pub mod host;
|
||||
pub mod mailbox;
|
||||
|
|
|
@ -33,25 +33,24 @@ impl FromStr for Mailbox {
|
|||
if let Some((username, mut host)) = s.split_once('@') {
|
||||
if username.is_empty() {
|
||||
Err(Error::EmptyUser)
|
||||
} else if username.contains(|c: char| c.is_whitespace()) {
|
||||
} else if username.contains(char::is_whitespace) {
|
||||
Err(Error::IllegalWhitespace)
|
||||
} else {
|
||||
let username = username.to_string();
|
||||
if let Some((h, b)) = host.split_once(|c: char| c.is_whitespace()) {
|
||||
if let Some((h, b)) = host.split_once(char::is_whitespace) {
|
||||
if h.is_empty() {
|
||||
return Err(Error::EmptyHost);
|
||||
} else if h.contains(|c: char| c.is_whitespace()) {
|
||||
} else if h.contains(char::is_whitespace) {
|
||||
return Err(Error::IllegalWhitespace);
|
||||
} else {
|
||||
}
|
||||
host = h;
|
||||
if !b.is_empty() {
|
||||
if b.contains("\n") {
|
||||
if b.contains('\n') {
|
||||
return Err(Error::IllegalWhitespace);
|
||||
}
|
||||
blurb = Some(b.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
let host = host.parse()?;
|
||||
Ok(Self {
|
||||
username,
|
||||
|
|
|
@ -4,7 +4,6 @@ use std::{
|
|||
io::{self, Write},
|
||||
os::unix::fs::DirBuilderExt,
|
||||
path::PathBuf,
|
||||
process::id,
|
||||
};
|
||||
|
||||
pub trait MultiDomain: MailStore {
|
||||
|
@ -39,7 +38,7 @@ impl MailStore for Filesystem {
|
|||
fn has_mailuser(&self, mailuser: &str) -> bool {
|
||||
if let Some((user, host)) = mailuser.rsplit_once('@') {
|
||||
let mut path = self.path.clone();
|
||||
if host.contains('.') && !host.contains(|c: char| c.is_whitespace()) {
|
||||
if host.contains('.') && !host.contains(char::is_whitespace) {
|
||||
path.push(host);
|
||||
path.push(user);
|
||||
return path.exists();
|
||||
|
@ -63,7 +62,7 @@ impl MailStore for Filesystem {
|
|||
name: folder.to_string(),
|
||||
messages: HashMap::new(),
|
||||
};
|
||||
dir.filter(|x| x.is_ok()).map(|x| x.unwrap()).for_each(|e| {
|
||||
dir.filter_map(Result::ok).for_each(|e| {
|
||||
if let Ok(contents) = fs::read_to_string(e.path()) {
|
||||
if let Ok(message) = contents.parse::<Message>() {
|
||||
folder.messages.insert(message.id.clone(), message);
|
||||
|
@ -77,7 +76,7 @@ impl MailStore for Filesystem {
|
|||
self.get_folder(user, folder).and_then(|f| {
|
||||
f.messages
|
||||
.values()
|
||||
.find(|m| m.title.as_ref().map(|x| x.as_str()) == Some(title))
|
||||
.find(|m| m.title.as_ref().map(String::as_str) == Some(title))
|
||||
.cloned()
|
||||
})
|
||||
}
|
||||
|
@ -172,7 +171,7 @@ impl MultiDomain for Filesystem {
|
|||
if !path.exists() {
|
||||
fs::DirBuilder::new()
|
||||
.recursive(true)
|
||||
.mode(700)
|
||||
.mode(0o700)
|
||||
.create(path)?;
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#![allow(unused_variables)]
|
||||
use crate::prelude::{Host, Mailbox, Mailuser, Message, ParseMailboxError};
|
||||
use std::{collections::HashMap, convert::Infallible, io, str::FromStr};
|
||||
use crate::prelude::{Host, Mailbox, Mailuser, Message};
|
||||
use std::{collections::HashMap, io, str::FromStr};
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -88,8 +88,7 @@ impl MailStore for Domain {
|
|||
fn has_mailuser(&self, mailuser: &str) -> bool {
|
||||
self.users()
|
||||
.iter()
|
||||
.find(|x| x.username == mailuser)
|
||||
.is_some()
|
||||
.any(|x| x.username == mailuser)
|
||||
}
|
||||
|
||||
fn get_folder(&self, user: &str, folder: &str) -> Option<Folder> {
|
||||
|
@ -106,7 +105,7 @@ impl MailStore for Domain {
|
|||
u.folders.get(folder).and_then(|f| {
|
||||
f.messages
|
||||
.values()
|
||||
.find(|m| m.title.as_ref().map(|x| x.as_str()) == Some(title))
|
||||
.find(|m| m.title.as_ref().map(String::as_str) == Some(title))
|
||||
})
|
||||
})
|
||||
.cloned()
|
||||
|
@ -126,7 +125,7 @@ impl MailStore for Domain {
|
|||
if self.users.contains_key(user) {
|
||||
return Ok(());
|
||||
}
|
||||
let mbox = Mailbox::from_str(&format!("{user}@{}", self.host.to_string()))
|
||||
let mbox = Mailbox::from_str(&format!("{user}@{}", self.host))
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{e}")))?;
|
||||
let folders = HashMap::new();
|
||||
let acct = Account {
|
||||
|
|
|
@ -68,12 +68,12 @@ impl fmt::Display for Message {
|
|||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if !self.senders.is_empty() {
|
||||
write!(f, "< ")?;
|
||||
self.senders.iter().try_for_each(|s| write!(f, "{s}\n"))?;
|
||||
self.senders.iter().try_for_each(|s| writeln!(f, "{s}"))?;
|
||||
}
|
||||
if !self.recipients.is_empty() {
|
||||
write!(f, ": ")?;
|
||||
self.recipients.iter().try_for_each(|r| write!(f, " {r}"))?;
|
||||
write!(f, "\n")?;
|
||||
writeln!(f)?;
|
||||
}
|
||||
write!(f, "{}\r\n", self.body)
|
||||
}
|
||||
|
|
|
@ -49,8 +49,8 @@ impl Request {
|
|||
pub fn recipients(&self) -> Vec<Mailuser> {
|
||||
let mut recipients = vec![];
|
||||
self.message.lines().for_each(|l| {
|
||||
if l.starts_with(':') {
|
||||
l[1..].trim().split_whitespace().for_each(|u| {
|
||||
if let Some(s) = l.strip_prefix(':') {
|
||||
s.split_whitespace().for_each(|u| {
|
||||
if let Ok(user) = u.parse() {
|
||||
recipients.push(user);
|
||||
}
|
||||
|
@ -63,8 +63,8 @@ impl Request {
|
|||
pub fn senders(&self) -> Vec<Mailbox> {
|
||||
let mut senders = vec![];
|
||||
self.message.lines().for_each(|l| {
|
||||
if l.starts_with('<') {
|
||||
if let Ok(mbox) = l[1..].trim().parse() {
|
||||
if let Some(s) = l.strip_prefix('<') {
|
||||
if let Ok(mbox) = s.trim().parse() {
|
||||
senders.push(mbox);
|
||||
}
|
||||
}
|
||||
|
@ -73,13 +73,12 @@ impl Request {
|
|||
}
|
||||
|
||||
pub fn timestamp(&self) -> Option<String> {
|
||||
let mut ts = None;
|
||||
self.message.lines().for_each(|l| {
|
||||
if l.starts_with('@') {
|
||||
ts = Some(l[1..].trim().to_string());
|
||||
for l in self.message.lines() {
|
||||
if let Some(s) = l.strip_prefix('@') {
|
||||
return Some(s.trim().to_string());
|
||||
}
|
||||
});
|
||||
ts
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,15 +9,15 @@ use {
|
|||
|
||||
#[derive(Debug)]
|
||||
/// A verifier is used to verify certificates sent by the receiving server
|
||||
/// during the tls handshake. For convenience the [CertificateStore] trait
|
||||
/// is implemented for [std::collections::HashMap<String, String>] and
|
||||
/// [std::collections::BTreeMap<String, String>], so a Verifier can easily
|
||||
/// during the tls handshake. For convenience the [`CertificateStore`] trait
|
||||
/// is implemented for [`std::collections::HashMap<String, String>`] and
|
||||
/// [`std::collections::BTreeMap<String, String>`], so a Verifier can easily
|
||||
/// be constructed from those types.
|
||||
///
|
||||
/// This type is passed to [rustls::client::DangerousClientConfig::set_certificate_verifier]
|
||||
/// This type is passed to [`rustls::client::DangerousClientConfig::set_certificate_verifier`]
|
||||
/// in order to allow Tofu certificate validation.
|
||||
/// # Examples
|
||||
/// Create a Verifier from a HashMap
|
||||
/// Create a Verifier from a `HashMap`
|
||||
/// ```
|
||||
/// use std::collections::HashMap;
|
||||
/// use dory::prelude::{CertificateStore, Verifier};
|
||||
|
@ -70,7 +70,7 @@ impl<S: CertificateStore> ServerCertVerifier for Verifier<S> {
|
|||
.borrow_mut()
|
||||
.insert_certificate(&name, &fp.fingerprint);
|
||||
}
|
||||
return Ok(ServerCertVerified::assertion());
|
||||
Ok(ServerCertVerified::assertion())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue