2023-04-14 01:05:27 +02:00
|
|
|
use chrono::Utc;
|
2023-04-15 15:08:21 +02:00
|
|
|
use lettre::message::header::ContentType;
|
2023-04-14 18:55:17 +02:00
|
|
|
use log::{debug, error, trace, warn};
|
2023-04-14 01:05:27 +02:00
|
|
|
|
2023-04-13 22:00:33 +02:00
|
|
|
use crate::errors::Error;
|
2023-04-13 18:56:32 +02:00
|
|
|
use crate::management::{delete_key, Action, Pending};
|
2023-04-14 00:52:54 +02:00
|
|
|
use crate::pending_path;
|
2023-04-14 14:23:28 +02:00
|
|
|
use crate::settings::{MAILER, SETTINGS};
|
2023-04-14 18:55:17 +02:00
|
|
|
use crate::utils::{get_email_from_cert, get_filename, parse_pem};
|
2023-04-13 18:56:32 +02:00
|
|
|
|
2023-04-14 14:23:28 +02:00
|
|
|
use lettre::{Message, Transport};
|
2023-04-13 18:56:32 +02:00
|
|
|
use std::fs;
|
|
|
|
use std::path::Path;
|
|
|
|
|
2023-04-14 18:55:17 +02:00
|
|
|
pub fn confirm_action(token: &str) -> Result<(Action, String), Error> {
|
|
|
|
trace!("Handling token {}", token);
|
2023-04-13 18:56:32 +02:00
|
|
|
let pending_path = pending_path!().join(token);
|
2023-04-13 22:55:05 +02:00
|
|
|
let content = if pending_path.is_file() {
|
2023-04-13 22:00:33 +02:00
|
|
|
match fs::read_to_string(&pending_path) {
|
2023-04-13 22:26:41 +02:00
|
|
|
Ok(content) => content,
|
2023-04-14 18:55:17 +02:00
|
|
|
Err(_) => {
|
|
|
|
warn!(
|
|
|
|
"Token {} was requested, but can't be read to string!",
|
|
|
|
token
|
|
|
|
);
|
|
|
|
return Err(Error::Inaccessible);
|
|
|
|
}
|
2023-04-13 22:00:33 +02:00
|
|
|
}
|
|
|
|
} else {
|
2023-04-14 18:55:17 +02:00
|
|
|
trace!("Requested token {} isn't a file", token);
|
2023-04-13 23:32:12 +02:00
|
|
|
return Err(Error::MissingPending);
|
2023-04-13 22:00:33 +02:00
|
|
|
};
|
2023-04-13 22:26:41 +02:00
|
|
|
let key = match serde_json::from_str::<Pending>(&content) {
|
2023-04-13 22:00:33 +02:00
|
|
|
Ok(key) => key,
|
2023-04-14 18:55:17 +02:00
|
|
|
Err(_) => {
|
|
|
|
warn!("Error while deserializing token {}!", token);
|
|
|
|
return Err(Error::DeserializeData);
|
|
|
|
}
|
2023-04-13 22:00:33 +02:00
|
|
|
};
|
2023-04-14 01:05:27 +02:00
|
|
|
if Utc::now().timestamp() - key.timestamp() > SETTINGS.max_age {
|
2023-04-14 18:55:17 +02:00
|
|
|
match fs::remove_file(&pending_path) {
|
|
|
|
Ok(_) => {
|
|
|
|
debug!(
|
|
|
|
"Deleted stale token {}",
|
|
|
|
get_filename(&pending_path).unwrap()
|
|
|
|
);
|
|
|
|
Err(Error::MissingPending)
|
|
|
|
}
|
|
|
|
Err(_) => {
|
|
|
|
warn!("Stale token {} can't be deleted!", token);
|
|
|
|
Err(Error::Inaccessible)
|
|
|
|
}
|
2023-04-14 01:05:27 +02:00
|
|
|
}
|
|
|
|
} else {
|
2023-04-14 18:55:17 +02:00
|
|
|
let address = match key.action() {
|
2023-04-14 01:05:27 +02:00
|
|
|
Action::Add => {
|
|
|
|
let cert = parse_pem(key.data())?;
|
2023-04-14 18:55:17 +02:00
|
|
|
let email = get_email_from_cert(&cert)?;
|
|
|
|
let domain = match email.split('@').last() {
|
2023-04-14 01:05:27 +02:00
|
|
|
Some(domain) => domain.to_string(),
|
2023-04-14 18:55:17 +02:00
|
|
|
None => {
|
|
|
|
warn!("Error while parsing email's domain in token {}", token);
|
|
|
|
return Err(Error::ParseEmail);
|
|
|
|
}
|
2023-04-14 01:05:27 +02:00
|
|
|
};
|
|
|
|
match sequoia_net::wkd::insert(
|
2023-04-14 12:18:49 +02:00
|
|
|
&SETTINGS.root_folder,
|
2023-04-14 01:05:27 +02:00
|
|
|
domain,
|
|
|
|
SETTINGS.variant,
|
|
|
|
&cert,
|
|
|
|
) {
|
2023-04-14 18:55:17 +02:00
|
|
|
Ok(_) => email,
|
|
|
|
Err(_) => {
|
|
|
|
warn!("Unable to create a wkd entry for token {}", token);
|
|
|
|
return Err(Error::AddingKey);
|
|
|
|
}
|
2023-04-14 01:05:27 +02:00
|
|
|
}
|
2023-04-13 22:00:33 +02:00
|
|
|
}
|
2023-04-14 18:55:17 +02:00
|
|
|
Action::Delete => match delete_key(key.data()) {
|
|
|
|
Ok(_) => key.data().to_owned(),
|
|
|
|
Err(error) => {
|
|
|
|
warn!("Unable to delete key for user {}", key.data());
|
|
|
|
return Err(error);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
};
|
|
|
|
debug!("Token {} was confirmed", token);
|
2023-04-14 01:05:27 +02:00
|
|
|
match fs::remove_file(&pending_path) {
|
2023-04-14 18:55:17 +02:00
|
|
|
Ok(_) => {
|
|
|
|
trace!(
|
|
|
|
"Deleted confirmed token {}",
|
|
|
|
pending_path.file_name().unwrap().to_str().unwrap()
|
|
|
|
);
|
|
|
|
Ok((*key.action(), address))
|
|
|
|
}
|
|
|
|
Err(_) => {
|
|
|
|
warn!("Unable to delete confirmed token {}", token);
|
|
|
|
Err(Error::Inaccessible)
|
|
|
|
}
|
2023-04-13 18:56:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-14 18:55:17 +02:00
|
|
|
pub fn send_confirmation_email(address: &str, action: &Action, token: &str) -> Result<(), Error> {
|
|
|
|
debug!("Sending email to {}", address);
|
2023-04-15 16:40:42 +02:00
|
|
|
let template = fs::read_to_string(Path::new("assets").join("mail-template.html")).unwrap();
|
2023-04-15 23:51:13 +02:00
|
|
|
let mut url = SETTINGS
|
|
|
|
.external_url
|
|
|
|
.join("api/")
|
|
|
|
.unwrap()
|
|
|
|
.join("confirm")
|
|
|
|
.unwrap();
|
|
|
|
url.set_query(Some(&format!("token={}", token)));
|
2023-04-14 12:18:49 +02:00
|
|
|
let email = Message::builder()
|
|
|
|
.from(match SETTINGS.mail_settings.mail_from.parse() {
|
|
|
|
Ok(mailbox) => mailbox,
|
2023-04-14 18:55:17 +02:00
|
|
|
Err(_) => {
|
|
|
|
error!("Unable to parse the email in the settings!");
|
|
|
|
panic!("Unable to parse the email in the settings!")
|
|
|
|
}
|
2023-04-14 12:18:49 +02:00
|
|
|
})
|
2023-04-14 18:55:17 +02:00
|
|
|
.to(match address.parse() {
|
2023-04-14 12:18:49 +02:00
|
|
|
Ok(mailbox) => mailbox,
|
2023-04-14 18:55:17 +02:00
|
|
|
Err(_) => {
|
|
|
|
warn!("Error while parsing destination email for token {}", token);
|
|
|
|
return Err(Error::ParseEmail);
|
|
|
|
}
|
2023-04-14 12:18:49 +02:00
|
|
|
})
|
2023-04-14 16:33:59 +02:00
|
|
|
.subject(
|
|
|
|
SETTINGS
|
|
|
|
.mail_settings
|
|
|
|
.mail_subject
|
|
|
|
.replace("%a", &action.to_string().to_lowercase()),
|
|
|
|
)
|
2023-04-15 15:08:21 +02:00
|
|
|
.header(ContentType::TEXT_HTML)
|
|
|
|
.body(
|
|
|
|
template
|
2023-04-15 23:51:13 +02:00
|
|
|
.replace("{{%u}}", url.as_ref())
|
2023-04-15 15:08:21 +02:00
|
|
|
.replace("{{%a}}", &action.to_string().to_lowercase()),
|
|
|
|
);
|
2023-04-14 14:23:28 +02:00
|
|
|
|
2023-04-14 12:18:49 +02:00
|
|
|
let message = match email {
|
|
|
|
Ok(message) => message,
|
2023-04-14 18:55:17 +02:00
|
|
|
Err(_) => {
|
|
|
|
warn!("Unable to build email for token {}", token);
|
|
|
|
return Err(Error::MailGeneration);
|
|
|
|
}
|
2023-04-14 12:18:49 +02:00
|
|
|
};
|
2023-04-14 14:23:28 +02:00
|
|
|
|
|
|
|
match MAILER.send(&message) {
|
2023-04-14 18:55:17 +02:00
|
|
|
Ok(_) => {
|
|
|
|
debug!("successfully sent email to {}", address);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
Err(_) => {
|
|
|
|
warn!("Unable to send email to {}", address);
|
|
|
|
Err(Error::SendMail)
|
|
|
|
}
|
2023-04-14 12:18:49 +02:00
|
|
|
}
|
2023-04-13 18:56:32 +02:00
|
|
|
}
|