Use anyhow::Error for UrlVerifier return type (fixes #61) (#65)

* Use anyhow::Error for UrlVerifier return type (fixes #61)

* fmt

* uncomment
This commit is contained in:
Nutomic 2023-07-26 16:26:22 +02:00 committed by GitHub
parent 32e3cd5574
commit 426871f5af
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 26 additions and 22 deletions

View file

@ -49,9 +49,9 @@ struct MyUrlVerifier();
#[async_trait] #[async_trait]
impl UrlVerifier for MyUrlVerifier { impl UrlVerifier for MyUrlVerifier {
async fn verify(&self, url: &Url) -> Result<(), &'static str> { async fn verify(&self, url: &Url) -> Result<(), anyhow::Error> {
if url.domain() == Some("malicious.com") { if url.domain() == Some("malicious.com") {
Err("malicious domain") Err(anyhow!("malicious domain"))
} else { } else {
Ok(()) Ok(())
} }

View file

@ -21,7 +21,7 @@ use crate::{
protocol::verification::verify_domains_match, protocol::verification::verify_domains_match,
traits::{ActivityHandler, Actor}, traits::{ActivityHandler, Actor},
}; };
use anyhow::Context; use anyhow::{anyhow, Context};
use async_trait::async_trait; use async_trait::async_trait;
use derive_builder::Builder; use derive_builder::Builder;
use dyn_clone::{clone_trait_object, DynClone}; use dyn_clone::{clone_trait_object, DynClone};
@ -114,9 +114,9 @@ impl<T: Clone> FederationConfig<T> {
verify_domains_match(activity.id(), activity.actor())?; verify_domains_match(activity.id(), activity.actor())?;
self.verify_url_valid(activity.id()).await?; self.verify_url_valid(activity.id()).await?;
if self.is_local_url(activity.id()) { if self.is_local_url(activity.id()) {
return Err(Error::UrlVerificationError( return Err(Error::UrlVerificationError(anyhow!(
"Activity was sent from local instance", "Activity was sent from local instance"
)); )));
} }
Ok(()) Ok(())
@ -139,12 +139,12 @@ impl<T: Clone> FederationConfig<T> {
"https" => {} "https" => {}
"http" => { "http" => {
if !self.allow_http_urls { if !self.allow_http_urls {
return Err(Error::UrlVerificationError( return Err(Error::UrlVerificationError(anyhow!(
"Http urls are only allowed in debug mode", "Http urls are only allowed in debug mode"
)); )));
} }
} }
_ => return Err(Error::UrlVerificationError("Invalid url scheme")), _ => return Err(Error::UrlVerificationError(anyhow!("Invalid url scheme"))),
}; };
// Urls which use our local domain are not a security risk, no further verification needed // Urls which use our local domain are not a security risk, no further verification needed
@ -153,13 +153,15 @@ impl<T: Clone> FederationConfig<T> {
} }
if url.domain().is_none() { if url.domain().is_none() {
return Err(Error::UrlVerificationError("Url must have a domain")); return Err(Error::UrlVerificationError(anyhow!(
"Url must have a domain"
)));
} }
if url.domain() == Some("localhost") && !self.debug { if url.domain() == Some("localhost") && !self.debug {
return Err(Error::UrlVerificationError( return Err(Error::UrlVerificationError(anyhow!(
"Localhost is only allowed in debug mode", "Localhost is only allowed in debug mode"
)); )));
} }
self.url_verifier self.url_verifier
@ -258,6 +260,7 @@ impl<T: Clone> Deref for FederationConfig<T> {
/// # use async_trait::async_trait; /// # use async_trait::async_trait;
/// # use url::Url; /// # use url::Url;
/// # use activitypub_federation::config::UrlVerifier; /// # use activitypub_federation::config::UrlVerifier;
/// # use anyhow::anyhow;
/// # #[derive(Clone)] /// # #[derive(Clone)]
/// # struct DatabaseConnection(); /// # struct DatabaseConnection();
/// # async fn get_blocklist(_: &DatabaseConnection) -> Vec<String> { /// # async fn get_blocklist(_: &DatabaseConnection) -> Vec<String> {
@ -270,11 +273,11 @@ impl<T: Clone> Deref for FederationConfig<T> {
/// ///
/// #[async_trait] /// #[async_trait]
/// impl UrlVerifier for Verifier { /// impl UrlVerifier for Verifier {
/// async fn verify(&self, url: &Url) -> Result<(), &'static str> { /// async fn verify(&self, url: &Url) -> Result<(), anyhow::Error> {
/// let blocklist = get_blocklist(&self.db_connection).await; /// let blocklist = get_blocklist(&self.db_connection).await;
/// let domain = url.domain().unwrap().to_string(); /// let domain = url.domain().unwrap().to_string();
/// if blocklist.contains(&domain) { /// if blocklist.contains(&domain) {
/// Err("Domain is blocked") /// Err(anyhow!("Domain is blocked"))
/// } else { /// } else {
/// Ok(()) /// Ok(())
/// } /// }
@ -284,7 +287,7 @@ impl<T: Clone> Deref for FederationConfig<T> {
#[async_trait] #[async_trait]
pub trait UrlVerifier: DynClone + Send { pub trait UrlVerifier: DynClone + Send {
/// Should return Ok iff the given url is valid for processing. /// Should return Ok iff the given url is valid for processing.
async fn verify(&self, url: &Url) -> Result<(), &'static str>; async fn verify(&self, url: &Url) -> Result<(), anyhow::Error>;
} }
/// Default URL verifier which does nothing. /// Default URL verifier which does nothing.
@ -293,7 +296,7 @@ struct DefaultUrlVerifier();
#[async_trait] #[async_trait]
impl UrlVerifier for DefaultUrlVerifier { impl UrlVerifier for DefaultUrlVerifier {
async fn verify(&self, _url: &Url) -> Result<(), &'static str> { async fn verify(&self, _url: &Url) -> Result<(), anyhow::Error> {
Ok(()) Ok(())
} }
} }

View file

@ -16,8 +16,8 @@ pub enum Error {
#[error("Object to be fetched was deleted")] #[error("Object to be fetched was deleted")]
ObjectDeleted, ObjectDeleted,
/// url verification error /// url verification error
#[error("{0}")] #[error("URL failed verification: {0}")]
UrlVerificationError(&'static str), UrlVerificationError(anyhow::Error),
/// Incoming activity has invalid digest for body /// Incoming activity has invalid digest for body
#[error("Incoming activity has invalid digest for body")] #[error("Incoming activity has invalid digest for body")]
ActivityBodyDigestInvalid, ActivityBodyDigestInvalid,

View file

@ -1,6 +1,7 @@
//! Verify that received data is valid //! Verify that received data is valid
use crate::error::Error; use crate::error::Error;
use anyhow::anyhow;
use url::Url; use url::Url;
/// Check that both urls have the same domain. If not, return UrlVerificationError. /// Check that both urls have the same domain. If not, return UrlVerificationError.
@ -15,7 +16,7 @@ use url::Url;
/// ``` /// ```
pub fn verify_domains_match(a: &Url, b: &Url) -> Result<(), Error> { pub fn verify_domains_match(a: &Url, b: &Url) -> Result<(), Error> {
if a.domain() != b.domain() { if a.domain() != b.domain() {
return Err(Error::UrlVerificationError("Domains do not match")); return Err(Error::UrlVerificationError(anyhow!("Domains do not match")));
} }
Ok(()) Ok(())
} }
@ -32,7 +33,7 @@ pub fn verify_domains_match(a: &Url, b: &Url) -> Result<(), Error> {
/// ``` /// ```
pub fn verify_urls_match(a: &Url, b: &Url) -> Result<(), Error> { pub fn verify_urls_match(a: &Url, b: &Url) -> Result<(), Error> {
if a != b { if a != b {
return Err(Error::UrlVerificationError("Urls do not match")); return Err(Error::UrlVerificationError(anyhow!("Urls do not match")));
} }
Ok(()) Ok(())
} }