Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/did key #1374

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
Next Next commit
did:key DID implementation
  • Loading branch information
UMR1352 committed May 15, 2024
commit 767cf73b0f46055ff2f80951a1c6abb291292aa1
122 changes: 122 additions & 0 deletions identity_did/src/did_key.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
use std::fmt::Debug;
use std::fmt::Display;
use std::str::FromStr;

use crate::CoreDID;
use crate::DIDUrl;
use crate::Error;
use crate::DID;

const METHOD: &str = "key";

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Deserialize, serde::Serialize)]
#[repr(transparent)]
#[serde(into = "DIDUrl", try_from = "DIDUrl")]
/// A type representing a `did:key` DID.
pub struct DIDKey(DIDUrl);

impl DIDKey {
/// Tries to parse a [`DIDKey`] from a string.
pub fn parse(s: &str) -> Result<Self, Error> {
s.parse()
}

/// Returns this [`DIDKey`]'s optional fragment.
pub fn fragment(&self) -> Option<&str> {
self.0.fragment()
}

/// Sets the fragment of this [`DIDKey`].
pub fn set_fragment(&mut self, fragment: Option<&str>) -> Result<(), Error> {
self.0.set_fragment(fragment)
}
}

impl AsRef<CoreDID> for DIDKey {
fn as_ref(&self) -> &CoreDID {
self.0.did()
}
}

impl From<DIDKey> for CoreDID {
fn from(value: DIDKey) -> Self {
value.0.did().clone()
}
}

impl TryFrom<DIDUrl> for DIDKey {
type Error = Error;
fn try_from(value: DIDUrl) -> Result<Self, Self::Error> {
if value.did().method() != METHOD {
Err(Error::InvalidMethodName)
} else if value.path().is_some() {
Err(Error::InvalidPath)
} else if value.query().is_some() {
Err(Error::InvalidQuery)
} else {
Ok(Self(value))
}
}
}

impl Display for DIDKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}

impl FromStr for DIDKey {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
s.parse::<DIDUrl>().and_then(TryFrom::try_from)
}
}

impl From<DIDKey> for String {
fn from(value: DIDKey) -> Self {
value.to_string()
}
}

impl TryFrom<CoreDID> for DIDKey {
type Error = Error;
fn try_from(value: CoreDID) -> Result<Self, Self::Error> {
if value.method() != METHOD {
return Err(Error::InvalidMethodName);
}

Ok(Self(DIDUrl::new(value, None)))
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_valid_deserialization() -> Result<(), Error> {
"did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp".parse::<DIDKey>()?;
"did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp#afragment".parse::<DIDKey>()?;

Ok(())
}

#[test]
fn test_invalid_serialization() {
assert!(
"did:iota:0xf4d6f08f5a1b80dd578da7dc1b49c886d580acd4cf7d48119dfeb82b538ad88a"
.parse::<DIDKey>()
.is_err()
);
assert!("did:key:".parse::<DIDKey>().is_err());
assert!("did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp/"
.parse::<DIDKey>()
.is_err());
assert!("did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp/somepath"
.parse::<DIDKey>()
.is_err());
assert!("did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp?somequery"
.parse::<DIDKey>()
.is_err());
}
}
1 change: 1 addition & 0 deletions identity_did/src/lib.rs
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@
mod did;
mod did_url;
mod error;
mod did_key;

pub use crate::did_url::DIDUrl;
pub use crate::did_url::RelativeDIDUrl;