Skip to content

Commit

Permalink
TECH-292 - Remove CivicPass constraint
Browse files Browse the repository at this point in the history
  • Loading branch information
TYRONEMICHAEL committed Aug 8, 2024
1 parent 716198f commit dae1ca5
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 78 deletions.
40 changes: 10 additions & 30 deletions src/civic_canister_backend/src/consent_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,28 @@ use std::fmt::{Display, Formatter};
use candid::candid_method;
use ic_cdk_macros::update;
use lazy_static::lazy_static;
use crate::credential::{SupportedCredentialType, verify_credential_spec};
use vc_util::issuer_api::{
CredentialSpec, Icrc21ConsentInfo,Icrc21VcConsentMessageRequest, Icrc21ConsentPreferences, Icrc21Error, Icrc21ErrorInfo,
Icrc21ConsentInfo,Icrc21VcConsentMessageRequest, Icrc21ConsentPreferences, Icrc21Error, Icrc21ErrorInfo,
};
use SupportedLanguage::{English, German};

/// Consent messages for the CivicPass VC to be shown and approved to the user during the VC sharing flow
const CIVIC_PASS_VC_DESCRIPTION_EN: &str = r###"# Civic Pass
const CIVIC_PASS_VC_DESCRIPTION_EN: &str = r###"# Verifiable Credential
Credential that states that the holder possesses a Civic Pass."###;
const CIVIC_PASS_VC_DESCRIPTION_DE: &str = r###"# Civic Pass
Credential that states that the holder possesses a Verifiable Credential."###;
const CIVIC_PASS_VC_DESCRIPTION_DE: &str = r###"# Verifiable Credential
Bescheinigung, aus der hervorgeht, dass der Inhaber einen Civic Pass besitzt."###;
Bescheinigung, aus der hervorgeht, dass der Inhaber einen Verifiable Credential besitzt."###;

lazy_static! {
static ref CONSENT_MESSAGE_TEMPLATES: HashMap<(CredentialTemplateType, SupportedLanguage), &'static str> =
HashMap::from([
(
(CredentialTemplateType::CivicPass, English),
(CredentialTemplateType::Credential, English),
CIVIC_PASS_VC_DESCRIPTION_EN
),
(
(CredentialTemplateType::CivicPass, German),
(CredentialTemplateType::Credential, German),
CIVIC_PASS_VC_DESCRIPTION_DE
)
]);
Expand All @@ -35,7 +34,7 @@ lazy_static! {
/// Supported consent message types
#[derive(Clone, Eq, PartialEq, Hash)]
pub enum CredentialTemplateType {
CivicPass,
Credential,
}

/// Supported languages for consent messages
Expand All @@ -45,14 +44,6 @@ pub enum SupportedLanguage {
German,
}

impl From<&SupportedCredentialType> for CredentialTemplateType {
fn from(value: &SupportedCredentialType) -> Self {
match value {
SupportedCredentialType::CivicPass => CredentialTemplateType::CivicPass,
}
}
}

impl From<Icrc21ConsentPreferences> for SupportedLanguage {
fn from(value: Icrc21ConsentPreferences) -> Self {
match &value.language.to_lowercase()[..2] {
Expand All @@ -79,38 +70,27 @@ async fn vc_consent_message(
req: Icrc21VcConsentMessageRequest,
) -> Result<Icrc21ConsentInfo, Icrc21Error> {
get_vc_consent_message(
&req.credential_spec,
&SupportedLanguage::from(req.preferences),
)
}

/// Retrieve the consent message for the given credential type and language.
fn get_vc_consent_message(
credential_spec: &CredentialSpec,
language: &SupportedLanguage,
) -> Result<Icrc21ConsentInfo, Icrc21Error> {
render_consent_message(credential_spec, language).map(|message| Icrc21ConsentInfo {
render_consent_message(language).map(|message| Icrc21ConsentInfo {
consent_message: message,
language: format!("{}", language),
})
}

/// Show the consent message with any arguments
fn render_consent_message(
credential_spec: &CredentialSpec,
language: &SupportedLanguage,
) -> Result<String, Icrc21Error> {
let credential_type = match verify_credential_spec(credential_spec) {
Ok(credential_type) => credential_type,
Err(err) => {
return Err(Icrc21Error::UnsupportedCanisterCall(Icrc21ErrorInfo {
description: err,
}));
}
};
let template = CONSENT_MESSAGE_TEMPLATES
.get(&(
CredentialTemplateType::from(&credential_type),
CredentialTemplateType::Credential,
language.clone(),
))
.ok_or(Icrc21Error::ConsentMessageUnavailable(Icrc21ErrorInfo {
Expand Down
50 changes: 2 additions & 48 deletions src/civic_canister_backend/src/credential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ use serde_json::Value;
use sha2::{Digest, Sha256};
use std::borrow::Cow;
use std::collections::{BTreeMap, HashMap};
use std::fmt;
use std::iter::repeat;
use vc_util::issuer_api::{
CredentialSpec, GetCredentialRequest, IssueCredentialError, IssuedCredentialData,
Expand All @@ -45,20 +44,6 @@ lazy_static! {
static ref CANISTER_SIG_PK: CanisterSigPublicKey = CanisterSigPublicKey::new(ic_cdk::id(), CANISTER_SIG_SEED.clone());
}

/// Supported types of credentials that can be issued by this canister.
#[derive(Debug)]
pub enum SupportedCredentialType {
CivicPass,
}

impl fmt::Display for SupportedCredentialType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SupportedCredentialType::CivicPass => write!(f, "CivicPass"),
}
}
}

/// Represents different types of claim values that can be part of a credential.
#[derive(CandidType, Serialize, Deserialize, Debug, Clone)]
pub enum ClaimValue {
Expand Down Expand Up @@ -455,11 +440,6 @@ fn get_credential(req: GetCredentialRequest) -> Result<IssuedCredentialData, Iss
if let Err(err) = authorize_vc_request(&req.signed_id_alias, &caller(), time().into()) {
return Result::<IssuedCredentialData, IssueCredentialError>::Err(err);
};
if let Err(err) = verify_credential_spec(&req.credential_spec) {
return Result::<IssuedCredentialData, IssueCredentialError>::Err(
IssueCredentialError::UnsupportedCredentialSpec(err),
);
}
// Check if the prepared context is present in the request. This context should contain the JWT of the VC, get it as a string
let prepared_context = match req.prepared_context {
Some(context) => context,
Expand Down Expand Up @@ -539,42 +519,23 @@ fn authorize_vc_request(

/// Check if the given user has a credential of the type and return it.
fn verify_authorized_principal(
credential_type: SupportedCredentialType,
alias_tuple: &AliasTuple,
) -> Result<StoredCredential, IssueCredentialError> {
// Get the credentials of this user
if let Some(credentials) = CREDENTIALS.with(|c| c.borrow().get(&alias_tuple.id_dapp)) {
// Check if the user has a credential of the type and return it
let v: Vec<StoredCredential> = credentials.into();
for c in v {
if c.type_.contains(&credential_type.to_string()) {
return Ok(c);
}
return Ok(c);
}
}
// No (matching) credential found for this user
println!(
"*** Principal {} it is not authorized for credential type {:?}",
alias_tuple.id_dapp.to_text(),
credential_type
);

Err(IssueCredentialError::CredentialNotFound(format!(
"Credential not found for principal {}",
alias_tuple.id_dapp.to_text()
)))
}

/// Verifies if the credential spec is supported and returns the corresponding credential type.
pub(crate) fn verify_credential_spec(
spec: &CredentialSpec,
) -> Result<SupportedCredentialType, String> {
match spec.credential_type.as_str() {
"CivicPass" => Ok(SupportedCredentialType::CivicPass),
other => Err(format!("Credential {} is not supported", other)),
}
}

fn internal_error(msg: &str) -> IssueCredentialError {
IssueCredentialError::Internal(String::from(msg))
}
Expand Down Expand Up @@ -603,14 +564,7 @@ fn prepare_credential_jwt(
credential_spec: &CredentialSpec,
alias_tuple: &AliasTuple,
) -> Result<String, IssueCredentialError> {
let credential_type = match verify_credential_spec(credential_spec) {
Ok(credential_type) => credential_type,
Err(err) => {
return Err(IssueCredentialError::UnsupportedCredentialSpec(err));
}
};

let credential = verify_authorized_principal(credential_type, alias_tuple);
let credential = verify_authorized_principal(alias_tuple);

match credential {
Err(err) => {
Expand Down

0 comments on commit dae1ca5

Please sign in to comment.