Implement EIP-191 integrity proofs
This commit is contained in:
parent
1ec8cb4ddd
commit
75fe4df328
4 changed files with 77 additions and 2 deletions
|
@ -1,3 +1,4 @@
|
|||
use serde_json::Value;
|
||||
use tokio_postgres::GenericClient;
|
||||
use uuid::Uuid;
|
||||
|
||||
|
@ -69,3 +70,18 @@ pub async fn prepare_update_person(
|
|||
recipients,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn prepare_signed_update_person(
|
||||
db_client: &impl GenericClient,
|
||||
instance: &Instance,
|
||||
user: &User,
|
||||
activity: Value,
|
||||
) -> Result<OutgoingActivity<Value>, DatabaseError> {
|
||||
let recipients = get_update_person_recipients(db_client, &user.id).await?;
|
||||
Ok(OutgoingActivity {
|
||||
instance: instance.clone(),
|
||||
sender: user.clone(),
|
||||
activity,
|
||||
recipients,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ use rsa::RsaPrivateKey;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::ethereum::identity::DidPkh;
|
||||
use crate::utils::crypto::sign_message;
|
||||
use super::canonicalization::{canonicalize_object, CanonicalizationError};
|
||||
|
||||
|
@ -14,6 +15,9 @@ pub const PROOF_KEY: &str = "proof";
|
|||
// - Signature algorithm: RSASSA-PKCS1-v1_5
|
||||
pub const PROOF_TYPE_JCS_RSA: &str = "JcsRsaSignature2022";
|
||||
|
||||
// Similar to EthereumPersonalSignature2021 but with JCS
|
||||
pub const PROOF_TYPE_JCS_EIP191: &str ="JcsEip191Signature2022";
|
||||
|
||||
pub const PROOF_PURPOSE: &str = "assertionMethod";
|
||||
|
||||
/// Data Integrity Proof
|
||||
|
@ -42,6 +46,19 @@ impl IntegrityProof {
|
|||
proof_value: signature.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn jcs_eip191(
|
||||
signer: &DidPkh,
|
||||
signature: &str,
|
||||
) -> Self {
|
||||
Self {
|
||||
proof_type: PROOF_TYPE_JCS_EIP191.to_string(),
|
||||
proof_purpose: PROOF_PURPOSE.to_string(),
|
||||
verification_method: signer.to_string(),
|
||||
created: Utc::now(),
|
||||
proof_value: signature.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
use rsa::RsaPublicKey;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::ethereum::{
|
||||
identity::DidPkh,
|
||||
signatures::recover_address,
|
||||
utils::address_to_string,
|
||||
};
|
||||
use crate::utils::crypto::verify_signature;
|
||||
use super::canonicalization::{canonicalize_object, CanonicalizationError};
|
||||
use super::create::{
|
||||
|
@ -78,6 +83,21 @@ pub fn verify_json_signature(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn verify_jcs_eip191_signature(
|
||||
signer: &DidPkh,
|
||||
message: &str,
|
||||
signature: &str,
|
||||
) -> Result<(), VerificationError> {
|
||||
let signature_data = signature.parse()
|
||||
.map_err(|_| VerificationError::InvalidProof("invalid proof"))?;
|
||||
let signer_address = recover_address(message.as_bytes(), &signature_data)
|
||||
.map_err(|_| VerificationError::InvalidSignature)?;
|
||||
if address_to_string(signer_address) != signer.address.to_lowercase() {
|
||||
return Err(VerificationError::InvalidSignature);
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json::json;
|
||||
|
|
|
@ -11,6 +11,7 @@ use crate::activitypub::builders::{
|
|||
update_person::{
|
||||
build_update_person,
|
||||
prepare_update_person,
|
||||
prepare_signed_update_person,
|
||||
},
|
||||
};
|
||||
use crate::config::Config;
|
||||
|
@ -25,7 +26,11 @@ use crate::ethereum::identity::{
|
|||
create_identity_claim,
|
||||
verify_identity_proof,
|
||||
};
|
||||
use crate::json_signatures::canonicalization::canonicalize_object;
|
||||
use crate::json_signatures::{
|
||||
canonicalization::canonicalize_object,
|
||||
create::{add_integrity_proof, IntegrityProof},
|
||||
verify::verify_jcs_eip191_signature,
|
||||
};
|
||||
use crate::mastodon_api::oauth::auth::get_current_user;
|
||||
use crate::mastodon_api::pagination::get_paginated_response;
|
||||
use crate::mastodon_api::search::helpers::search_profiles_only;
|
||||
|
@ -249,11 +254,28 @@ async fn send_signed_update(
|
|||
if !current_user.profile.identity_proofs.any(&signer) {
|
||||
return Err(ValidationError("unknown signer").into());
|
||||
};
|
||||
let _activity = build_update_person(
|
||||
let activity = build_update_person(
|
||||
&config.instance_url(),
|
||||
¤t_user,
|
||||
Some(data.internal_activity_id),
|
||||
).map_err(|_| HttpError::InternalError)?;
|
||||
let canonical_json = canonicalize_object(&activity)
|
||||
.map_err(|_| HttpError::InternalError)?;
|
||||
verify_jcs_eip191_signature(&signer, &canonical_json, &data.signature)
|
||||
.map_err(|_| ValidationError("invalid signature"))?;
|
||||
let proof = IntegrityProof::jcs_eip191(&signer, &data.signature);
|
||||
let mut activity_value = serde_json::to_value(activity)
|
||||
.map_err(|_| HttpError::InternalError)?;
|
||||
add_integrity_proof(&mut activity_value, proof)
|
||||
.map_err(|_| HttpError::InternalError)?;
|
||||
|
||||
prepare_signed_update_person(
|
||||
db_client,
|
||||
&config.instance(),
|
||||
¤t_user,
|
||||
activity_value,
|
||||
).await?.spawn_deliver();
|
||||
|
||||
let account = Account::from_user(current_user, &config.instance_url());
|
||||
Ok(HttpResponse::Ok().json(account))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue