Never ignore invalid HTTP signatures
This commit is contained in:
parent
d3db42ec9e
commit
06e172d9fa
3 changed files with 31 additions and 11 deletions
|
@ -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<DbActorProfile, AuthenticationError> {
|
||||
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<DbActorProfile, AuthenticationError> {
|
||||
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) => {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<HttpSignatureData, VerificationError> {
|
||||
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"))?;
|
||||
|
||||
|
|
Loading…
Reference in a new issue