Add error type for AP authentication errors

This commit is contained in:
silverpill 2022-10-27 18:23:48 +00:00
parent b345cb4a77
commit 077d942573
3 changed files with 37 additions and 27 deletions

View file

@ -2,10 +2,11 @@ use actix_web::HttpRequest;
use tokio_postgres::GenericClient; use tokio_postgres::GenericClient;
use crate::config::Config; use crate::config::Config;
use crate::errors::DatabaseError;
use crate::http_signatures::verify::{ use crate::http_signatures::verify::{
parse_http_signature, parse_http_signature,
verify_http_signature, verify_http_signature,
VerificationError, HttpSignatureVerificationError as HttpSignatureError,
}; };
use crate::models::profiles::queries::get_profile_by_remote_actor_id; use crate::models::profiles::queries::get_profile_by_remote_actor_id;
use crate::models::profiles::types::DbActorProfile; use crate::models::profiles::types::DbActorProfile;
@ -13,7 +14,28 @@ use crate::utils::crypto::deserialize_public_key;
use super::fetcher::helpers::get_or_import_profile_by_actor_id; use super::fetcher::helpers::get_or_import_profile_by_actor_id;
use super::receiver::HandlerError; use super::receiver::HandlerError;
fn key_id_to_actor_id(key_id: &str) -> Result<String, VerificationError> { #[derive(thiserror::Error, Debug)]
pub enum AuthenticationError {
#[error(transparent)]
HttpSignatureError(#[from] HttpSignatureError),
#[error("invalid key ID")]
InvalidKeyId(#[from] url::ParseError),
#[error("database error")]
DatabaseError(#[from] DatabaseError),
#[error("{0}")]
ActorError(String),
#[error("invalid public key")]
InvalidPublicKey(#[from] rsa::pkcs8::Error),
#[error("actor and request signer do not match")]
InvalidSigner,
}
fn key_id_to_actor_id(key_id: &str) -> Result<String, AuthenticationError> {
let key_url = url::Url::parse(key_id)?; let key_url = url::Url::parse(key_id)?;
// Strip #main-key (works with most AP servers) // Strip #main-key (works with most AP servers)
let actor_id = &key_url[..url::Position::BeforeQuery]; let actor_id = &key_url[..url::Position::BeforeQuery];
@ -28,7 +50,7 @@ pub async fn verify_signed_request(
db_client: &impl GenericClient, db_client: &impl GenericClient,
request: &HttpRequest, request: &HttpRequest,
no_fetch: bool, no_fetch: bool,
) -> Result<DbActorProfile, VerificationError> { ) -> Result<DbActorProfile, AuthenticationError> {
let signature_data = parse_http_signature( let signature_data = parse_http_signature(
request.method(), request.method(),
request.uri(), request.uri(),
@ -48,12 +70,12 @@ pub async fn verify_signed_request(
Ok(profile) => profile, Ok(profile) => profile,
Err(HandlerError::DatabaseError(error)) => return Err(error.into()), Err(HandlerError::DatabaseError(error)) => return Err(error.into()),
Err(other_error) => { Err(other_error) => {
return Err(VerificationError::ActorError(other_error.to_string())); return Err(AuthenticationError::ActorError(other_error.to_string()));
}, },
} }
}; };
let actor = actor_profile.actor_json.as_ref() let actor = actor_profile.actor_json.as_ref()
.ok_or(VerificationError::ActorError("invalid profile".to_string()))?; .ok_or(AuthenticationError::ActorError("invalid profile".to_string()))?;
let public_key = deserialize_public_key(&actor.public_key.public_key_pem)?; let public_key = deserialize_public_key(&actor.public_key.public_key_pem)?;
verify_http_signature(&signature_data, &public_key)?; verify_http_signature(&signature_data, &public_key)?;

View file

@ -10,9 +10,11 @@ use crate::errors::{
HttpError, HttpError,
ValidationError, ValidationError,
}; };
use crate::http_signatures::verify::VerificationError;
use super::activity::{Activity, Object}; use super::activity::{Activity, Object};
use super::authentication::verify_signed_request; use super::authentication::{
verify_signed_request,
AuthenticationError,
};
use super::fetcher::{ use super::fetcher::{
fetchers::FetchError, fetchers::FetchError,
helpers::import_post, helpers::import_post,
@ -49,7 +51,7 @@ pub enum HandlerError {
DatabaseError(#[from] DatabaseError), DatabaseError(#[from] DatabaseError),
#[error(transparent)] #[error(transparent)]
AuthError(#[from] VerificationError), AuthError(#[from] AuthenticationError),
} }
impl From<HandlerError> for HttpError { impl From<HandlerError> for HttpError {
@ -129,7 +131,7 @@ pub fn find_object_id(object: &Value) -> Result<String, ValidationError> {
} }
fn require_actor_signature(actor_id: &str, signer_id: &str) fn require_actor_signature(actor_id: &str, signer_id: &str)
-> Result<(), VerificationError> -> Result<(), AuthenticationError>
{ {
if actor_id != signer_id { if actor_id != signer_id {
// Forwarded activity // Forwarded activity
@ -138,7 +140,7 @@ fn require_actor_signature(actor_id: &str, signer_id: &str)
signer_id, signer_id,
actor_id, actor_id,
); );
return Err(VerificationError::InvalidSigner); return Err(AuthenticationError::InvalidSigner);
}; };
Ok(()) Ok(())
} }

View file

@ -5,39 +5,25 @@ use chrono::{DateTime, TimeZone, Utc};
use regex::Regex; use regex::Regex;
use rsa::RsaPublicKey; use rsa::RsaPublicKey;
use crate::errors::DatabaseError;
use crate::utils::crypto::verify_signature; use crate::utils::crypto::verify_signature;
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum VerificationError { pub enum HttpSignatureVerificationError {
#[error("{0}")] #[error("{0}")]
HeaderError(&'static str), HeaderError(&'static str),
#[error("{0}")] #[error("{0}")]
ParseError(&'static str), ParseError(&'static str),
#[error("invalid key ID")]
UrlError(#[from] url::ParseError),
#[error("database error")]
DatabaseError(#[from] DatabaseError),
#[error("{0}")]
ActorError(String),
#[error("invalid public key")]
InvalidPublicKey(#[from] rsa::pkcs8::Error),
#[error("invalid encoding")] #[error("invalid encoding")]
InvalidEncoding(#[from] base64::DecodeError), InvalidEncoding(#[from] base64::DecodeError),
#[error("invalid signature")] #[error("invalid signature")]
InvalidSignature, InvalidSignature,
#[error("actor and request signer do not match")]
InvalidSigner,
} }
type VerificationError = HttpSignatureVerificationError;
pub struct HttpSignatureData { pub struct HttpSignatureData {
pub key_id: String, pub key_id: String,
pub message: String, // reconstructed message pub message: String, // reconstructed message