Move DidPkh type to identity module
This commit is contained in:
parent
fbfb6bb3c2
commit
4e53a5c4e4
12 changed files with 131 additions and 118 deletions
|
@ -8,10 +8,10 @@ use crate::activitypub::vocabulary::{
|
|||
use crate::errors::ValidationError;
|
||||
use crate::ethereum::identity::{
|
||||
ETHEREUM_EIP191_PROOF,
|
||||
DidPkh,
|
||||
verify_identity_proof,
|
||||
verify_eip191_identity_proof,
|
||||
};
|
||||
use crate::frontend::get_subscription_page_url;
|
||||
use crate::identity::did_pkh::DidPkh;
|
||||
use crate::models::profiles::types::{
|
||||
ExtraField,
|
||||
IdentityProof,
|
||||
|
@ -49,7 +49,7 @@ pub fn parse_identity_proof(
|
|||
.map_err(|_| ValidationError("invalid did"))?;
|
||||
let signature = attachment.signature_value.as_ref()
|
||||
.ok_or(ValidationError("missing signature"))?;
|
||||
verify_identity_proof(
|
||||
verify_eip191_identity_proof(
|
||||
actor_id,
|
||||
&did,
|
||||
signature,
|
||||
|
|
|
@ -1,96 +1,13 @@
|
|||
use std::convert::TryInto;
|
||||
use std::str::FromStr;
|
||||
|
||||
use regex::Regex;
|
||||
use serde::{
|
||||
Deserialize, Deserializer, Serialize, Serializer,
|
||||
de::Error as DeserializerError,
|
||||
};
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::errors::ValidationError;
|
||||
use crate::utils::caip2::ChainId;
|
||||
use crate::utils::currencies::Currency;
|
||||
use crate::identity::did_pkh::DidPkh;
|
||||
use super::signatures::recover_address;
|
||||
use super::utils::address_to_string;
|
||||
|
||||
// Version 00
|
||||
pub const ETHEREUM_EIP191_PROOF: &str = "ethereum-eip191-00";
|
||||
|
||||
// https://github.com/w3c-ccg/did-pkh/blob/main/did-pkh-method-draft.md
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct DidPkh {
|
||||
pub chain_id: ChainId,
|
||||
pub address: String,
|
||||
}
|
||||
|
||||
impl DidPkh {
|
||||
pub fn from_address(currency: &Currency, address: &str) -> Self {
|
||||
let chain_id = match currency {
|
||||
Currency::Ethereum => ChainId::ethereum_mainnet(),
|
||||
Currency::Monero => unimplemented!(),
|
||||
};
|
||||
let address = currency.normalize_address(address);
|
||||
Self { chain_id, address }
|
||||
}
|
||||
|
||||
pub fn currency(&self) -> Option<Currency> {
|
||||
(&self.chain_id).try_into().ok()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for DidPkh {
|
||||
fn to_string(&self) -> String {
|
||||
format!(
|
||||
"did:pkh:{}:{}:{}",
|
||||
self.chain_id.namespace,
|
||||
self.chain_id.reference,
|
||||
self.address,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
#[error("DID parse error")]
|
||||
pub struct DidParseError;
|
||||
|
||||
// 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})";
|
||||
|
||||
impl FromStr for DidPkh {
|
||||
type Err = DidParseError;
|
||||
|
||||
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 {
|
||||
chain_id: ChainId {
|
||||
namespace: caps["network"].to_string(),
|
||||
reference: caps["chain"].to_string(),
|
||||
},
|
||||
address: caps["address"].to_string(),
|
||||
};
|
||||
Ok(did)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/vc-data-model/#credential-subject
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
@ -113,7 +30,7 @@ pub fn create_identity_claim(
|
|||
}
|
||||
|
||||
/// Verifies proof of address ownership
|
||||
pub fn verify_identity_proof(
|
||||
pub fn verify_eip191_identity_proof(
|
||||
actor_id: &str,
|
||||
did: &DidPkh,
|
||||
signature: &str,
|
||||
|
@ -138,29 +55,13 @@ mod tests {
|
|||
sign_message,
|
||||
};
|
||||
use crate::ethereum::utils::address_to_string;
|
||||
use crate::utils::currencies::Currency;
|
||||
use super::*;
|
||||
|
||||
const ETHEREUM: Currency = Currency::Ethereum;
|
||||
|
||||
#[test]
|
||||
fn test_did_string_conversion() {
|
||||
let address = "0xB9C5714089478a327F09197987f16f9E5d936E8a";
|
||||
let did = DidPkh::from_address(ÐEREUM, address);
|
||||
assert_eq!(did.currency().unwrap(), ETHEREUM);
|
||||
assert_eq!(did.address, address.to_lowercase());
|
||||
|
||||
let did_str = did.to_string();
|
||||
assert_eq!(
|
||||
did_str,
|
||||
"did:pkh:eip155:1:0xb9c5714089478a327f09197987f16f9e5d936e8a",
|
||||
);
|
||||
|
||||
let did: DidPkh = did_str.parse().unwrap();
|
||||
assert_eq!(did.address, address.to_lowercase());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_verify_identity_proof() {
|
||||
fn test_verify_eip191_identity_proof() {
|
||||
let actor_id = "https://example.com/users/test";
|
||||
let secret_key = generate_ecdsa_key();
|
||||
let secret_key_ref = SecretKeyRef::new(&secret_key);
|
||||
|
@ -168,8 +69,9 @@ mod tests {
|
|||
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_identity_proof(actor_id, &did, &signature);
|
||||
let signature = sign_message(&secret_key_str, message.as_bytes())
|
||||
.unwrap().to_string();
|
||||
let result = verify_eip191_identity_proof(actor_id, &did, &signature);
|
||||
assert_eq!(result.is_ok(), true);
|
||||
}
|
||||
}
|
||||
|
|
109
src/identity/did_pkh.rs
Normal file
109
src/identity/did_pkh.rs
Normal file
|
@ -0,0 +1,109 @@
|
|||
/// https://github.com/w3c-ccg/did-pkh/blob/main/did-pkh-method-draft.md
|
||||
use std::convert::TryInto;
|
||||
use std::str::FromStr;
|
||||
|
||||
use regex::Regex;
|
||||
use serde::{
|
||||
Deserialize, Deserializer, Serialize, Serializer,
|
||||
de::Error as DeserializerError,
|
||||
};
|
||||
|
||||
use crate::utils::caip2::ChainId;
|
||||
use crate::utils::currencies::Currency;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct DidPkh {
|
||||
pub chain_id: ChainId,
|
||||
pub address: String,
|
||||
}
|
||||
|
||||
impl DidPkh {
|
||||
pub fn from_address(currency: &Currency, address: &str) -> Self {
|
||||
let chain_id = match currency {
|
||||
Currency::Ethereum => ChainId::ethereum_mainnet(),
|
||||
Currency::Monero => unimplemented!(),
|
||||
};
|
||||
let address = currency.normalize_address(address);
|
||||
Self { chain_id, address }
|
||||
}
|
||||
|
||||
pub fn currency(&self) -> Option<Currency> {
|
||||
(&self.chain_id).try_into().ok()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for DidPkh {
|
||||
fn to_string(&self) -> String {
|
||||
format!(
|
||||
"did:pkh:{}:{}:{}",
|
||||
self.chain_id.namespace,
|
||||
self.chain_id.reference,
|
||||
self.address,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
#[error("DID parse error")]
|
||||
pub struct DidParseError;
|
||||
|
||||
// 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})";
|
||||
|
||||
impl FromStr for DidPkh {
|
||||
type Err = DidParseError;
|
||||
|
||||
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 {
|
||||
chain_id: ChainId {
|
||||
namespace: caps["network"].to_string(),
|
||||
reference: caps["chain"].to_string(),
|
||||
},
|
||||
address: caps["address"].to_string(),
|
||||
};
|
||||
Ok(did)
|
||||
}
|
||||
}
|
||||
|
||||
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)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_did_string_conversion() {
|
||||
let address = "0xB9C5714089478a327F09197987f16f9E5d936E8a";
|
||||
let ethereum = Currency::Ethereum;
|
||||
let did = DidPkh::from_address(ðereum, address);
|
||||
assert_eq!(did.currency().unwrap(), ethereum);
|
||||
assert_eq!(did.address, address.to_lowercase());
|
||||
|
||||
let did_str = did.to_string();
|
||||
assert_eq!(
|
||||
did_str,
|
||||
"did:pkh:eip155:1:0xb9c5714089478a327f09197987f16f9e5d936e8a",
|
||||
);
|
||||
|
||||
let did: DidPkh = did_str.parse().unwrap();
|
||||
assert_eq!(did.address, address.to_lowercase());
|
||||
}
|
||||
}
|
1
src/identity/mod.rs
Normal file
1
src/identity/mod.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod did_pkh;
|
|
@ -3,7 +3,7 @@ use rsa::RsaPrivateKey;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::ethereum::identity::DidPkh;
|
||||
use crate::identity::did_pkh::DidPkh;
|
||||
use crate::utils::crypto::sign_message;
|
||||
use super::canonicalization::{canonicalize_object, CanonicalizationError};
|
||||
|
||||
|
|
|
@ -2,10 +2,10 @@ use rsa::RsaPublicKey;
|
|||
use serde_json::Value;
|
||||
|
||||
use crate::ethereum::{
|
||||
identity::DidPkh,
|
||||
signatures::recover_address,
|
||||
utils::address_to_string,
|
||||
};
|
||||
use crate::identity::did_pkh::DidPkh;
|
||||
use crate::utils::crypto::verify_signature;
|
||||
use super::canonicalization::{canonicalize_object, CanonicalizationError};
|
||||
use super::create::{
|
||||
|
|
|
@ -8,6 +8,7 @@ pub mod ethereum;
|
|||
mod frontend;
|
||||
pub mod http;
|
||||
mod http_signatures;
|
||||
mod identity;
|
||||
mod ipfs;
|
||||
mod json_signatures;
|
||||
pub mod logger;
|
||||
|
|
|
@ -22,10 +22,10 @@ use crate::ethereum::eip4361::verify_eip4361_signature;
|
|||
use crate::ethereum::gate::is_allowed_user;
|
||||
use crate::ethereum::identity::{
|
||||
ETHEREUM_EIP191_PROOF,
|
||||
DidPkh,
|
||||
create_identity_claim,
|
||||
verify_identity_proof,
|
||||
verify_eip191_identity_proof,
|
||||
};
|
||||
use crate::identity::did_pkh::DidPkh;
|
||||
use crate::json_signatures::{
|
||||
canonicalization::canonicalize_object,
|
||||
create::{add_integrity_proof, IntegrityProof},
|
||||
|
@ -334,7 +334,7 @@ async fn create_identity_proof(
|
|||
Err(DatabaseError::NotFound(_)) => (),
|
||||
Err(other_error) => return Err(other_error.into()),
|
||||
};
|
||||
verify_identity_proof(
|
||||
verify_eip191_identity_proof(
|
||||
&actor_id,
|
||||
&did,
|
||||
&proof_data.signature,
|
||||
|
|
|
@ -11,7 +11,7 @@ use crate::activitypub::fetcher::helpers::{
|
|||
};
|
||||
use crate::config::Config;
|
||||
use crate::errors::{ValidationError, HttpError};
|
||||
use crate::ethereum::identity::DidPkh;
|
||||
use crate::identity::did_pkh::DidPkh;
|
||||
use crate::mastodon_api::accounts::types::Account;
|
||||
use crate::mastodon_api::statuses::helpers::build_status_list;
|
||||
use crate::mastodon_api::statuses::types::Tag;
|
||||
|
|
|
@ -4,7 +4,7 @@ use uuid::Uuid;
|
|||
use crate::database::catch_unique_violation;
|
||||
use crate::database::query_macro::query;
|
||||
use crate::errors::DatabaseError;
|
||||
use crate::ethereum::identity::DidPkh;
|
||||
use crate::identity::did_pkh::DidPkh;
|
||||
use crate::models::cleanup::{
|
||||
find_orphaned_files,
|
||||
find_orphaned_ipfs_objects,
|
||||
|
|
|
@ -14,7 +14,7 @@ use crate::activitypub::actors::types::{Actor, ActorAddress};
|
|||
use crate::activitypub::identifiers::local_actor_id;
|
||||
use crate::database::json_macro::{json_from_sql, json_to_sql};
|
||||
use crate::errors::{ConversionError, ValidationError};
|
||||
use crate::ethereum::identity::DidPkh;
|
||||
use crate::identity::did_pkh::DidPkh;
|
||||
use crate::utils::caip2::ChainId;
|
||||
use super::validators::{
|
||||
validate_username,
|
||||
|
|
|
@ -3,7 +3,7 @@ use uuid::Uuid;
|
|||
|
||||
use crate::database::catch_unique_violation;
|
||||
use crate::errors::DatabaseError;
|
||||
use crate::ethereum::identity::DidPkh;
|
||||
use crate::identity::did_pkh::DidPkh;
|
||||
use crate::models::profiles::queries::create_profile;
|
||||
use crate::models::profiles::types::{DbActorProfile, ProfileCreateData};
|
||||
use crate::utils::currencies::Currency;
|
||||
|
|
Loading…
Reference in a new issue