mirror of
https://git.verdigado.com/NB-Public/simple-wkd.git
synced 2024-10-30 03:05:51 +01:00
Improve error handling further
This commit is contained in:
parent
0f5b9ae1d6
commit
85b2c707b8
5 changed files with 64 additions and 40 deletions
|
@ -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
|
||||||
|
|
|
@ -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")]
|
||||||
|
@ -55,20 +59,22 @@ impl From<Error> for CompatErr {
|
||||||
impl ResponseError for CompatErr {
|
impl ResponseError for CompatErr {
|
||||||
fn status_code(&self) -> actix_web::http::StatusCode {
|
fn status_code(&self) -> actix_web::http::StatusCode {
|
||||||
match self {
|
match self {
|
||||||
Self::AnyhowErr(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
Self::AnyhowErr(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
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::MalformedCert => StatusCode::BAD_REQUEST,
|
SpecialErrors::InvalidCert => StatusCode::BAD_REQUEST,
|
||||||
SpecialErrors::MalformedEmail => StatusCode::BAD_REQUEST,
|
SpecialErrors::EmailMissing => StatusCode::BAD_REQUEST,
|
||||||
SpecialErrors::MissingFile => StatusCode::NOT_FOUND,
|
SpecialErrors::MalformedCert => StatusCode::BAD_REQUEST,
|
||||||
SpecialErrors::UnallowedDomain => StatusCode::UNAUTHORIZED,
|
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> {
|
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()),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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!",
|
||||||
|
))?)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue