Move create_identity_claim to identity::claims module
Make it work with any DID type
This commit is contained in:
parent
a5c9da78ef
commit
1bfb951df8
5 changed files with 53 additions and 50 deletions
|
@ -11,7 +11,10 @@ use crate::ethereum::identity::{
|
|||
verify_eip191_identity_proof,
|
||||
};
|
||||
use crate::frontend::get_subscription_page_url;
|
||||
use crate::identity::did::Did;
|
||||
use crate::identity::{
|
||||
claims::create_identity_claim,
|
||||
did::Did,
|
||||
};
|
||||
use crate::models::profiles::types::{
|
||||
ExtraField,
|
||||
IdentityProof,
|
||||
|
@ -47,6 +50,8 @@ pub fn parse_identity_proof(
|
|||
};
|
||||
let did = attachment.name.parse::<Did>()
|
||||
.map_err(|_| ValidationError("invalid did"))?;
|
||||
let message = create_identity_claim(actor_id, &did)
|
||||
.map_err(|_| ValidationError("invalid claim"))?;
|
||||
let did_pkh = match did {
|
||||
Did::Pkh(ref did_pkh) => did_pkh,
|
||||
_ => return Err(ValidationError("invalid proof issuer")),
|
||||
|
@ -54,8 +59,8 @@ pub fn parse_identity_proof(
|
|||
let signature = attachment.signature_value.as_ref()
|
||||
.ok_or(ValidationError("missing signature"))?;
|
||||
verify_eip191_identity_proof(
|
||||
actor_id,
|
||||
did_pkh,
|
||||
&message,
|
||||
signature,
|
||||
).map_err(|_| ValidationError("invalid identity proof"))?;
|
||||
let proof = IdentityProof {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use serde::Serialize;
|
||||
|
||||
use crate::errors::ValidationError;
|
||||
use crate::identity::did_pkh::DidPkh;
|
||||
use super::signatures::recover_address;
|
||||
|
@ -8,35 +6,12 @@ use super::utils::address_to_string;
|
|||
// Version 00
|
||||
pub const ETHEREUM_EIP191_PROOF: &str = "ethereum-eip191-00";
|
||||
|
||||
// https://www.w3.org/TR/vc-data-model/#credential-subject
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct Claim {
|
||||
id: String, // actor ID
|
||||
owner_of: String, // DID
|
||||
}
|
||||
|
||||
/// Creates address ownership claim and prepares it for signing
|
||||
pub fn create_identity_claim(
|
||||
actor_id: &str,
|
||||
did: &DidPkh,
|
||||
) -> Result<String, serde_json::Error> {
|
||||
let claim = Claim {
|
||||
id: actor_id.to_string(),
|
||||
owner_of: did.to_string(),
|
||||
};
|
||||
let message = serde_json::to_string(&claim)?;
|
||||
Ok(message)
|
||||
}
|
||||
|
||||
/// Verifies proof of address ownership
|
||||
pub fn verify_eip191_identity_proof(
|
||||
actor_id: &str,
|
||||
did: &DidPkh,
|
||||
message: &str,
|
||||
signature: &str,
|
||||
) -> Result<(), ValidationError> {
|
||||
let message = create_identity_claim(actor_id, did)
|
||||
.map_err(|_| ValidationError("invalid claim"))?;
|
||||
let signature_data = signature.parse()
|
||||
.map_err(|_| ValidationError("invalid signature string"))?;
|
||||
let signer = recover_address(message.as_bytes(), &signature_data)
|
||||
|
@ -62,16 +37,15 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_verify_eip191_identity_proof() {
|
||||
let actor_id = "https://example.com/users/test";
|
||||
let message = "test";
|
||||
let secret_key = generate_ecdsa_key();
|
||||
let secret_key_ref = SecretKeyRef::new(&secret_key);
|
||||
let secret_key_str = secret_key.display_secret().to_string();
|
||||
let address = address_to_string(secret_key_ref.address());
|
||||
let did = DidPkh::from_address(ÐEREUM, &address);
|
||||
let message = create_identity_claim(actor_id, &did).unwrap();
|
||||
let signature = sign_message(&secret_key_str, message.as_bytes())
|
||||
.unwrap().to_string();
|
||||
let result = verify_eip191_identity_proof(actor_id, &did, &signature);
|
||||
let result = verify_eip191_identity_proof(&did, message, &signature);
|
||||
assert_eq!(result.is_ok(), true);
|
||||
}
|
||||
}
|
||||
|
|
23
src/identity/claims.rs
Normal file
23
src/identity/claims.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use serde::Serialize;
|
||||
use super::did::Did;
|
||||
|
||||
// https://www.w3.org/TR/vc-data-model/#credential-subject
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct Claim {
|
||||
id: String, // actor ID
|
||||
owner_of: String, // DID
|
||||
}
|
||||
|
||||
/// Creates key ownership claim and prepares it for signing
|
||||
pub fn create_identity_claim(
|
||||
actor_id: &str,
|
||||
did: &Did,
|
||||
) -> Result<String, serde_json::Error> {
|
||||
let claim = Claim {
|
||||
id: actor_id.to_string(),
|
||||
owner_of: did.to_string(),
|
||||
};
|
||||
let message = serde_json::to_string(&claim)?;
|
||||
Ok(message)
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
pub mod claims;
|
||||
pub mod did;
|
||||
pub mod did_key;
|
||||
pub mod did_pkh;
|
||||
|
|
|
@ -22,10 +22,9 @@ use crate::ethereum::eip4361::verify_eip4361_signature;
|
|||
use crate::ethereum::gate::is_allowed_user;
|
||||
use crate::ethereum::identity::{
|
||||
ETHEREUM_EIP191_PROOF,
|
||||
create_identity_claim,
|
||||
verify_eip191_identity_proof,
|
||||
};
|
||||
use crate::identity::did::Did;
|
||||
use crate::identity::{claims::create_identity_claim, did::Did};
|
||||
use crate::json_signatures::{
|
||||
canonicalization::canonicalize_object,
|
||||
create::{add_integrity_proof, IntegrityProof},
|
||||
|
@ -297,10 +296,6 @@ async fn get_identity_claim(
|
|||
let actor_id = current_user.profile.actor_id(&config.instance_url());
|
||||
let did = query_params.did.parse::<Did>()
|
||||
.map_err(|_| ValidationError("invalid DID"))?;
|
||||
let did = match did {
|
||||
Did::Key(_) => return Err(ValidationError("unsupported DID type").into()),
|
||||
Did::Pkh(did_pkh) => did_pkh,
|
||||
};
|
||||
let claim = create_identity_claim(&actor_id, &did)
|
||||
.map_err(|_| HttpError::InternalError)?;
|
||||
let response = IdentityClaim { claim };
|
||||
|
@ -316,9 +311,24 @@ async fn create_identity_proof(
|
|||
) -> Result<HttpResponse, HttpError> {
|
||||
let db_client = &**get_database_client(&db_pool).await?;
|
||||
let mut current_user = get_current_user(db_client, auth.token()).await?;
|
||||
let actor_id = current_user.profile.actor_id(&config.instance_url());
|
||||
let did = proof_data.did.parse::<Did>()
|
||||
.map_err(|_| ValidationError("invalid DID"))?;
|
||||
// Reject proof if there's another local user with the same DID.
|
||||
// This is needed for matching ethereum subscriptions
|
||||
match get_user_by_did(db_client, &did).await {
|
||||
Ok(user) => {
|
||||
if user.id != current_user.id {
|
||||
return Err(ValidationError("DID already associated with another user").into());
|
||||
};
|
||||
},
|
||||
Err(DatabaseError::NotFound(_)) => (),
|
||||
Err(other_error) => return Err(other_error.into()),
|
||||
};
|
||||
let actor_id = current_user.profile.actor_id(&config.instance_url());
|
||||
let message = create_identity_claim(&actor_id, &did)
|
||||
.map_err(|_| ValidationError("invalid claim"))?;
|
||||
|
||||
// Verify proof
|
||||
let did_pkh = match did {
|
||||
Did::Key(_) => return Err(ValidationError("unsupported DID type").into()),
|
||||
Did::Pkh(ref did_pkh) => did_pkh,
|
||||
|
@ -336,22 +346,12 @@ async fn create_identity_proof(
|
|||
return Err(ValidationError("DID doesn't match current identity").into());
|
||||
};
|
||||
};
|
||||
// Reject proof if there's another local user with the same DID.
|
||||
// This is needed for matching ethereum subscriptions
|
||||
match get_user_by_did(db_client, &did).await {
|
||||
Ok(user) => {
|
||||
if user.id != current_user.id {
|
||||
return Err(ValidationError("DID already associated with another user").into());
|
||||
};
|
||||
},
|
||||
Err(DatabaseError::NotFound(_)) => (),
|
||||
Err(other_error) => return Err(other_error.into()),
|
||||
};
|
||||
verify_eip191_identity_proof(
|
||||
&actor_id,
|
||||
did_pkh,
|
||||
&message,
|
||||
&proof_data.signature,
|
||||
)?;
|
||||
|
||||
let proof = IdentityProof {
|
||||
issuer: did,
|
||||
proof_type: ETHEREUM_EIP191_PROOF.to_string(),
|
||||
|
|
Loading…
Reference in a new issue