diff --git a/src/activitypub/authentication.rs b/src/activitypub/authentication.rs index 96ebc3d..f55ab41 100644 --- a/src/activitypub/authentication.rs +++ b/src/activitypub/authentication.rs @@ -32,6 +32,9 @@ pub enum AuthenticationError { #[error(transparent)] HttpSignatureError(#[from] HttpSignatureError), + #[error("no HTTP signature")] + NoHttpSignature, + #[error(transparent)] JsonSignatureError(#[from] JsonSignatureError), @@ -76,11 +79,17 @@ pub async fn verify_signed_request( request: &HttpRequest, no_fetch: bool, ) -> Result { - let signature_data = parse_http_signature( + let signature_data = match parse_http_signature( request.method(), request.uri(), request.headers(), - )?; + ) { + Ok(signature_data) => signature_data, + Err(HttpSignatureError::NoSignature) => { + return Err(AuthenticationError::NoHttpSignature); + }, + Err(other_error) => return Err(other_error.into()), + }; let actor_id = key_id_to_actor_id(&signature_data.key_id)?; let actor_profile = if no_fetch { @@ -113,12 +122,13 @@ pub async fn verify_signed_activity( db_client: &impl GenericClient, activity: &Value, ) -> Result { - let signature_data = get_json_signature(activity).map_err(|error| { - match error { - JsonSignatureError::NoProof => AuthenticationError::NoJsonSignature, - other_error => other_error.into(), - } - })?; + let signature_data = match get_json_signature(activity) { + Ok(signature_data) => signature_data, + Err(JsonSignatureError::NoProof) => { + return Err(AuthenticationError::NoJsonSignature); + }, + Err(other_error) => return Err(other_error.into()), + }; let actor_profile = match signature_data.signer { JsonSigner::ActorKeyId(ref key_id) => { diff --git a/src/activitypub/receiver.rs b/src/activitypub/receiver.rs index 6ea4432..0fa9bc8 100644 --- a/src/activitypub/receiver.rs +++ b/src/activitypub/receiver.rs @@ -157,6 +157,8 @@ pub async fn receive_activity( let object_id = find_object_id(&activity.object)?; activity.actor == object_id } else { false }; + + // HTTP signature is required let mut signer = match verify_signed_request( config, db_client, @@ -169,8 +171,13 @@ pub async fn receive_activity( request_signer }, Err(error) => { - if is_self_delete { + if is_self_delete && matches!( + error, + AuthenticationError::NoHttpSignature | + AuthenticationError::DatabaseError(_) + ) { // Ignore Delete(Person) activities without HTTP signatures + // or if signer is not found in local database return Ok(()); }; log::warn!("invalid HTTP signature: {}", error); @@ -178,7 +185,7 @@ pub async fn receive_activity( }, }; - // Verify embedded signature + // JSON signature is optional match verify_signed_activity(config, db_client, activity_raw).await { Ok(activity_signer) => { if activity_signer.acct != signer.acct { diff --git a/src/http_signatures/verify.rs b/src/http_signatures/verify.rs index 15e29e9..0a955cd 100644 --- a/src/http_signatures/verify.rs +++ b/src/http_signatures/verify.rs @@ -13,6 +13,9 @@ const SIGNATURE_EXPIRES_IN: i64 = 12; // 12 hours #[derive(thiserror::Error, Debug)] pub enum HttpSignatureVerificationError { + #[error("missing signature header")] + NoSignature, + #[error("{0}")] HeaderError(&'static str), @@ -41,7 +44,7 @@ pub fn parse_http_signature( request_headers: &HeaderMap, ) -> Result { let signature_header = request_headers.get("signature") - .ok_or(VerificationError::HeaderError("missing signature header"))? + .ok_or(VerificationError::NoSignature)? .to_str() .map_err(|_| VerificationError::HeaderError("invalid signature header"))?;