Use general Did type intsead of DidPkh in identity proofs
This commit is contained in:
parent
4e53a5c4e4
commit
dae6e9437b
12 changed files with 135 additions and 64 deletions
|
@ -11,7 +11,7 @@ use crate::ethereum::identity::{
|
||||||
verify_eip191_identity_proof,
|
verify_eip191_identity_proof,
|
||||||
};
|
};
|
||||||
use crate::frontend::get_subscription_page_url;
|
use crate::frontend::get_subscription_page_url;
|
||||||
use crate::identity::did_pkh::DidPkh;
|
use crate::identity::did::Did;
|
||||||
use crate::models::profiles::types::{
|
use crate::models::profiles::types::{
|
||||||
ExtraField,
|
ExtraField,
|
||||||
IdentityProof,
|
IdentityProof,
|
||||||
|
@ -45,13 +45,14 @@ pub fn parse_identity_proof(
|
||||||
if proof_type != ETHEREUM_EIP191_PROOF {
|
if proof_type != ETHEREUM_EIP191_PROOF {
|
||||||
return Err(ValidationError("unknown proof type"));
|
return Err(ValidationError("unknown proof type"));
|
||||||
};
|
};
|
||||||
let did = attachment.name.parse::<DidPkh>()
|
let did = attachment.name.parse::<Did>()
|
||||||
.map_err(|_| ValidationError("invalid did"))?;
|
.map_err(|_| ValidationError("invalid did"))?;
|
||||||
|
let Did::Pkh(ref did_pkh) = did;
|
||||||
let signature = attachment.signature_value.as_ref()
|
let signature = attachment.signature_value.as_ref()
|
||||||
.ok_or(ValidationError("missing signature"))?;
|
.ok_or(ValidationError("missing signature"))?;
|
||||||
verify_eip191_identity_proof(
|
verify_eip191_identity_proof(
|
||||||
actor_id,
|
actor_id,
|
||||||
&did,
|
did_pkh,
|
||||||
signature,
|
signature,
|
||||||
).map_err(|_| ValidationError("invalid identity proof"))?;
|
).map_err(|_| ValidationError("invalid identity proof"))?;
|
||||||
let proof = IdentityProof {
|
let proof = IdentityProof {
|
||||||
|
|
|
@ -9,6 +9,7 @@ use crate::http_signatures::verify::{
|
||||||
verify_http_signature,
|
verify_http_signature,
|
||||||
HttpSignatureVerificationError as HttpSignatureError,
|
HttpSignatureVerificationError as HttpSignatureError,
|
||||||
};
|
};
|
||||||
|
use crate::identity::did::Did;
|
||||||
use crate::json_signatures::verify::{
|
use crate::json_signatures::verify::{
|
||||||
get_json_signature,
|
get_json_signature,
|
||||||
verify_jcs_rsa_signature,
|
verify_jcs_rsa_signature,
|
||||||
|
@ -136,8 +137,9 @@ pub async fn verify_signed_activity(
|
||||||
verify_jcs_rsa_signature(&signature_data, &public_key)?;
|
verify_jcs_rsa_signature(&signature_data, &public_key)?;
|
||||||
actor_profile
|
actor_profile
|
||||||
},
|
},
|
||||||
JsonSigner::DidPkh(ref signer) => {
|
JsonSigner::DidPkh(did_pkh) => {
|
||||||
let mut profiles: Vec<_> = search_profiles_by_did_only(db_client, signer)
|
let did = Did::Pkh(did_pkh.clone());
|
||||||
|
let mut profiles: Vec<_> = search_profiles_by_did_only(db_client, &did)
|
||||||
.await?.into_iter()
|
.await?.into_iter()
|
||||||
// Exclude local profiles
|
// Exclude local profiles
|
||||||
.filter(|profile| !profile.is_local())
|
.filter(|profile| !profile.is_local())
|
||||||
|
@ -150,7 +152,7 @@ pub async fn verify_signed_activity(
|
||||||
};
|
};
|
||||||
if let Some(profile) = profiles.pop() {
|
if let Some(profile) = profiles.pop() {
|
||||||
verify_jcs_eip191_signature(
|
verify_jcs_eip191_signature(
|
||||||
signer,
|
&did_pkh,
|
||||||
&signature_data.message,
|
&signature_data.message,
|
||||||
&signature_data.signature,
|
&signature_data.signature,
|
||||||
)?;
|
)?;
|
||||||
|
|
79
src/identity/did.rs
Normal file
79
src/identity/did.rs
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
/// https://www.w3.org/TR/did-core/
|
||||||
|
use std::fmt;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use regex::Regex;
|
||||||
|
use serde::{
|
||||||
|
Deserialize, Deserializer, Serialize, Serializer,
|
||||||
|
de::Error as DeserializerError,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::did_pkh::DidPkh;
|
||||||
|
|
||||||
|
const DID_RE: &str = r"did:(?P<method>\w+):.+";
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum Did {
|
||||||
|
Pkh(DidPkh),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
#[error("DID parse error")]
|
||||||
|
pub struct DidParseError;
|
||||||
|
|
||||||
|
impl FromStr for Did {
|
||||||
|
type Err = DidParseError;
|
||||||
|
|
||||||
|
fn from_str(value: &str) -> Result<Self, Self::Err> {
|
||||||
|
let did_re = Regex::new(DID_RE).unwrap();
|
||||||
|
let caps = did_re.captures(value).ok_or(DidParseError)?;
|
||||||
|
let did = match &caps["method"] {
|
||||||
|
"pkh" => {
|
||||||
|
let did_pkh = DidPkh::from_str(value)?;
|
||||||
|
Self::Pkh(did_pkh)
|
||||||
|
},
|
||||||
|
_ => return Err(DidParseError),
|
||||||
|
};
|
||||||
|
Ok(did)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Did {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let did_str = match self {
|
||||||
|
Self::Pkh(did_pkh) => did_pkh.to_string(),
|
||||||
|
};
|
||||||
|
write!(formatter, "{}", did_str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Did {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where D: Deserializer<'de>
|
||||||
|
{
|
||||||
|
let did_str: String = Deserialize::deserialize(deserializer)?;
|
||||||
|
did_str.parse().map_err(DeserializerError::custom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for Did {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where S: Serializer
|
||||||
|
{
|
||||||
|
let did_str = self.to_string();
|
||||||
|
serializer.serialize_str(&did_str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_did_string_conversion() {
|
||||||
|
let did_str = "did:pkh:eip155:1:0xb9c5714089478a327f09197987f16f9e5d936e8a";
|
||||||
|
let did: Did = did_str.parse().unwrap();
|
||||||
|
assert!(matches!(did, Did::Pkh(_)));
|
||||||
|
assert_eq!(did.to_string(), did_str);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,13 +3,10 @@ use std::convert::TryInto;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde::{
|
|
||||||
Deserialize, Deserializer, Serialize, Serializer,
|
|
||||||
de::Error as DeserializerError,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::utils::caip2::ChainId;
|
use crate::utils::caip2::ChainId;
|
||||||
use crate::utils::currencies::Currency;
|
use crate::utils::currencies::Currency;
|
||||||
|
use super::did::DidParseError;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct DidPkh {
|
pub struct DidPkh {
|
||||||
|
@ -43,10 +40,6 @@ impl ToString for DidPkh {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
|
||||||
#[error("DID parse error")]
|
|
||||||
pub struct DidParseError;
|
|
||||||
|
|
||||||
// https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-10.md#syntax
|
// https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-10.md#syntax
|
||||||
const DID_PKH_RE: &str = r"did:pkh:(?P<network>[-a-z0-9]{3,8}):(?P<chain>[-a-zA-Z0-9]{1,32}):(?P<address>[a-zA-Z0-9]{1,64})";
|
const DID_PKH_RE: &str = r"did:pkh:(?P<network>[-a-z0-9]{3,8}):(?P<chain>[-a-zA-Z0-9]{1,32}):(?P<address>[a-zA-Z0-9]{1,64})";
|
||||||
|
|
||||||
|
@ -67,30 +60,12 @@ impl FromStr for DidPkh {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for DidPkh {
|
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where S: Serializer
|
|
||||||
{
|
|
||||||
let did_str = self.to_string();
|
|
||||||
serializer.serialize_str(&did_str)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for DidPkh {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where D: Deserializer<'de>
|
|
||||||
{
|
|
||||||
let did_str: String = Deserialize::deserialize(deserializer)?;
|
|
||||||
did_str.parse().map_err(DeserializerError::custom)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_did_string_conversion() {
|
fn test_did_pkh_string_conversion() {
|
||||||
let address = "0xB9C5714089478a327F09197987f16f9E5d936E8a";
|
let address = "0xB9C5714089478a327F09197987f16f9E5d936E8a";
|
||||||
let ethereum = Currency::Ethereum;
|
let ethereum = Currency::Ethereum;
|
||||||
let did = DidPkh::from_address(ðereum, address);
|
let did = DidPkh::from_address(ðereum, address);
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
|
pub mod did;
|
||||||
pub mod did_pkh;
|
pub mod did_pkh;
|
||||||
|
|
|
@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::errors::ValidationError;
|
use crate::errors::ValidationError;
|
||||||
|
use crate::identity::did::Did;
|
||||||
use crate::mastodon_api::pagination::PageSize;
|
use crate::mastodon_api::pagination::PageSize;
|
||||||
use crate::mastodon_api::uploads::{UploadError, save_validated_b64_file};
|
use crate::mastodon_api::uploads::{UploadError, save_validated_b64_file};
|
||||||
use crate::models::profiles::types::{
|
use crate::models::profiles::types::{
|
||||||
|
@ -78,12 +79,13 @@ impl Account {
|
||||||
|
|
||||||
let mut identity_proofs = vec![];
|
let mut identity_proofs = vec![];
|
||||||
for proof in profile.identity_proofs.clone().into_inner() {
|
for proof in profile.identity_proofs.clone().into_inner() {
|
||||||
|
let Did::Pkh(did_pkh) = proof.issuer;
|
||||||
// Skip proof if it doesn't map to field name
|
// Skip proof if it doesn't map to field name
|
||||||
if let Some(currency) = proof.issuer.currency() {
|
if let Some(currency) = did_pkh.currency() {
|
||||||
let field_name = currency.field_name();
|
let field_name = currency.field_name();
|
||||||
let field = AccountField {
|
let field = AccountField {
|
||||||
name: field_name,
|
name: field_name,
|
||||||
value: proof.issuer.address,
|
value: did_pkh.address,
|
||||||
// Use current time because DID proofs are always valid
|
// Use current time because DID proofs are always valid
|
||||||
verified_at: Some(Utc::now()),
|
verified_at: Some(Utc::now()),
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,7 +25,7 @@ use crate::ethereum::identity::{
|
||||||
create_identity_claim,
|
create_identity_claim,
|
||||||
verify_eip191_identity_proof,
|
verify_eip191_identity_proof,
|
||||||
};
|
};
|
||||||
use crate::identity::did_pkh::DidPkh;
|
use crate::identity::did::Did;
|
||||||
use crate::json_signatures::{
|
use crate::json_signatures::{
|
||||||
canonicalization::canonicalize_object,
|
canonicalization::canonicalize_object,
|
||||||
create::{add_integrity_proof, IntegrityProof},
|
create::{add_integrity_proof, IntegrityProof},
|
||||||
|
@ -249,7 +249,7 @@ async fn send_signed_update(
|
||||||
) -> Result<HttpResponse, HttpError> {
|
) -> Result<HttpResponse, HttpError> {
|
||||||
let db_client = &mut **get_database_client(&db_pool).await?;
|
let db_client = &mut **get_database_client(&db_pool).await?;
|
||||||
let current_user = get_current_user(db_client, auth.token()).await?;
|
let current_user = get_current_user(db_client, auth.token()).await?;
|
||||||
let signer = data.signer.parse::<DidPkh>()
|
let signer = data.signer.parse::<Did>()
|
||||||
.map_err(|_| ValidationError("invalid DID"))?;
|
.map_err(|_| ValidationError("invalid DID"))?;
|
||||||
if !current_user.profile.identity_proofs.any(&signer) {
|
if !current_user.profile.identity_proofs.any(&signer) {
|
||||||
return Err(ValidationError("unknown signer").into());
|
return Err(ValidationError("unknown signer").into());
|
||||||
|
@ -261,6 +261,7 @@ async fn send_signed_update(
|
||||||
).map_err(|_| HttpError::InternalError)?;
|
).map_err(|_| HttpError::InternalError)?;
|
||||||
let canonical_json = canonicalize_object(&activity)
|
let canonical_json = canonicalize_object(&activity)
|
||||||
.map_err(|_| HttpError::InternalError)?;
|
.map_err(|_| HttpError::InternalError)?;
|
||||||
|
let Did::Pkh(signer) = signer;
|
||||||
verify_jcs_eip191_signature(&signer, &canonical_json, &data.signature)
|
verify_jcs_eip191_signature(&signer, &canonical_json, &data.signature)
|
||||||
.map_err(|_| ValidationError("invalid signature"))?;
|
.map_err(|_| ValidationError("invalid signature"))?;
|
||||||
let proof = IntegrityProof::jcs_eip191(&signer, &data.signature);
|
let proof = IntegrityProof::jcs_eip191(&signer, &data.signature);
|
||||||
|
@ -290,7 +291,7 @@ async fn get_identity_claim(
|
||||||
let db_client = &**get_database_client(&db_pool).await?;
|
let db_client = &**get_database_client(&db_pool).await?;
|
||||||
let current_user = get_current_user(db_client, auth.token()).await?;
|
let current_user = get_current_user(db_client, auth.token()).await?;
|
||||||
let actor_id = current_user.profile.actor_id(&config.instance_url());
|
let actor_id = current_user.profile.actor_id(&config.instance_url());
|
||||||
let did = query_params.did.parse::<DidPkh>()
|
let Did::Pkh(did) = query_params.did.parse::<Did>()
|
||||||
.map_err(|_| ValidationError("invalid DID"))?;
|
.map_err(|_| ValidationError("invalid DID"))?;
|
||||||
let claim = create_identity_claim(&actor_id, &did)
|
let claim = create_identity_claim(&actor_id, &did)
|
||||||
.map_err(|_| HttpError::InternalError)?;
|
.map_err(|_| HttpError::InternalError)?;
|
||||||
|
@ -308,9 +309,10 @@ async fn create_identity_proof(
|
||||||
let db_client = &**get_database_client(&db_pool).await?;
|
let db_client = &**get_database_client(&db_pool).await?;
|
||||||
let mut current_user = get_current_user(db_client, auth.token()).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 actor_id = current_user.profile.actor_id(&config.instance_url());
|
||||||
let did = proof_data.did.parse::<DidPkh>()
|
let did = proof_data.did.parse::<Did>()
|
||||||
.map_err(|_| ValidationError("invalid DID"))?;
|
.map_err(|_| ValidationError("invalid DID"))?;
|
||||||
if did.chain_id != ChainId::ethereum_mainnet() {
|
let Did::Pkh(ref did_pkh) = did;
|
||||||
|
if did_pkh.chain_id != ChainId::ethereum_mainnet() {
|
||||||
// DID must point to Ethereum Mainnet because it is a valid
|
// DID must point to Ethereum Mainnet because it is a valid
|
||||||
// identifier on any Ethereum chain
|
// identifier on any Ethereum chain
|
||||||
return Err(ValidationError("unsupported chain ID").into());
|
return Err(ValidationError("unsupported chain ID").into());
|
||||||
|
@ -319,7 +321,7 @@ async fn create_identity_proof(
|
||||||
current_user.public_wallet_address(&Currency::Ethereum);
|
current_user.public_wallet_address(&Currency::Ethereum);
|
||||||
if let Some(address) = maybe_public_address {
|
if let Some(address) = maybe_public_address {
|
||||||
// Do not allow to add more than one address proof
|
// Do not allow to add more than one address proof
|
||||||
if did.address != address {
|
if did_pkh.address != address {
|
||||||
return Err(ValidationError("DID doesn't match current identity").into());
|
return Err(ValidationError("DID doesn't match current identity").into());
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -336,7 +338,7 @@ async fn create_identity_proof(
|
||||||
};
|
};
|
||||||
verify_eip191_identity_proof(
|
verify_eip191_identity_proof(
|
||||||
&actor_id,
|
&actor_id,
|
||||||
&did,
|
did_pkh,
|
||||||
&proof_data.signature,
|
&proof_data.signature,
|
||||||
)?;
|
)?;
|
||||||
let proof = IdentityProof {
|
let proof = IdentityProof {
|
||||||
|
@ -399,7 +401,7 @@ async fn search_by_did(
|
||||||
query_params: web::Query<SearchDidQueryParams>,
|
query_params: web::Query<SearchDidQueryParams>,
|
||||||
) -> Result<HttpResponse, HttpError> {
|
) -> Result<HttpResponse, HttpError> {
|
||||||
let db_client = &**get_database_client(&db_pool).await?;
|
let db_client = &**get_database_client(&db_pool).await?;
|
||||||
let did: DidPkh = query_params.did.parse()
|
let did: Did = query_params.did.parse()
|
||||||
.map_err(|_| ValidationError("invalid DID"))?;
|
.map_err(|_| ValidationError("invalid DID"))?;
|
||||||
let profiles = search_profiles_by_did(db_client, &did, false).await?;
|
let profiles = search_profiles_by_did(db_client, &did, false).await?;
|
||||||
let accounts: Vec<Account> = profiles.into_iter()
|
let accounts: Vec<Account> = profiles.into_iter()
|
||||||
|
|
|
@ -11,7 +11,7 @@ use crate::activitypub::fetcher::helpers::{
|
||||||
};
|
};
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::errors::{ValidationError, HttpError};
|
use crate::errors::{ValidationError, HttpError};
|
||||||
use crate::identity::did_pkh::DidPkh;
|
use crate::identity::did::Did;
|
||||||
use crate::mastodon_api::accounts::types::Account;
|
use crate::mastodon_api::accounts::types::Account;
|
||||||
use crate::mastodon_api::statuses::helpers::build_status_list;
|
use crate::mastodon_api::statuses::helpers::build_status_list;
|
||||||
use crate::mastodon_api::statuses::types::Tag;
|
use crate::mastodon_api::statuses::types::Tag;
|
||||||
|
@ -33,7 +33,7 @@ enum SearchQuery {
|
||||||
TagQuery(String),
|
TagQuery(String),
|
||||||
Url(String),
|
Url(String),
|
||||||
WalletAddress(String),
|
WalletAddress(String),
|
||||||
Did(DidPkh),
|
Did(Did),
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ fn parse_tag_query(query: &str) -> Result<String, ValidationError> {
|
||||||
fn parse_search_query(search_query: &str) -> SearchQuery {
|
fn parse_search_query(search_query: &str) -> SearchQuery {
|
||||||
let search_query = search_query.trim();
|
let search_query = search_query.trim();
|
||||||
// DID is a valid URI so it should be tried before Url::parse
|
// DID is a valid URI so it should be tried before Url::parse
|
||||||
if let Ok(did) = DidPkh::from_str(search_query) {
|
if let Ok(did) = Did::from_str(search_query) {
|
||||||
return SearchQuery::Did(did);
|
return SearchQuery::Did(did);
|
||||||
};
|
};
|
||||||
if Url::parse(search_query).is_ok() {
|
if Url::parse(search_query).is_ok() {
|
||||||
|
|
|
@ -4,7 +4,7 @@ use uuid::Uuid;
|
||||||
use crate::database::catch_unique_violation;
|
use crate::database::catch_unique_violation;
|
||||||
use crate::database::query_macro::query;
|
use crate::database::query_macro::query;
|
||||||
use crate::errors::DatabaseError;
|
use crate::errors::DatabaseError;
|
||||||
use crate::identity::did_pkh::DidPkh;
|
use crate::identity::{did::Did, did_pkh::DidPkh};
|
||||||
use crate::models::cleanup::{
|
use crate::models::cleanup::{
|
||||||
find_orphaned_files,
|
find_orphaned_files,
|
||||||
find_orphaned_ipfs_objects,
|
find_orphaned_ipfs_objects,
|
||||||
|
@ -402,7 +402,7 @@ pub async fn search_profiles(
|
||||||
|
|
||||||
pub async fn search_profiles_by_did_only(
|
pub async fn search_profiles_by_did_only(
|
||||||
db_client: &impl GenericClient,
|
db_client: &impl GenericClient,
|
||||||
did: &DidPkh,
|
did: &Did,
|
||||||
) -> Result<Vec<DbActorProfile>, DatabaseError> {
|
) -> Result<Vec<DbActorProfile>, DatabaseError> {
|
||||||
let rows = db_client.query(
|
let rows = db_client.query(
|
||||||
"
|
"
|
||||||
|
@ -425,12 +425,17 @@ pub async fn search_profiles_by_did_only(
|
||||||
|
|
||||||
pub async fn search_profiles_by_did(
|
pub async fn search_profiles_by_did(
|
||||||
db_client: &impl GenericClient,
|
db_client: &impl GenericClient,
|
||||||
did: &DidPkh,
|
did: &Did,
|
||||||
prefer_verified: bool,
|
prefer_verified: bool,
|
||||||
) -> Result<Vec<DbActorProfile>, DatabaseError> {
|
) -> Result<Vec<DbActorProfile>, DatabaseError> {
|
||||||
let did_str = did.to_string();
|
|
||||||
let verified = search_profiles_by_did_only(db_client, did).await?;
|
let verified = search_profiles_by_did_only(db_client, did).await?;
|
||||||
let unverified = if let Some(currency) = did.currency() {
|
let maybe_currency_address = match did {
|
||||||
|
Did::Pkh(did_pkh) => {
|
||||||
|
did_pkh.currency()
|
||||||
|
.map(|currency| (currency, did_pkh.address.clone()))
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let unverified = if let Some((currency, address)) = maybe_currency_address {
|
||||||
// If currency is Ethereum,
|
// If currency is Ethereum,
|
||||||
// search over extra fields must be case insensitive.
|
// search over extra fields must be case insensitive.
|
||||||
let value_op = match currency {
|
let value_op = match currency {
|
||||||
|
@ -457,9 +462,8 @@ pub async fn search_profiles_by_did(
|
||||||
let field_name = currency.field_name();
|
let field_name = currency.field_name();
|
||||||
let query = query!(
|
let query = query!(
|
||||||
&statement,
|
&statement,
|
||||||
did=did_str,
|
|
||||||
field_name=field_name,
|
field_name=field_name,
|
||||||
field_value=did.address,
|
field_value=address,
|
||||||
)?;
|
)?;
|
||||||
let rows = db_client.query(query.sql(), query.parameters()).await?;
|
let rows = db_client.query(query.sql(), query.parameters()).await?;
|
||||||
let unverified = rows.iter()
|
let unverified = rows.iter()
|
||||||
|
@ -487,7 +491,8 @@ pub async fn search_profiles_by_wallet_address(
|
||||||
wallet_address: &str,
|
wallet_address: &str,
|
||||||
prefer_verified: bool,
|
prefer_verified: bool,
|
||||||
) -> Result<Vec<DbActorProfile>, DatabaseError> {
|
) -> Result<Vec<DbActorProfile>, DatabaseError> {
|
||||||
let did = DidPkh::from_address(currency, wallet_address);
|
let did_pkh = DidPkh::from_address(currency, wallet_address);
|
||||||
|
let did = Did::Pkh(did_pkh);
|
||||||
search_profiles_by_did(db_client, &did, prefer_verified).await
|
search_profiles_by_did(db_client, &did, prefer_verified).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -723,7 +728,7 @@ mod tests {
|
||||||
async fn test_search_profiles_by_wallet_address_identity_proof() {
|
async fn test_search_profiles_by_wallet_address_identity_proof() {
|
||||||
let db_client = &mut create_test_database().await;
|
let db_client = &mut create_test_database().await;
|
||||||
let identity_proof = IdentityProof {
|
let identity_proof = IdentityProof {
|
||||||
issuer: DidPkh::from_address(ÐEREUM, "0x1234abcd"),
|
issuer: Did::Pkh(DidPkh::from_address(ÐEREUM, "0x1234abcd")),
|
||||||
proof_type: "ethereum".to_string(),
|
proof_type: "ethereum".to_string(),
|
||||||
value: "13590013185bdea963".to_string(),
|
value: "13590013185bdea963".to_string(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,7 +14,7 @@ use crate::activitypub::actors::types::{Actor, ActorAddress};
|
||||||
use crate::activitypub::identifiers::local_actor_id;
|
use crate::activitypub::identifiers::local_actor_id;
|
||||||
use crate::database::json_macro::{json_from_sql, json_to_sql};
|
use crate::database::json_macro::{json_from_sql, json_to_sql};
|
||||||
use crate::errors::{ConversionError, ValidationError};
|
use crate::errors::{ConversionError, ValidationError};
|
||||||
use crate::identity::did_pkh::DidPkh;
|
use crate::identity::did::Did;
|
||||||
use crate::utils::caip2::ChainId;
|
use crate::utils::caip2::ChainId;
|
||||||
use super::validators::{
|
use super::validators::{
|
||||||
validate_username,
|
validate_username,
|
||||||
|
@ -25,7 +25,7 @@ use super::validators::{
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct IdentityProof {
|
pub struct IdentityProof {
|
||||||
pub issuer: DidPkh,
|
pub issuer: Did,
|
||||||
pub proof_type: String,
|
pub proof_type: String,
|
||||||
pub value: String,
|
pub value: String,
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ impl IdentityProofs {
|
||||||
|
|
||||||
/// Returns true if identity proof list contains at least one proof
|
/// Returns true if identity proof list contains at least one proof
|
||||||
/// created by a given DID.
|
/// created by a given DID.
|
||||||
pub fn any(&self, issuer: &DidPkh) -> bool {
|
pub fn any(&self, issuer: &Did) -> bool {
|
||||||
let Self(identity_proofs) = self;
|
let Self(identity_proofs) = self;
|
||||||
identity_proofs.iter().any(|proof| proof.issuer == *issuer)
|
identity_proofs.iter().any(|proof| proof.issuer == *issuer)
|
||||||
}
|
}
|
||||||
|
@ -430,7 +430,8 @@ mod tests {
|
||||||
fn test_identity_proof_serialization() {
|
fn test_identity_proof_serialization() {
|
||||||
let json_data = r#"{"issuer":"did:pkh:eip155:1:0xb9c5714089478a327f09197987f16f9e5d936e8a","proof_type":"ethereum-eip191-00","value":"dbfe"}"#;
|
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 proof: IdentityProof = serde_json::from_str(json_data).unwrap();
|
||||||
assert_eq!(proof.issuer.address, "0xb9c5714089478a327f09197987f16f9e5d936e8a");
|
let Did::Pkh(ref did_pkh) = proof.issuer;
|
||||||
|
assert_eq!(did_pkh.address, "0xb9c5714089478a327f09197987f16f9e5d936e8a");
|
||||||
let serialized = serde_json::to_string(&proof).unwrap();
|
let serialized = serde_json::to_string(&proof).unwrap();
|
||||||
assert_eq!(serialized, json_data);
|
assert_eq!(serialized, json_data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use uuid::Uuid;
|
||||||
|
|
||||||
use crate::database::catch_unique_violation;
|
use crate::database::catch_unique_violation;
|
||||||
use crate::errors::DatabaseError;
|
use crate::errors::DatabaseError;
|
||||||
use crate::identity::did_pkh::DidPkh;
|
use crate::identity::{did::Did, did_pkh::DidPkh};
|
||||||
use crate::models::profiles::queries::create_profile;
|
use crate::models::profiles::queries::create_profile;
|
||||||
use crate::models::profiles::types::{DbActorProfile, ProfileCreateData};
|
use crate::models::profiles::types::{DbActorProfile, ProfileCreateData};
|
||||||
use crate::utils::currencies::Currency;
|
use crate::utils::currencies::Currency;
|
||||||
|
@ -184,7 +184,7 @@ pub async fn get_user_by_login_address(
|
||||||
|
|
||||||
pub async fn get_user_by_did(
|
pub async fn get_user_by_did(
|
||||||
db_client: &impl GenericClient,
|
db_client: &impl GenericClient,
|
||||||
did: &DidPkh,
|
did: &Did,
|
||||||
) -> Result<User, DatabaseError> {
|
) -> Result<User, DatabaseError> {
|
||||||
// DIDs must be locally unique
|
// DIDs must be locally unique
|
||||||
let maybe_row = db_client.query_opt(
|
let maybe_row = db_client.query_opt(
|
||||||
|
@ -212,7 +212,8 @@ pub async fn get_user_by_public_wallet_address(
|
||||||
currency: &Currency,
|
currency: &Currency,
|
||||||
wallet_address: &str,
|
wallet_address: &str,
|
||||||
) -> Result<User, DatabaseError> {
|
) -> Result<User, DatabaseError> {
|
||||||
let did = DidPkh::from_address(currency, wallet_address);
|
let did_pkh = DidPkh::from_address(currency, wallet_address);
|
||||||
|
let did = Did::Pkh(did_pkh);
|
||||||
get_user_by_did(db_client, &did).await
|
get_user_by_did(db_client, &did).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ use regex::Regex;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::errors::ValidationError;
|
use crate::errors::ValidationError;
|
||||||
|
use crate::identity::did::Did;
|
||||||
use crate::models::profiles::types::DbActorProfile;
|
use crate::models::profiles::types::DbActorProfile;
|
||||||
use crate::utils::currencies::Currency;
|
use crate::utils::currencies::Currency;
|
||||||
|
|
||||||
|
@ -48,11 +49,12 @@ impl User {
|
||||||
/// Returns wallet address if it is verified
|
/// Returns wallet address if it is verified
|
||||||
pub fn public_wallet_address(&self, currency: &Currency) -> Option<String> {
|
pub fn public_wallet_address(&self, currency: &Currency) -> Option<String> {
|
||||||
for proof in self.profile.identity_proofs.clone().into_inner() {
|
for proof in self.profile.identity_proofs.clone().into_inner() {
|
||||||
|
let Did::Pkh(did_pkh) = proof.issuer;
|
||||||
// Return the first matching address, because only
|
// Return the first matching address, because only
|
||||||
// one proof per currency is allowed.
|
// one proof per currency is allowed.
|
||||||
if let Some(ref address_currency) = proof.issuer.currency() {
|
if let Some(ref address_currency) = did_pkh.currency() {
|
||||||
if address_currency == currency {
|
if address_currency == currency {
|
||||||
return Some(proof.issuer.address);
|
return Some(did_pkh.address);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue