0
0
Fork 0
mirror of https://git.verdigado.com/NB-Public/simple-wkd.git synced 2024-10-30 05:05:52 +01:00

Improve error handling further

This commit is contained in:
Delta1925 2023-04-17 23:22:58 +02:00
parent 0f5b9ae1d6
commit 85b2c707b8
No known key found for this signature in database
GPG key ID: 1C21ACE44193CB25
5 changed files with 64 additions and 40 deletions

View file

@ -6,7 +6,7 @@ use crate::management::{delete_key, Action, Pending};
use crate::pending_path; use crate::pending_path;
use crate::settings::{MAILER, ROOT_FOLDER, SETTINGS}; use crate::settings::{MAILER, ROOT_FOLDER, SETTINGS};
use crate::utils::{get_email_from_cert, parse_pem, read_file}; use crate::utils::{get_email_from_cert, parse_pem, read_file};
use anyhow::{anyhow, bail, Result}; use anyhow::Result;
use lettre::{Message, Transport}; use lettre::{Message, Transport};
use std::fs; use std::fs;
@ -26,9 +26,7 @@ pub fn confirm_action(token: &str) -> Result<(Action, String)> {
let email = get_email_from_cert(&cert)?; let email = get_email_from_cert(&cert)?;
let domain = match email.split('@').last() { let domain = match email.split('@').last() {
Some(domain) => domain.to_string(), Some(domain) => domain.to_string(),
None => { None => Err(SpecialErrors::MalformedEmail)?,
Err(SpecialErrors::MalformedEmail)?
}
}; };
sequoia_net::wkd::insert(ROOT_FOLDER, domain, SETTINGS.variant, &cert)?; sequoia_net::wkd::insert(ROOT_FOLDER, domain, SETTINGS.variant, &cert)?;
email email
@ -59,7 +57,10 @@ pub fn send_confirmation_email(address: &str, action: &Action, token: &str) -> R
panic!("Unable to parse the email in the settings!") panic!("Unable to parse the email in the settings!")
} }
}) })
.to(address.parse()?) .to(match address.parse() {
Ok(mbox) => mbox,
Err(_) => Err(SpecialErrors::MalformedEmail)?,
})
.subject( .subject(
SETTINGS SETTINGS
.mail_settings .mail_settings

View file

@ -7,14 +7,18 @@ use crate::utils::return_outcome;
#[derive(Debug, DeriveError)] #[derive(Debug, DeriveError)]
pub enum SpecialErrors { pub enum SpecialErrors {
#[error("Could not find any primay user email in the keyblock!")]
EmailMissing,
#[error("The request had expired!")] #[error("The request had expired!")]
ExpiredRequest, ExpiredRequest,
#[error("The key for the requested user does not exist!")] #[error("The key for the requested user does not exist!")]
InexistingUser, InexistingUser,
#[error("The key is either expired or uses an obsolete cipher!")]
InvalidCert,
#[error("Could not parse keyblock")]
MalformedCert,
#[error("Could not parse user email: malformed email")] #[error("Could not parse user email: malformed email")]
MalformedEmail, MalformedEmail,
#[error("Could not find any primay user email in the keyblock!")]
MalformedCert,
#[error("The requested file does not exist!")] #[error("The requested file does not exist!")]
MissingFile, MissingFile,
#[error("User email rejected: domain not allowed")] #[error("User email rejected: domain not allowed")]
@ -59,16 +63,18 @@ impl ResponseError for CompatErr {
Self::SpecialErr(error) => match error { Self::SpecialErr(error) => match error {
SpecialErrors::ExpiredRequest => StatusCode::BAD_REQUEST, SpecialErrors::ExpiredRequest => StatusCode::BAD_REQUEST,
SpecialErrors::InexistingUser => StatusCode::NOT_FOUND, SpecialErrors::InexistingUser => StatusCode::NOT_FOUND,
SpecialErrors::InvalidCert => StatusCode::BAD_REQUEST,
SpecialErrors::EmailMissing => StatusCode::BAD_REQUEST,
SpecialErrors::MalformedCert => StatusCode::BAD_REQUEST, SpecialErrors::MalformedCert => StatusCode::BAD_REQUEST,
SpecialErrors::MalformedEmail => StatusCode::BAD_REQUEST, SpecialErrors::MalformedEmail => StatusCode::BAD_REQUEST,
SpecialErrors::MissingFile => StatusCode::NOT_FOUND, SpecialErrors::MissingFile => StatusCode::NOT_FOUND,
SpecialErrors::UnallowedDomain => StatusCode::UNAUTHORIZED, SpecialErrors::UnallowedDomain => StatusCode::UNAUTHORIZED,
} },
} }
} }
fn error_response(&self) -> actix_web::HttpResponse<actix_web::body::BoxBody> { fn error_response(&self) -> actix_web::HttpResponse<actix_web::body::BoxBody> {
match return_outcome(Err(&self.to_string())) { match return_outcome(Err(self)) {
Ok(httpbuilder) => httpbuilder, Ok(httpbuilder) => httpbuilder,
Err(_) => HttpResponseBuilder::new(self.status_code()).body(self.to_string()), Err(_) => HttpResponseBuilder::new(self.status_code()).body(self.to_string()),
} }

View file

@ -9,7 +9,7 @@ use crate::errors::CompatErr;
use crate::management::{clean_stale, store_pending_addition, store_pending_deletion, Action}; use crate::management::{clean_stale, store_pending_addition, store_pending_deletion, Action};
use crate::settings::{ROOT_FOLDER, SETTINGS}; use crate::settings::{ROOT_FOLDER, SETTINGS};
use crate::utils::{ use crate::utils::{
gen_random_token, get_email_from_cert, is_email_allowed, parse_pem, return_outcome, read_file, gen_random_token, get_email_from_cert, is_email_allowed, parse_pem, read_file, return_outcome,
}; };
use actix_files::Files; use actix_files::Files;
@ -18,7 +18,6 @@ use actix_web::http::StatusCode;
use actix_web::{ use actix_web::{
get, post, web, App, HttpRequest, HttpResponse, HttpResponseBuilder, HttpServer, Result, get, post, web, App, HttpRequest, HttpResponse, HttpResponseBuilder, HttpServer, Result,
}; };
use anyhow::anyhow;
use errors::SpecialErrors; use errors::SpecialErrors;
use serde::Deserialize; use serde::Deserialize;
use std::env; use std::env;
@ -108,12 +107,8 @@ async fn submit(pem: web::Form<Key>) -> Result<HttpResponse, CompatErr> {
async fn confirm(token: web::Query<Token>) -> Result<HttpResponse, CompatErr> { async fn confirm(token: web::Query<Token>) -> Result<HttpResponse, CompatErr> {
let (action, _email) = confirm_action(&token.token)?; let (action, _email) = confirm_action(&token.token)?;
match action { match action {
Action::Add => { Action::Add => Ok(return_outcome(Ok("Your key was added successfully!"))?),
Ok(return_outcome(Ok("Your key was added successfully!"))?) Action::Delete => Ok(return_outcome(Ok("Your key was deleted successfully!"))?),
}
Action::Delete => {
Ok(return_outcome(Ok("Your key was deleted successfully!"))?)
}
} }
} }
@ -122,5 +117,7 @@ async fn delete(email: web::Query<Email>) -> Result<HttpResponse, CompatErr> {
let token = gen_random_token(); let token = gen_random_token();
store_pending_deletion(email.email.clone(), &token)?; store_pending_deletion(email.email.clone(), &token)?;
send_confirmation_email(&email.email, &Action::Delete, &token)?; send_confirmation_email(&email.email, &Action::Delete, &token)?;
Ok(return_outcome(Ok("You requested the deletion of your key successfully!"))?) Ok(return_outcome(Ok(
"You requested the deletion of your key successfully!",
))?)
} }

View file

@ -1,8 +1,9 @@
use lettre::{transport::smtp::authentication::Credentials, SmtpTransport}; use lettre::{transport::smtp::authentication::Credentials, SmtpTransport};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use sequoia_net::wkd::Variant; use sequoia_net::wkd::Variant;
use sequoia_openpgp::policy::StandardPolicy;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{path::{PathBuf}}; use std::path::PathBuf;
use url::Url; use url::Url;
use crate::utils::read_file; use crate::utils::read_file;
@ -84,6 +85,7 @@ fn get_mailer() -> SmtpTransport {
mailer mailer
} }
pub const POLICY: &StandardPolicy = &StandardPolicy::new();
pub const ROOT_FOLDER: &str = "data"; pub const ROOT_FOLDER: &str = "data";
pub static SETTINGS: Lazy<Settings> = Lazy::new(get_settings); pub static SETTINGS: Lazy<Settings> = Lazy::new(get_settings);
pub static MAILER: Lazy<SmtpTransport> = Lazy::new(get_mailer); pub static MAILER: Lazy<SmtpTransport> = Lazy::new(get_mailer);

View file

@ -1,18 +1,21 @@
use crate::errors::CompatErr;
use crate::errors::SpecialErrors; use crate::errors::SpecialErrors;
use crate::settings::POLICY;
use crate::settings::ROOT_FOLDER; use crate::settings::ROOT_FOLDER;
use crate::settings::SETTINGS; use crate::settings::SETTINGS;
use actix_web::ResponseError;
use actix_web::{ use actix_web::{
http::{header::ContentType, StatusCode}, http::{header::ContentType, StatusCode},
HttpResponse, HttpResponseBuilder, HttpResponse, HttpResponseBuilder,
}; };
use anyhow::{anyhow, bail, Result}; use anyhow::Result;
use flexi_logger::{ use flexi_logger::{
detailed_format, style, DeferredNow, FileSpec, FlexiLoggerError, Logger, LoggerHandle, Record, detailed_format, style, DeferredNow, FileSpec, FlexiLoggerError, Logger, LoggerHandle, Record,
}; };
use rand::{distributions::Alphanumeric, thread_rng, Rng}; use rand::{distributions::Alphanumeric, thread_rng, Rng};
use sequoia_net::wkd::Url; use sequoia_net::wkd::Url;
use sequoia_openpgp::{parse::Parse, policy::StandardPolicy, Cert}; use sequoia_openpgp::{parse::Parse, Cert};
use std::{ use std::{
fs, fs,
path::{Path, PathBuf}, path::{Path, PathBuf},
@ -32,6 +35,16 @@ macro_rules! webpage_path {
}; };
} }
#[macro_export]
macro_rules! validate_cert {
( $x:expr ) => {
match $x.with_policy(POLICY, None) {
Ok(validcert) => Ok(validcert),
Err(_) => Err(SpecialErrors::InvalidCert),
}
};
}
pub fn read_file(path: &PathBuf) -> Result<String> { pub fn read_file(path: &PathBuf) -> Result<String> {
if path.is_file() { if path.is_file() {
Ok(fs::read_to_string(path)?) Ok(fs::read_to_string(path)?)
@ -52,9 +65,11 @@ pub fn is_email_allowed(email: &str) -> Result<()> {
} }
pub fn parse_pem(pemfile: &str) -> Result<Cert> { pub fn parse_pem(pemfile: &str) -> Result<Cert> {
let cert = sequoia_openpgp::Cert::from_bytes(pemfile.as_bytes())?; let cert = match sequoia_openpgp::Cert::from_bytes(pemfile.as_bytes()) {
let policy = StandardPolicy::new(); Ok(cert) => cert,
cert.with_policy(&policy, None)?; Err(_) => Err(SpecialErrors::MalformedCert)?,
};
validate_cert!(cert)?;
Ok(cert) Ok(cert)
} }
@ -64,13 +79,12 @@ pub fn gen_random_token() -> String {
} }
pub fn get_email_from_cert(cert: &Cert) -> Result<String> { pub fn get_email_from_cert(cert: &Cert) -> Result<String> {
let policy = StandardPolicy::new(); let validcert = validate_cert!(cert)?;
let validcert = cert.with_policy(&policy, None)?;
let userid_opt = validcert.primary_userid()?; let userid_opt = validcert.primary_userid()?;
let email_opt = userid_opt.email()?; let email_opt = userid_opt.email()?;
match email_opt { match email_opt {
Some(email) => Ok(email), Some(email) => Ok(email),
None => Err(SpecialErrors::MalformedCert)?, None => Err(SpecialErrors::EmailMissing)?,
} }
} }
@ -135,15 +149,19 @@ pub fn init_logger() -> Result<LoggerHandle, FlexiLoggerError> {
.start() .start()
} }
pub fn return_outcome(data: Result<&str, &str>) -> Result<HttpResponse> { pub fn return_outcome(data: Result<&str, &CompatErr>) -> Result<HttpResponse> {
let path = webpage_path!().join("status").join("index.html"); let path = webpage_path!().join("status").join("index.html");
let template = read_file(&path)?; let template = read_file(&path)?;
let (page, message) = match data { let (page, message) = match data {
Ok(message) => (template.replace("((%s))", "Success!"), message), Ok(message) => (template.replace("((%s))", "Success!"), message.to_string()),
Err(message) => (template.replace("((%s))", "Failure!"), message), Err(error) => (template.replace("((%s))", "Failure!"), error.to_string()),
}; };
let page = page.replace("((%m))", message); let status_code = match data {
return Ok(HttpResponseBuilder::new(StatusCode::OK) Ok(_) => StatusCode::OK,
Err(error) => error.status_code(),
};
let page = page.replace("((%m))", &message);
return Ok(HttpResponseBuilder::new(status_code)
.insert_header(ContentType::html()) .insert_header(ContentType::html())
.body(page)); .body(page));
} }