Return error if trying to sign activity which is already signed

This commit is contained in:
silverpill 2022-11-01 00:02:25 +00:00
parent b700a8ac6d
commit 3dbb922f3c
3 changed files with 26 additions and 5 deletions

View file

@ -13,6 +13,7 @@ use crate::http_signatures::create::{
HttpSignatureError, HttpSignatureError,
}; };
use crate::json_signatures::create::{ use crate::json_signatures::create::{
is_object_signed,
sign_object, sign_object,
JsonSignatureError, JsonSignatureError,
}; };
@ -122,7 +123,14 @@ async fn deliver_activity_worker(
), ),
ACTOR_KEY_SUFFIX, ACTOR_KEY_SUFFIX,
); );
let activity_signed = sign_object(&activity, &actor_key, &actor_key_id)?; let activity_value = serde_json::to_value(&activity)?;
let activity_signed = if is_object_signed(&activity_value) {
log::warn!("activity is already signed");
activity_value
} else {
sign_object(&activity_value, &actor_key, &actor_key_id)?
};
let activity_json = serde_json::to_string(&activity_signed)?; let activity_json = serde_json::to_string(&activity_signed)?;
if recipients.is_empty() { if recipients.is_empty() {
return Ok(()); return Ok(());

View file

@ -19,6 +19,8 @@ pub struct Proof {
pub proof_value: String, pub proof_value: String,
} }
pub const PROOF_KEY: &str = "proof";
// Similar to https://identity.foundation/JcsEd25519Signature2020/ // Similar to https://identity.foundation/JcsEd25519Signature2020/
// - Canonicalization algorithm: JCS // - Canonicalization algorithm: JCS
// - Digest algorithm: SHA-256 // - Digest algorithm: SHA-256
@ -40,10 +42,13 @@ pub enum JsonSignatureError {
#[error("invalid object")] #[error("invalid object")]
InvalidObject, InvalidObject,
#[error("already signed")]
AlreadySigned,
} }
pub fn sign_object( pub fn sign_object(
object: &impl Serialize, object: &Value,
signer_key: &RsaPrivateKey, signer_key: &RsaPrivateKey,
signer_key_id: &str, signer_key_id: &str,
) -> Result<Value, JsonSignatureError> { ) -> Result<Value, JsonSignatureError> {
@ -63,10 +68,17 @@ pub fn sign_object(
let mut object_value = serde_json::to_value(object)?; let mut object_value = serde_json::to_value(object)?;
let object_map = object_value.as_object_mut() let object_map = object_value.as_object_mut()
.ok_or(JsonSignatureError::InvalidObject)?; .ok_or(JsonSignatureError::InvalidObject)?;
object_map.insert("proof".to_string(), proof_value); if object_map.contains_key(PROOF_KEY) {
return Err(JsonSignatureError::AlreadySigned);
};
object_map.insert(PROOF_KEY.to_string(), proof_value);
Ok(object_value) Ok(object_value)
} }
pub fn is_object_signed(object: &Value) -> bool {
object.get(PROOF_KEY).is_some()
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use serde_json::json; use serde_json::json;
@ -92,6 +104,7 @@ mod tests {
}); });
let result = sign_object(&object, &signer_key, signer_key_id).unwrap(); let result = sign_object(&object, &signer_key, signer_key_id).unwrap();
assert!(is_object_signed(&result));
assert_eq!(result["actor"], object["actor"]); assert_eq!(result["actor"], object["actor"]);
assert_eq!(result["object"], object["object"]); assert_eq!(result["object"], object["object"]);
let signature_date = result["proof"]["created"].as_str().unwrap(); let signature_date = result["proof"]["created"].as_str().unwrap();

View file

@ -3,7 +3,7 @@ use serde_json::Value;
use crate::utils::crypto::verify_signature; use crate::utils::crypto::verify_signature;
use super::canonicalization::{canonicalize_object, CanonicalizationError}; use super::canonicalization::{canonicalize_object, CanonicalizationError};
use super::create::{Proof, PROOF_TYPE, PROOF_PURPOSE}; use super::create::{Proof, PROOF_KEY, PROOF_TYPE, PROOF_PURPOSE};
pub struct SignatureData { pub struct SignatureData {
pub key_id: String, pub key_id: String,
@ -40,7 +40,7 @@ pub fn get_json_signature(
let mut object = object.clone(); let mut object = object.clone();
let object_map = object.as_object_mut() let object_map = object.as_object_mut()
.ok_or(VerificationError::InvalidObject)?; .ok_or(VerificationError::InvalidObject)?;
let proof_value = object_map.remove("proof") let proof_value = object_map.remove(PROOF_KEY)
.ok_or(VerificationError::NoProof)?; .ok_or(VerificationError::NoProof)?;
let proof: Proof = serde_json::from_value(proof_value) let proof: Proof = serde_json::from_value(proof_value)
.map_err(|_| VerificationError::InvalidProof("invalid proof"))?; .map_err(|_| VerificationError::InvalidProof("invalid proof"))?;