Add error type for AP authentication errors
This commit is contained in:
parent
b345cb4a77
commit
077d942573
3 changed files with 37 additions and 27 deletions
|
@ -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)?;
|
||||||
|
|
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue