use once_cell::sync::Lazy;
use regex::Regex;
use super::cred_def::CredentialDefinitionId;
use super::DELIMITER;
use crate::did::DidValue;
use crate::qualifiable::{self, qualifiable_type, Qualifiable};
use crate::{Validatable, ValidationError};
static QUALIFIED_REV_REG_ID: Lazy<Regex> = Lazy::new(|| {
Regex::new("(^revreg:(?P<method>[a-z0-9]+):)?(?P<did>.+):4:(?P<cred_def_id>.+):(?P<rev_reg_type>.+):(?P<tag>.+)$").unwrap()
});
qualifiable_type!(RevocationRegistryId, "A revocation registry identifier");
impl RevocationRegistryId {
pub const PREFIX: &'static str = "revreg";
pub const MARKER: &'static str = "4";
pub fn new(
did: &DidValue,
cred_def_id: &CredentialDefinitionId,
rev_reg_type: &str,
tag: &str,
) -> RevocationRegistryId {
let id = format!(
"{}{}{}{}{}{}{}{}{}",
did.0,
DELIMITER,
Self::MARKER,
DELIMITER,
cred_def_id.0,
DELIMITER,
rev_reg_type,
DELIMITER,
tag
);
Self::from(qualifiable::combine(
Self::PREFIX,
did.get_method(),
id.as_str(),
))
}
pub fn parts(&self) -> Option<(DidValue, CredentialDefinitionId, String, String)> {
QUALIFIED_REV_REG_ID.captures(&self.0).map(|caps| {
(
DidValue(caps["did"].to_string()),
CredentialDefinitionId(caps["cred_def_id"].to_string()),
caps["rev_reg_type"].to_string(),
caps["tag"].to_string(),
)
})
}
}
impl Qualifiable for RevocationRegistryId {
fn prefix() -> &'static str {
Self::PREFIX
}
fn combine(method: Option<&str>, entity: &str) -> Self {
let sid = Self(entity.to_owned());
match sid.parts() {
Some((did, cred_def_id, rev_reg_type, tag)) => Self::new(
&did.default_method(method),
&cred_def_id.default_method(method),
&rev_reg_type,
&tag,
),
None => sid,
}
}
fn to_unqualified(&self) -> Self {
match self.parts() {
Some((did, cred_def_id, rev_reg_type, tag)) => Self::new(
&did.to_unqualified(),
&cred_def_id.to_unqualified(),
&rev_reg_type,
&tag,
),
None => self.clone(),
}
}
}
impl Validatable for RevocationRegistryId {
fn validate(&self) -> Result<(), ValidationError> {
self.parts().ok_or(format!(
"Revocation Registry Id validation failed: {:?}, doesn't match pattern",
self.0
))?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
fn _did() -> DidValue {
DidValue("NcYxiDXkpYi6ov5FcYDi1e".to_string())
}
fn _rev_reg_type() -> String {
"CL_ACCUM".to_string()
}
fn _tag() -> String {
"TAG_1".to_string()
}
fn _did_qualified() -> DidValue {
DidValue("did:sov:NcYxiDXkpYi6ov5FcYDi1e".to_string())
}
fn _cred_def_id_unqualified() -> CredentialDefinitionId {
CredentialDefinitionId(
"NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag".to_string(),
)
}
fn _cred_def_id_qualified() -> CredentialDefinitionId {
CredentialDefinitionId("creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag".to_string())
}
fn _rev_reg_id_unqualified() -> RevocationRegistryId {
RevocationRegistryId("NcYxiDXkpYi6ov5FcYDi1e:4:NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag:CL_ACCUM:TAG_1".to_string())
}
fn _rev_reg_id_qualified() -> RevocationRegistryId {
RevocationRegistryId("revreg:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:4:creddef:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:3:CL:schema:sov:did:sov:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag:CL_ACCUM:TAG_1".to_string())
}
mod to_unqualified {
use super::*;
#[test]
fn test_rev_reg_id_parts_for_id_as_unqualified() {
assert_eq!(
_rev_reg_id_unqualified(),
_rev_reg_id_unqualified().to_unqualified()
);
}
#[test]
fn test_rev_reg_id_parts_for_id_as_qualified() {
assert_eq!(
_rev_reg_id_unqualified(),
_rev_reg_id_qualified().to_unqualified()
);
}
}
mod parts {
use super::*;
#[test]
fn test_rev_reg_id_parts_for_id_as_unqualified() {
let (did, cred_def_id, rev_reg_type, tag) = _rev_reg_id_unqualified().parts().unwrap();
assert_eq!(_did(), did);
assert_eq!(_cred_def_id_unqualified(), cred_def_id);
assert_eq!(_rev_reg_type(), rev_reg_type);
assert_eq!(_tag(), tag);
}
#[test]
fn test_rev_reg_id_parts_for_id_as_qualified() {
let (did, cred_def_id, rev_reg_type, tag) = _rev_reg_id_qualified().parts().unwrap();
assert_eq!(_did_qualified(), did);
assert_eq!(_cred_def_id_qualified(), cred_def_id);
assert_eq!(_rev_reg_type(), rev_reg_type);
assert_eq!(_tag(), tag);
}
}
mod validate {
use super::*;
#[test]
fn test_validate_rev_reg_id_as_unqualified() {
_rev_reg_id_unqualified().validate().unwrap();
}
#[test]
fn test_validate_rev_reg_id_as_fully_qualified() {
_rev_reg_id_qualified().validate().unwrap();
}
}
mod to_qualified {
use super::*;
#[test]
fn test_red_def_to_qualified() {
assert_eq!(
_rev_reg_id_unqualified().to_qualified("sov").unwrap(),
_rev_reg_id_qualified()
)
}
}
}