use serde::{Deserialize, Serialize};
pub const BBS_PROVER_NYM_TAG: &str = "bbs:prover_nym";
pub const BBS_SECRET_PROVER_BLIND_TAG: &str = "bbs:secret_prover_blind";
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum CredentialFormat {
Bbs2023,
Zkp,
EddsaJcs2022,
SdJwtVc,
#[serde(untagged)]
Other(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum CredentialStatus {
Valid,
Expired,
Revoked,
Unknown,
}
impl CredentialStatus {
pub fn as_index_token(&self) -> &'static str {
match self {
CredentialStatus::Valid => "valid",
CredentialStatus::Expired => "expired",
CredentialStatus::Revoked => "revoked",
CredentialStatus::Unknown => "unknown",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum CredentialPurpose {
Invite,
Membership,
Role,
Endorsement,
Personhood,
#[serde(untagged)]
Other(String),
}
impl CredentialPurpose {
pub fn as_index_token(&self) -> String {
match self {
CredentialPurpose::Invite => "invite".to_string(),
CredentialPurpose::Membership => "membership".to_string(),
CredentialPurpose::Role => "role".to_string(),
CredentialPurpose::Endorsement => "endorsement".to_string(),
CredentialPurpose::Personhood => "personhood".to_string(),
CredentialPurpose::Other(s) => s.clone(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct StoredCredential {
pub id: String,
pub format: CredentialFormat,
#[serde(default)]
pub types: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub schema_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub community_did: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub subject_did: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub issuer_did: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub purpose: Option<CredentialPurpose>,
pub status: CredentialStatus,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub valid_from: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub valid_until: Option<String>,
pub received_at: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub source: Option<String>,
#[serde(default, skip_serializing_if = "std::collections::BTreeMap::is_empty")]
pub tags: std::collections::BTreeMap<String, String>,
pub body: Vec<u8>,
}
impl StoredCredential {
pub(crate) fn index_terms(&self) -> Vec<(IndexField, String)> {
let mut terms = Vec::new();
for t in &self.types {
terms.push((IndexField::Type, t.clone()));
}
if let Some(c) = &self.community_did {
terms.push((IndexField::CommunityDid, c.clone()));
}
if let Some(i) = &self.issuer_did {
terms.push((IndexField::IssuerDid, i.clone()));
}
if let Some(p) = &self.purpose {
terms.push((IndexField::Purpose, p.as_index_token()));
}
terms.push((IndexField::Status, self.status.as_index_token().to_string()));
terms
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IndexField {
Type,
CommunityDid,
IssuerDid,
Purpose,
Status,
}
impl IndexField {
pub fn token(&self) -> &'static str {
match self {
IndexField::Type => "type",
IndexField::CommunityDid => "community",
IndexField::IssuerDid => "issuer",
IndexField::Purpose => "purpose",
IndexField::Status => "status",
}
}
}