0
0
Fork 0
mirror of https://git.verdigado.com/NB-Public/simple-wkd.git synced 2024-12-05 02:52:50 +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::settings::{MAILER, ROOT_FOLDER, SETTINGS};
use crate::utils::{get_email_from_cert, parse_pem, read_file};
use anyhow::{anyhow, bail, Result};
use anyhow::Result;
use lettre::{Message, Transport};
use std::fs;
@ -26,9 +26,7 @@ pub fn confirm_action(token: &str) -> Result<(Action, String)> {
let email = get_email_from_cert(&cert)?;
let domain = match email.split('@').last() {
Some(domain) => domain.to_string(),
None => {
Err(SpecialErrors::MalformedEmail)?
}
None => Err(SpecialErrors::MalformedEmail)?,
};
sequoia_net::wkd::insert(ROOT_FOLDER, domain, SETTINGS.variant, &cert)?;
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!")
}
})
.to(address.parse()?)
.to(match address.parse() {
Ok(mbox) => mbox,
Err(_) => Err(SpecialErrors::MalformedEmail)?,
})
.subject(
SETTINGS
.mail_settings

View file

@ -7,14 +7,18 @@ use crate::utils::return_outcome;
#[derive(Debug, DeriveError)]
pub enum SpecialErrors {
#[error("Could not find any primay user email in the keyblock!")]
EmailMissing,
#[error("The request had expired!")]
ExpiredRequest,
#[error("The key for the requested user does not exist!")]
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")]
MalformedEmail,
#[error("Could not find any primay user email in the keyblock!")]
MalformedCert,
#[error("The requested file does not exist!")]
MissingFile,
#[error("User email rejected: domain not allowed")]
@ -55,20 +59,22 @@ impl From<Error> for CompatErr {
impl ResponseError for CompatErr {
fn status_code(&self) -> actix_web::http::StatusCode {
match self {
Self::AnyhowErr(_) => StatusCode::INTERNAL_SERVER_ERROR,
Self::SpecialErr(error) => match error {
SpecialErrors::ExpiredRequest => StatusCode::BAD_REQUEST,
SpecialErrors::InexistingUser => StatusCode::NOT_FOUND,
SpecialErrors::MalformedCert => StatusCode::BAD_REQUEST,
SpecialErrors::MalformedEmail => StatusCode::BAD_REQUEST,
SpecialErrors::MissingFile => StatusCode::NOT_FOUND,
SpecialErrors::UnallowedDomain => StatusCode::UNAUTHORIZED,
}
Self::AnyhowErr(_) => StatusCode::INTERNAL_SERVER_ERROR,
Self::SpecialErr(error) => match error {
SpecialErrors::ExpiredRequest => StatusCode::BAD_REQUEST,
SpecialErrors::InexistingUser => StatusCode::NOT_FOUND,
SpecialErrors::InvalidCert => StatusCode::BAD_REQUEST,
SpecialErrors::EmailMissing => StatusCode::BAD_REQUEST,
SpecialErrors::MalformedCert => StatusCode::BAD_REQUEST,
SpecialErrors::MalformedEmail => StatusCode::BAD_REQUEST,
SpecialErrors::MissingFile => StatusCode::NOT_FOUND,
SpecialErrors::UnallowedDomain => StatusCode::UNAUTHORIZED,
},
}
}
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,
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::settings::{ROOT_FOLDER, SETTINGS};
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;
@ -18,7 +18,6 @@ use actix_web::http::StatusCode;
use actix_web::{
get, post, web, App, HttpRequest, HttpResponse, HttpResponseBuilder, HttpServer, Result,
};
use anyhow::anyhow;
use errors::SpecialErrors;
use serde::Deserialize;
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> {
let (action, _email) = confirm_action(&token.token)?;
match action {
Action::Add => {
Ok(return_outcome(Ok("Your key was added successfully!"))?)
}
Action::Delete => {
Ok(return_outcome(Ok("Your key was deleted successfully!"))?)
}
Action::Add => Ok(return_outcome(Ok("Your key was added 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();
store_pending_deletion(email.email.clone(), &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 once_cell::sync::Lazy;
use sequoia_net::wkd::Variant;
use sequoia_openpgp::policy::StandardPolicy;
use serde::{Deserialize, Serialize};
use std::{path::{PathBuf}};
use std::path::PathBuf;
use url::Url;
use crate::utils::read_file;
@ -84,6 +85,7 @@ fn get_mailer() -> SmtpTransport {
mailer
}
pub const POLICY: &StandardPolicy = &StandardPolicy::new();
pub const ROOT_FOLDER: &str = "data";
pub static SETTINGS: Lazy<Settings> = Lazy::new(get_settings);
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::settings::POLICY;
use crate::settings::ROOT_FOLDER;
use crate::settings::SETTINGS;
use actix_web::ResponseError;
use actix_web::{
http::{header::ContentType, StatusCode},
HttpResponse, HttpResponseBuilder,
};
use anyhow::{anyhow, bail, Result};
use anyhow::Result;
use flexi_logger::{
detailed_format, style, DeferredNow, FileSpec, FlexiLoggerError, Logger, LoggerHandle, Record,
};
use rand::{distributions::Alphanumeric, thread_rng, Rng};
use sequoia_net::wkd::Url;
use sequoia_openpgp::{parse::Parse, policy::StandardPolicy, Cert};
use sequoia_openpgp::{parse::Parse, Cert};
use std::{
fs,
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> {
if path.is_file() {
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> {
let cert = sequoia_openpgp::Cert::from_bytes(pemfile.as_bytes())?;
let policy = StandardPolicy::new();
cert.with_policy(&policy, None)?;
let cert = match sequoia_openpgp::Cert::from_bytes(pemfile.as_bytes()) {
Ok(cert) => cert,
Err(_) => Err(SpecialErrors::MalformedCert)?,
};
validate_cert!(cert)?;
Ok(cert)
}
@ -64,13 +79,12 @@ pub fn gen_random_token() -> String {
}
pub fn get_email_from_cert(cert: &Cert) -> Result<String> {
let policy = StandardPolicy::new();
let validcert = cert.with_policy(&policy, None)?;
let validcert = validate_cert!(cert)?;
let userid_opt = validcert.primary_userid()?;
let email_opt = userid_opt.email()?;
match email_opt {
Some(email) => Ok(email),
None => Err(SpecialErrors::MalformedCert)?,
None => Err(SpecialErrors::EmailMissing)?,
}
}
@ -135,15 +149,19 @@ pub fn init_logger() -> Result<LoggerHandle, FlexiLoggerError> {
.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 template = read_file(&path)?;
let (page, message) = match data {
Ok(message) => (template.replace("((%s))", "Success!"), message),
Err(message) => (template.replace("((%s))", "Failure!"), message),
Ok(message) => (template.replace("((%s))", "Success!"), message.to_string()),
Err(error) => (template.replace("((%s))", "Failure!"), error.to_string()),
};
let page = page.replace("((%m))", message);
return Ok(HttpResponseBuilder::new(StatusCode::OK)
let status_code = match data {
Ok(_) => StatusCode::OK,
Err(error) => error.status_code(),
};
let page = page.replace("((%m))", &message);
return Ok(HttpResponseBuilder::new(status_code)
.insert_header(ContentType::html())
.body(page));
}