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: added support for indexing by legacy identifiers #335

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 157 additions & 13 deletions src/data_types/macros.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
#[macro_export]
macro_rules! impl_anoncreds_object_identifier {
($i:ident) => {
use regex::Regex;
use std::hash::{Hash, Hasher};
use $crate::error::ValidationError;
use $crate::utils::validation::{
Validatable, LEGACY_CRED_DEF_IDENTIFIER, LEGACY_DID_IDENTIFIER,
LEGACY_REV_REG_DEF_IDENTIFIER, LEGACY_SCHEMA_IDENTIFIER, URI_IDENTIFIER,
};

#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize, Default)]
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct $i(pub String);

impl $i {
Expand Down Expand Up @@ -40,22 +42,85 @@ macro_rules! impl_anoncreds_object_identifier {
pub fn is_uri(&self) -> bool {
URI_IDENTIFIER.captures(&self.0).is_some()
}
fn get_legacy_regex(&self) -> Result<Regex, ValidationError> {
match stringify!($i) {
"IssuerId" => Ok(LEGACY_DID_IDENTIFIER.clone()),
"CredentialDefinitionId" => Ok(LEGACY_CRED_DEF_IDENTIFIER.clone()),
"SchemaId" => Ok(LEGACY_SCHEMA_IDENTIFIER.clone()),
"RevocationRegistryDefinitionId" => Ok(LEGACY_REV_REG_DEF_IDENTIFIER.clone()),
invalid_name => Err($crate::invalid!(
"type: {} does not have a validation regex",
invalid_name,
)),
}
}
fn to_legacy_identifier(&self) -> Result<String, ValidationError> {
let legacy_regex = self.get_legacy_regex()?;
let did_indy_regex = Regex::new(r"^(?:[^:]+:)+([1-9A-HJ-NP-Za-km-z]{21,22})(?:/[^/]+){2}/([^/]+)/([^/]+)/([^/]+)(?:/([^/]+))?$").unwrap();
if let Some(captures) = did_indy_regex.captures(&self.0){
let mut normalized_id = String::new();
let mut index = 0;
for cap in captures.iter().skip(1) {
if let Some(mch) = cap {
let mut new_suffix = mch.as_str();
if index == 1{
new_suffix = match mch.as_str(){
"SCHEMA" => "2",
"CLAIM_DEF" => "3",
"REV_REG_DEF" => "4",
"REV_REG_ENTRY" => "5",
_ => return Err($crate::invalid!("Invalid object type: {}", mch.as_str())),
};
}
normalized_id += (new_suffix.to_owned() + "/").as_str();
}
index += 1;
}
return Ok(normalized_id)
}else if let Some(captures) = legacy_regex.captures(&self.0) {
let mut normalized_id = String::new();
for cap in captures.iter().skip(1) {
if let Some(mch) = cap {
normalized_id += (mch.as_str().to_owned() + "/").as_str();
}
}
return Ok(normalized_id)
}
Ok(self.0.to_string())
}
}

impl PartialEq for $i {
fn eq(&self, other: &Self) -> bool {
if self.0 == other.0 {
true
} else if let Ok(self_legacy) = self.to_legacy_identifier() {
// if identifiers are not equal try making them both legacy identifiers and compare
if let Ok(other_legacy) = other.to_legacy_identifier() {
return self_legacy == other_legacy;
}
false
} else {
false
}
}
}

impl Eq for $i {}

impl Hash for $i {
fn hash<H: Hasher>(&self, state: &mut H) {
if let Ok(legacy) = self.to_legacy_identifier() {
legacy.hash(state);
} else {
self.0.hash(state);
}
}
}

impl Validatable for $i {
fn validate(&self) -> Result<(), ValidationError> {
let legacy_regex = match stringify!($i) {
"IssuerId" => &LEGACY_DID_IDENTIFIER,
"CredentialDefinitionId" => &LEGACY_CRED_DEF_IDENTIFIER,
"SchemaId" => &LEGACY_SCHEMA_IDENTIFIER,
"RevocationRegistryDefinitionId" => &LEGACY_REV_REG_DEF_IDENTIFIER,
invalid_name => {
return Err($crate::invalid!(
"type: {} does not have a validation regex",
invalid_name,
))
}
};
let legacy_regex = self.get_legacy_regex()?;

if $crate::utils::validation::URI_IDENTIFIER
.captures(&self.0)
Expand Down Expand Up @@ -105,3 +170,82 @@ macro_rules! impl_anoncreds_object_identifier {
}
};
}

#[cfg(test)]
mod test_legacy_id_matching {
use crate::{
data_types::{
cred_def::CredentialDefinitionId, rev_reg_def::RevocationRegistryDefinitionId,
schema::SchemaId,
},
error::ValidationError,
};

// use super::*;
#[test]
fn test_eq() -> Result<(), ValidationError> {
// test schema id matching
let did_indy_schema_id =
SchemaId::new("did:indy:sovrin:F72i3Y3Q4i466efjYJYCHM/anoncreds/v0/SCHEMA/npdb/4.3.4")?;
let legacy_indy_schema_id = SchemaId::new("F72i3Y3Q4i466efjYJYCHM:2:npdb:4.3.4")?;
assert!(did_indy_schema_id.eq(&legacy_indy_schema_id));

// test cred def id matching
let did_indy_cred_def_id = CredentialDefinitionId::new(
"did:indy:sovrin:5nDyJVP1NrcPAttP3xwMB9/anoncreds/v0/CLAIM_DEF/56495/npdb",
)?;
let legacy_indy_cred_def_id =
CredentialDefinitionId::new("5nDyJVP1NrcPAttP3xwMB9:3:CL:56495:npdb")?;
assert!(did_indy_cred_def_id.eq(&legacy_indy_cred_def_id));

// test rev reg def id matching
let did_indy_rev_reg_def_id = RevocationRegistryDefinitionId::new(
"did:indy:sovrin:5nDyJVP1NrcPAttP3xwMB9/anoncreds/v0/REV_REG_DEF/56495/npdb/TAG1",
)?;
let legacy_indy_rev_reg_def_id = RevocationRegistryDefinitionId::new(
"5nDyJVP1NrcPAttP3xwMB9:4:5nDyJVP1NrcPAttP3xwMB9:3:CL:56495:npdb:CL_ACCUM:TAG1",
)?;
assert!(did_indy_rev_reg_def_id.eq(&legacy_indy_rev_reg_def_id));
Ok(())
}

#[test]
fn test_hashmap() -> Result<(), ValidationError> {
use std::collections::HashMap;
let mut map = HashMap::new();
let did_indy_schema_id =
SchemaId::new("did:indy:sovrin:F72i3Y3Q4i466efjYJYCHM/anoncreds/v0/SCHEMA/npdb/4.3.4")?;
let legacy_indy_schema_id = SchemaId::new("F72i3Y3Q4i466efjYJYCHM:2:npdb:4.3.4")?;
map.insert(did_indy_schema_id.clone(), "schema_id");
assert_eq!(map.get(&legacy_indy_schema_id), Some(&"schema_id"));

let legacy_indy_schema_id = SchemaId::new("F72i3Y3Q4i466efjYJYCHM:2:npdb:4.3.5")?;
map.insert(legacy_indy_schema_id.clone(), "schema_id2");
assert_eq!(map.get(&legacy_indy_schema_id), Some(&"schema_id2"));

// test cred def id matching
let did_indy_cred_def_id = CredentialDefinitionId::new(
"did:indy:sovrin:5nDyJVP1NrcPAttP3xwMB9/anoncreds/v0/CLAIM_DEF/56495/npdb",
)?;
let legacy_indy_cred_def_id =
CredentialDefinitionId::new("5nDyJVP1NrcPAttP3xwMB9:3:CL:56495:npdb")?;
let mut map = HashMap::new();
map.insert(did_indy_cred_def_id, "cred_def_id");
assert_eq!(map.get(&legacy_indy_cred_def_id), Some(&"cred_def_id"));

// test rev reg def id matching
let did_indy_rev_reg_def_id = RevocationRegistryDefinitionId::new(
"did:indy:sovrin:5nDyJVP1NrcPAttP3xwMB9/anoncreds/v0/REV_REG_DEF/56495/npdb/TAG1",
)?;
let legacy_indy_rev_reg_def_id = RevocationRegistryDefinitionId::new(
"5nDyJVP1NrcPAttP3xwMB9:4:5nDyJVP1NrcPAttP3xwMB9:3:CL:56495:npdb:CL_ACCUM:TAG1",
)?;
let mut map = HashMap::new();
map.insert(did_indy_rev_reg_def_id, "rev_reg_def_id");
assert_eq!(
map.get(&legacy_indy_rev_reg_def_id),
Some(&"rev_reg_def_id")
);
Ok(())
}
}
6 changes: 3 additions & 3 deletions src/utils/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ pub static LEGACY_DID_IDENTIFIER: Lazy<Regex> =
Lazy::new(|| Regex::new("^[1-9A-HJ-NP-Za-km-z]{21,22}$").unwrap());

pub static LEGACY_SCHEMA_IDENTIFIER: Lazy<Regex> =
Lazy::new(|| Regex::new("^[1-9A-HJ-NP-Za-km-z]{21,22}:2:[^:]+:[0-9.]+$").unwrap());
Lazy::new(|| Regex::new("^([1-9A-HJ-NP-Za-km-z]{21,22}):(2):([^:]+):([0-9.]+)$").unwrap());

pub static LEGACY_CRED_DEF_IDENTIFIER: Lazy<Regex> = Lazy::new(|| {
Regex::new("^[1-9A-HJ-NP-Za-km-z]{21,22}:3:CL:(([1-9][0-9]*)|([a-zA-Z0-9]{21,22}:2:[^:]+:[0-9.]+)):([^:]+)?$").unwrap()
Regex::new("^([1-9A-HJ-NP-Za-km-z]{21,22}):(3):CL:(?:([1-9][0-9]*)|([a-zA-Z0-9]{21,22}:2:[^:]+:[0-9.]+)):([^:]+)?$").unwrap()
});

pub static LEGACY_REV_REG_DEF_IDENTIFIER: Lazy<Regex> = Lazy::new(|| {
Regex::new("^[1-9A-HJ-NP-Za-km-z]{21,22}:4:[1-9A-HJ-NP-Za-km-z]{21,22}:3:CL:(([1-9][0-9]*)|([a-zA-Z0-9]{21,22}:2:[^:]+:[0-9.]+)):([^:]+):CL_ACCUM:([^:]+)?$").unwrap()
Regex::new("^([1-9A-HJ-NP-Za-km-z]{21,22}):(4):[1-9A-HJ-NP-Za-km-z]{21,22}:3:CL:(?:([1-9][0-9]*)|([a-zA-Z0-9]{21,22}:2:[^:]+:[0-9.]+)):([^:]+):CL_ACCUM:([^:]+)?$").unwrap()
});

pub fn is_uri_identifier(id: &str) -> bool {
Expand Down
Loading