Add DidKey type

This commit is contained in:
silverpill 2022-11-09 01:51:44 +00:00
parent dae6e9437b
commit a5c9da78ef
10 changed files with 90 additions and 12 deletions

View file

@ -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(

View file

@ -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
View 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);
}
}

View file

@ -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)
}
}

View file

@ -1,2 +1,3 @@
pub mod did;
pub mod did_key;
pub mod did_pkh;

View file

@ -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();

View file

@ -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

View file

@ -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,

View file

@ -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);

View file

@ -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() {