From 79e695ff50842759b8e441b137d32fdd64ed790d Mon Sep 17 00:00:00 2001 From: Michael Lodder Date: Mon, 3 Feb 2020 17:25:17 -0700 Subject: [PATCH] Update to use newer stuff and handle did path Signed-off-by: Michael Lodder --- Cargo.toml | 11 ++-- src/doc.rs | 2 +- src/fields/context.rs | 4 +- src/fields/publickey.rs | 6 +- src/fields/service_endpoint.rs | 2 +- src/fields/subject.rs | 14 +++- src/uri.rs | 114 ++++++++++++++++++++------------- tests/uri.rs | 10 +++ 8 files changed, 104 insertions(+), 59 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1e4f103..3d993ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "did_doc" -version = "0.3.1" +version = "0.4.0" authors = ["David Huseby", "Mike Lodder"] edition = "2018" description = "Library for loading/saving DID documents." @@ -14,16 +14,15 @@ license = "Apache-2.0" [lib] name = "did_doc" path = "src/lib.rs" -crate-type = ["staticlib", "rlib", "cdylib"] +crate-type = ["rlib"] [dependencies] +failure = "0.1.5" indexmap = { version = "1.2.0", features = ["serde-1"] } log = "0.4.6" -serde = "1.0" -serde_derive = "1.0" +nom = "5.1" +serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" strum = "0.15.0" strum_macros = "0.15.0" void = "1.0.2" -failure = "0.1.5" -nom = "5.0.0" diff --git a/src/doc.rs b/src/doc.rs index 173039d..adcb1b1 100644 --- a/src/doc.rs +++ b/src/doc.rs @@ -1,6 +1,6 @@ use crate::fields::{string_or_list, Context, PublicKey, ServiceEndpoint, Subject}; use indexmap::IndexMap; -use serde_derive::{Deserialize, Serialize}; +use serde::{Deserialize, Serialize}; use serde_json::{self, Value}; use std::str::FromStr; use std::string::{String, ToString}; diff --git a/src/fields/context.rs b/src/fields/context.rs index 7b12f43..c1bacfd 100644 --- a/src/fields/context.rs +++ b/src/fields/context.rs @@ -1,5 +1,5 @@ -use serde::ser::{Serialize, SerializeSeq, Serializer}; -use serde_derive::Deserialize; +use serde::ser::{SerializeSeq, Serializer}; +use serde::{Serialize, Deserialize}; use std::default::Default; use std::str::FromStr; use void::Void; diff --git a/src/fields/publickey.rs b/src/fields/publickey.rs index e342e5e..2ceacec 100644 --- a/src/fields/publickey.rs +++ b/src/fields/publickey.rs @@ -1,7 +1,7 @@ use crate::fields::Subject; -use serde::de::{self, Deserialize, Deserializer, MapAccess, Visitor}; -use serde::ser::{Serialize, SerializeStruct, Serializer}; -use serde_derive::{Deserialize, Serialize}; +use serde::de::{self, Deserializer, MapAccess, Visitor}; +use serde::ser::{SerializeStruct, Serializer}; +use serde::{Deserialize, Serialize}; use std::default::Default; use std::fmt; use std::str::FromStr; diff --git a/src/fields/service_endpoint.rs b/src/fields/service_endpoint.rs index 1cf3e18..d37bf12 100644 --- a/src/fields/service_endpoint.rs +++ b/src/fields/service_endpoint.rs @@ -1,6 +1,6 @@ use crate::fields::{string_or_list, Context, Subject}; use indexmap::IndexMap; -use serde_derive::{Deserialize, Serialize}; +use serde::{Deserialize, Serialize}; use serde_json::Value; #[derive(Serialize, Deserialize, Debug)] diff --git a/src/fields/subject.rs b/src/fields/subject.rs index a916b56..0cb5aaf 100644 --- a/src/fields/subject.rs +++ b/src/fields/subject.rs @@ -1,4 +1,4 @@ -use serde_derive::{Deserialize, Serialize}; +use serde::{Deserialize, Serialize}; use std::cmp::Eq; use std::hash::{Hash, Hasher}; use std::str::FromStr; @@ -34,6 +34,18 @@ impl PartialEq for Subject { } } +impl PartialEq for Subject { + fn eq(&self, rhs: &Uri) -> bool { + self.0 == *rhs + } +} + +impl PartialEq for &Subject { + fn eq(&self, rhs: &Uri) -> bool { + self.0 == *rhs + } +} + impl PartialEq for Subject { fn eq(&self, rhs: &Subject) -> bool { self == rhs diff --git a/src/uri.rs b/src/uri.rs index a5294a7..0138e03 100644 --- a/src/uri.rs +++ b/src/uri.rs @@ -3,7 +3,6 @@ use crate::{DidError, DidErrorKind}; use std::{ collections::BTreeMap, default::Default, - fmt, str::FromStr }; @@ -16,14 +15,15 @@ use nom::{ IResult, }; -use serde::de::{self, Deserialize, Deserializer, Visitor}; -use serde::ser::{Serialize, Serializer}; +use serde::{Serialize, Deserialize}; +use serde::{de::{Deserializer, Visitor, Error}, ser::Serializer}; #[derive(Debug)] pub struct Uri { empty: bool, pub id: String, pub method: String, + pub path: Option>, pub params: Option>, pub query: Option>, pub fragment: Option, @@ -67,6 +67,7 @@ impl Default for Uri { empty: true, id: String::default(), method: String::default(), + path: None, params: None, query: None, fragment: None @@ -91,6 +92,7 @@ impl Clone for Uri { empty: self.empty, id: self.id.clone(), method: self.method.clone(), + path: self.path.clone(), params: self.params.clone(), query: self.query.clone(), fragment: self.fragment.clone(), @@ -104,9 +106,17 @@ impl std::fmt::Display for Uri { return write!(f, ""); } + let mut path = String::new(); + if let Some(p) = &self.path { + path.push('/'); + path.push_str(&p.join("/")); + } + let mut params = String::new(); if let Some(p) = &self.params { - params.push(';'); + if params.len() == 0 { + params.push(';'); + } params.push_str( &p.iter() .map(|(k, v)| format!("{}={}", k, v)) @@ -131,18 +141,58 @@ impl std::fmt::Display for Uri { write!( f, - "did:{}:{}{}{}{}", - self.method, self.id, params, query, fragment + "did:{}:{}{}{}{}{}", + self.method, self.id, path, params, query, fragment ) } } +impl<'de> Deserialize<'de> for Uri { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct UriVisitor; + + impl<'de> Visitor<'de> for UriVisitor { + type Value = Uri; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("DID string") + } + + fn visit_str(self, value: &str) -> Result + where + E: Error, + { + match Uri::from_str(value) { + Ok(d) => Ok(d), + Err(e) => Err(Error::custom(e.to_string())) + } + } + } + + deserializer.deserialize_any(UriVisitor) + } +} + +impl Serialize for Uri { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let s = self.to_string(); + serializer.serialize_str(s.as_str()) + } +} + fn parse_did_string(i: &[u8]) -> IResult<&[u8], Uri> { if i.len() == 0 { return Ok((i, Uri { empty: true, id: String::default(), method: String::default(), + path: None, params: None, query: None, fragment: None @@ -153,6 +203,7 @@ fn parse_did_string(i: &[u8]) -> IResult<&[u8], Uri> { let (i, method) = map(take_while(is_did_method_char), std::str::from_utf8)(i)?; let (i, _) = char(':')(i)?; let (i, id) = map(take_while(is_did_id_char), std::str::from_utf8)(i)?; + let (i, path) = opt(did_path)(i)?; let (i, params) = opt(did_params)(i)?; let (i, query) = opt(did_query)(i)?; let (i, fragment) = opt(did_fragment)(i)?; @@ -163,6 +214,7 @@ fn parse_did_string(i: &[u8]) -> IResult<&[u8], Uri> { empty: false, id: id.unwrap().to_string(), method: method.unwrap().to_string(), + path: path.map(|s| { s.into_iter().map(|g| g.to_string()).collect() }), params: params.map(|m| { m.into_iter() .map(|(k, v)| (k.to_string(), v.to_string())) @@ -186,6 +238,11 @@ fn is_did_id_char(c: u8) -> bool { c.is_ascii_alphanumeric() || c == '.' || c == '_' || c == '-' } +fn did_path(i: &[u8]) -> IResult<&[u8], Vec<&str>> { + let (i, segments) = preceded(char('/'), separated_list(char('/'), map_res(is_a("abcedfghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-%:@!$&'().*+,"), std::str::from_utf8)))(i)?; + Ok((i, segments.into_iter().collect())) +} + fn did_params(i: &[u8]) -> IResult<&[u8], BTreeMap<&str, &str>> { let (i, lst) = preceded(char(';'), separated_list(char(';'), param_item))(i)?; @@ -223,45 +280,6 @@ fn did_fragment(i: &[u8]) -> IResult<&[u8], &str> { preceded(char('#'), map_res(is_not(":#[]"), std::str::from_utf8))(i) } -impl<'de> Deserialize<'de> for Uri { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct UriVisitor; - - impl<'de> Visitor<'de> for UriVisitor { - type Value = Uri; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("DID string") - } - - fn visit_str(self, value: &str) -> Result - where - E: de::Error, - { - match Uri::from_str(value) { - Ok(d) => Ok(d), - Err(e) => Err(de::Error::custom(e.to_string())) - } - } - } - - deserializer.deserialize_any(UriVisitor) - } -} - -impl Serialize for Uri { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let s = self.to_string(); - serializer.serialize_str(s.as_str()) - } -} - #[cfg(test)] mod resolve_method_tests { use super::*; @@ -296,4 +314,10 @@ mod resolve_method_tests { assert_eq!(d.get("%61"), Some(&"%62")); } + #[test] + fn test_did_path() { + let path = b"/spec/trust_ping/1.0/ping"; + let p = did_path(path).unwrap().1; + assert_eq!(p, vec!["spec", "trust_ping", "1.0", "ping"].iter().map(|s| s.to_string()).collect::>()); + } } diff --git a/tests/uri.rs b/tests/uri.rs index 3bee69c..db0ed1c 100644 --- a/tests/uri.rs +++ b/tests/uri.rs @@ -101,3 +101,13 @@ fn did_uri_2() { } } +#[test] +fn did_uri_3() { + let s = "did:sov:wjb4bjwb1235kbg1235/spec/tree/d7879f5e/text"; + let did = s.parse::(); + assert!(did.is_ok()); + let did = did.unwrap(); + assert_eq!(did.id, "wjb4bjwb1235kbg1235"); + assert!(did.path.is_some()); + assert_eq!(did.path, Some(vec!["spec".to_string(), "tree".to_string(), "d7879f5e".to_string(), "text".to_string()])); +}