Add DidKey type
This commit is contained in:
parent
dae6e9437b
commit
a5c9da78ef
10 changed files with 90 additions and 12 deletions
|
@ -47,7 +47,10 @@ pub fn parse_identity_proof(
|
|||
};
|
||||
let did = attachment.name.parse::<Did>()
|
||||
.map_err(|_| ValidationError("invalid did"))?;
|
||||
let Did::Pkh(ref did_pkh) = did;
|
||||
let did_pkh = match did {
|
||||
Did::Pkh(ref did_pkh) => did_pkh,
|
||||
_ => return Err(ValidationError("invalid proof issuer")),
|
||||
};
|
||||
let signature = attachment.signature_value.as_ref()
|
||||
.ok_or(ValidationError("missing signature"))?;
|
||||
verify_eip191_identity_proof(
|
||||
|
|
|
@ -8,12 +8,14 @@ use serde::{
|
|||
de::Error as DeserializerError,
|
||||
};
|
||||
|
||||
use super::did_key::DidKey;
|
||||
use super::did_pkh::DidPkh;
|
||||
|
||||
const DID_RE: &str = r"did:(?P<method>\w+):.+";
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Did {
|
||||
Key(DidKey),
|
||||
Pkh(DidPkh),
|
||||
}
|
||||
|
||||
|
@ -28,6 +30,10 @@ impl FromStr for Did {
|
|||
let did_re = Regex::new(DID_RE).unwrap();
|
||||
let caps = did_re.captures(value).ok_or(DidParseError)?;
|
||||
let did = match &caps["method"] {
|
||||
"key" => {
|
||||
let did_key = DidKey::from_str(value)?;
|
||||
Self::Key(did_key)
|
||||
},
|
||||
"pkh" => {
|
||||
let did_pkh = DidPkh::from_str(value)?;
|
||||
Self::Pkh(did_pkh)
|
||||
|
@ -41,6 +47,7 @@ impl FromStr for Did {
|
|||
impl fmt::Display for Did {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let did_str = match self {
|
||||
Self::Key(did_key) => did_key.to_string(),
|
||||
Self::Pkh(did_pkh) => did_pkh.to_string(),
|
||||
};
|
||||
write!(formatter, "{}", did_str)
|
||||
|
|
46
src/identity/did_key.rs
Normal file
46
src/identity/did_key.rs
Normal file
|
@ -0,0 +1,46 @@
|
|||
/// https://w3c-ccg.github.io/did-method-key/
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
use regex::Regex;
|
||||
|
||||
use super::did::DidParseError;
|
||||
|
||||
const DID_KEY_RE: &str = r"did:key:(?P<key>z[a-km-zA-HJ-NP-Z1-9]+)";
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct DidKey {
|
||||
pub key: String,
|
||||
}
|
||||
|
||||
impl FromStr for DidKey {
|
||||
type Err = DidParseError;
|
||||
|
||||
fn from_str(value: &str) -> Result<Self, Self::Err> {
|
||||
let did_key_re = Regex::new(DID_KEY_RE).unwrap();
|
||||
let caps = did_key_re.captures(value).ok_or(DidParseError)?;
|
||||
let did_key = Self {
|
||||
key: caps["key"].to_string(),
|
||||
};
|
||||
Ok(did_key)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DidKey {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let did_str = format!("did:key:{}", self.key);
|
||||
write!(formatter, "{}", did_str)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_did_key_string_conversion() {
|
||||
let did_str = "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK";
|
||||
let did_key: DidKey = did_str.parse().unwrap();
|
||||
assert_eq!(did_key.to_string(), did_str);
|
||||
}
|
||||
}
|
|
@ -49,14 +49,14 @@ impl FromStr for DidPkh {
|
|||
fn from_str(value: &str) -> Result<Self, Self::Err> {
|
||||
let did_pkh_re = Regex::new(DID_PKH_RE).unwrap();
|
||||
let caps = did_pkh_re.captures(value).ok_or(DidParseError)?;
|
||||
let did = Self {
|
||||
let did_pkh = Self {
|
||||
chain_id: ChainId {
|
||||
namespace: caps["network"].to_string(),
|
||||
reference: caps["chain"].to_string(),
|
||||
},
|
||||
address: caps["address"].to_string(),
|
||||
};
|
||||
Ok(did)
|
||||
Ok(did_pkh)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
pub mod did;
|
||||
pub mod did_key;
|
||||
pub mod did_pkh;
|
||||
|
|
|
@ -79,7 +79,10 @@ impl Account {
|
|||
|
||||
let mut identity_proofs = vec![];
|
||||
for proof in profile.identity_proofs.clone().into_inner() {
|
||||
let Did::Pkh(did_pkh) = proof.issuer;
|
||||
let did_pkh = match proof.issuer {
|
||||
Did::Pkh(did_pkh) => did_pkh,
|
||||
_ => continue,
|
||||
};
|
||||
// Skip proof if it doesn't map to field name
|
||||
if let Some(currency) = did_pkh.currency() {
|
||||
let field_name = currency.field_name();
|
||||
|
|
|
@ -261,10 +261,14 @@ async fn send_signed_update(
|
|||
).map_err(|_| HttpError::InternalError)?;
|
||||
let canonical_json = canonicalize_object(&activity)
|
||||
.map_err(|_| HttpError::InternalError)?;
|
||||
let Did::Pkh(signer) = signer;
|
||||
verify_jcs_eip191_signature(&signer, &canonical_json, &data.signature)
|
||||
.map_err(|_| ValidationError("invalid signature"))?;
|
||||
let proof = IntegrityProof::jcs_eip191(&signer, &data.signature);
|
||||
let proof = match signer {
|
||||
Did::Key(_) => return Err(ValidationError("unsupported DID type").into()),
|
||||
Did::Pkh(signer) => {
|
||||
verify_jcs_eip191_signature(&signer, &canonical_json, &data.signature)
|
||||
.map_err(|_| ValidationError("invalid signature"))?;
|
||||
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)
|
||||
|
@ -291,8 +295,12 @@ async fn get_identity_claim(
|
|||
let db_client = &**get_database_client(&db_pool).await?;
|
||||
let current_user = get_current_user(db_client, auth.token()).await?;
|
||||
let actor_id = current_user.profile.actor_id(&config.instance_url());
|
||||
let Did::Pkh(did) = query_params.did.parse::<Did>()
|
||||
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 };
|
||||
|
@ -311,7 +319,10 @@ async fn create_identity_proof(
|
|||
let actor_id = current_user.profile.actor_id(&config.instance_url());
|
||||
let did = proof_data.did.parse::<Did>()
|
||||
.map_err(|_| ValidationError("invalid DID"))?;
|
||||
let Did::Pkh(ref did_pkh) = did;
|
||||
let did_pkh = match did {
|
||||
Did::Key(_) => return Err(ValidationError("unsupported DID type").into()),
|
||||
Did::Pkh(ref did_pkh) => did_pkh,
|
||||
};
|
||||
if did_pkh.chain_id != ChainId::ethereum_mainnet() {
|
||||
// DID must point to Ethereum Mainnet because it is a valid
|
||||
// identifier on any Ethereum chain
|
||||
|
|
|
@ -434,6 +434,7 @@ pub async fn search_profiles_by_did(
|
|||
did_pkh.currency()
|
||||
.map(|currency| (currency, did_pkh.address.clone()))
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
let unverified = if let Some((currency, address)) = maybe_currency_address {
|
||||
// If currency is Ethereum,
|
||||
|
|
|
@ -430,7 +430,10 @@ mod tests {
|
|||
fn test_identity_proof_serialization() {
|
||||
let json_data = r#"{"issuer":"did:pkh:eip155:1:0xb9c5714089478a327f09197987f16f9e5d936e8a","proof_type":"ethereum-eip191-00","value":"dbfe"}"#;
|
||||
let proof: IdentityProof = serde_json::from_str(json_data).unwrap();
|
||||
let Did::Pkh(ref did_pkh) = proof.issuer;
|
||||
let did_pkh = match proof.issuer {
|
||||
Did::Pkh(ref did_pkh) => did_pkh,
|
||||
_ => panic!("unexpected did method"),
|
||||
};
|
||||
assert_eq!(did_pkh.address, "0xb9c5714089478a327f09197987f16f9e5d936e8a");
|
||||
let serialized = serde_json::to_string(&proof).unwrap();
|
||||
assert_eq!(serialized, json_data);
|
||||
|
|
|
@ -49,7 +49,10 @@ impl User {
|
|||
/// Returns wallet address if it is verified
|
||||
pub fn public_wallet_address(&self, currency: &Currency) -> Option<String> {
|
||||
for proof in self.profile.identity_proofs.clone().into_inner() {
|
||||
let Did::Pkh(did_pkh) = proof.issuer;
|
||||
let did_pkh = match proof.issuer {
|
||||
Did::Pkh(did_pkh) => did_pkh,
|
||||
_ => continue,
|
||||
};
|
||||
// Return the first matching address, because only
|
||||
// one proof per currency is allowed.
|
||||
if let Some(ref address_currency) = did_pkh.currency() {
|
||||
|
|
Loading…
Reference in a new issue