feat: support port config and cert file

Summary:

This will now support a port config in the IMAPStore of the config. This is
still optional and will fall back to 993 if you don't have it.

It will also ignore tls verification if we have a CertificateFile config
option. This will take a bit of refactoring to implement our own tls context
so, for now we will disable it. As we have put in the comment, if the user
really wants this then they can configure this in there root store.


Test Plan:

N / A this tool is not tested yet
This commit is contained in:
Ade Attwood 2024-06-21 18:56:09 +01:00
parent 5126594966
commit 7549d36192
2 changed files with 47 additions and 18 deletions

View file

@ -5,12 +5,21 @@ use std::process::Command;
pub struct ImapStoreConfig {
pub name: String,
pub host: String,
pub port: Option<u16>,
pub user: String,
pub pass: Option<String>,
pub pass_command: Option<String>,
pub cert_file: Option<String>,
}
impl ImapStoreConfig {
pub fn port(&self) -> u16 {
if let Some(port) = self.port {
return port;
}
993
}
pub fn password(&self) -> String {
if let Some(pass) = &self.pass {
return pass.to_string();
@ -56,9 +65,11 @@ impl Config {
enum ConfigLine {
ImapStore(String),
Host(String),
Port(u16),
User(String),
Pass(String),
PassCommand(String),
CertFile(String),
Channel(String),
Near(String),
@ -76,9 +87,11 @@ impl TryFrom<&str> for ConfigLine {
match key {
"IMAPStore" => Ok(ConfigLine::ImapStore(value)),
"Host" => Ok(ConfigLine::Host(value)),
"Port" => Ok(ConfigLine::Port(value.parse().unwrap())),
"User" => Ok(ConfigLine::User(value)),
"Pass" => Ok(ConfigLine::Pass(remove_quotes(value))),
"PassCmd" => Ok(ConfigLine::PassCommand(remove_quotes(value))),
"CertificateFile" => Ok(ConfigLine::CertFile(value)),
"Channel" => Ok(ConfigLine::Channel(value)),
"Near" => Ok(ConfigLine::Near(value)),
@ -136,6 +149,10 @@ pub fn from_file(config_path: &str) -> Config {
let store = config.imap_stores.last_mut().unwrap();
store.host = host;
}
ConfigLine::Port(port) => {
let store = config.imap_stores.last_mut().unwrap();
store.port = Some(port);
}
ConfigLine::User(user) => {
let store = config.imap_stores.last_mut().unwrap();
store.user = user;
@ -148,6 +165,10 @@ pub fn from_file(config_path: &str) -> Config {
let store = config.imap_stores.last_mut().unwrap();
store.pass_command = Some(command);
}
ConfigLine::CertFile(cert_file) => {
let store = config.imap_stores.last_mut().unwrap();
store.cert_file = Some(cert_file);
}
ConfigLine::Channel(name) => {
let mut channel_config = ChannelConfig::default();

View file

@ -3,24 +3,36 @@ mod config;
use std::process::Command;
use std::thread;
use config::ImapStoreConfig;
use imap::{ImapConnection, Session};
fn connect(host: String, user: String, pass: String) -> Option<Session<Box<dyn ImapConnection>>> {
let client = imap::ClientBuilder::new(host.clone(), 993)
fn connect(config: &ImapStoreConfig) -> Option<Session<Box<dyn ImapConnection>>> {
let mut client_builder = imap::ClientBuilder::new(config.host.clone(), config.port())
.mode(imap::ConnectionMode::AutoTls)
.tls_kind(imap::TlsKind::Rust)
.tls_kind(imap::TlsKind::Rust);
// For now disable skipping tls verification if we have a cert file. I will need to refactor
// this to setup the TPC connection manually to support this. As we have passed in a
// certificate we are assuming its all good. If we really want this to be secure for now we
// need to setup the certificates in the system root store.
if config.cert_file.is_some() {
log::warn!("Skipping tls verification for {}", &config.host);
client_builder = client_builder.danger_skip_tls_verify(true);
}
let client = client_builder
.connect()
.expect("Could not connect to the server");
let mut session = client
.login(user, pass)
.login(&config.user, config.password())
.expect("Unable to login please ensure yor credentials are correct");
let capabilities = session.capabilities().expect("Unable to get capabilities");
if !capabilities.has_str("IDLE") {
log::info!(
"Skipping connection, {} dose not support idle connections",
&host
&config.host
);
return None;
@ -55,12 +67,13 @@ fn main() {
let channel_name = channel.name.clone();
watchers.push(thread::spawn(move || {
let mut session = connect(
imap_store.host.clone(),
imap_store.user.clone(),
imap_store.password().clone(),
)
.unwrap();
let mut session = match connect(&imap_store) {
Some(session) => session,
None => {
log::error!("Unable to connect to channel {}", channel_name);
return;
}
};
log::info!("Watching for messages on channel {}", channel_name);
@ -71,14 +84,9 @@ fn main() {
if result.is_err() {
log::error!("Error while idling: {:?}", result);
thread::sleep(std::time::Duration::from_secs(10));
session = connect(
imap_store.host.clone(),
imap_store.user.clone(),
imap_store.password().clone(),
)
.unwrap();
thread::sleep(std::time::Duration::from_secs(10));
session = connect(&imap_store).unwrap();
continue;
}