diff --git a/demos/vc_issuer/src/main.rs b/demos/vc_issuer/src/main.rs index bad1714e24..cab429aef3 100644 --- a/demos/vc_issuer/src/main.rs +++ b/demos/vc_issuer/src/main.rs @@ -20,10 +20,9 @@ use std::borrow::Cow; use std::cell::RefCell; use std::collections::HashSet; use vc_util::issuer_api::{ - ArgumentValue, CredentialSpec, GetCredentialRequest, GetCredentialResponse, Icrc21ConsentInfo, - Icrc21Error, Icrc21ErrorInfo, Icrc21VcConsentMessageRequest, IssueCredentialError, - IssuedCredentialData, PrepareCredentialRequest, PrepareCredentialResponse, - PreparedCredentialData, SignedIdAlias, + ArgumentValue, CredentialSpec, GetCredentialRequest, Icrc21ConsentInfo, Icrc21Error, + Icrc21ErrorInfo, Icrc21VcConsentMessageRequest, IssueCredentialError, IssuedCredentialData, + PrepareCredentialRequest, PreparedCredentialData, SignedIdAlias, }; use vc_util::{ did_for_principal, get_verified_id_alias_from_jws, vc_jwt_to_jws, vc_signing_input, @@ -188,23 +187,23 @@ fn extract_id_alias( #[update] #[candid_method] -async fn prepare_credential(req: PrepareCredentialRequest) -> PrepareCredentialResponse { +async fn prepare_credential( + req: PrepareCredentialRequest, +) -> Result { let alias_tuple = match authorize_vc_request(&req.signed_id_alias, time().into()) { Ok(alias_tuple) => alias_tuple, - Err(err) => return PrepareCredentialResponse::Err(err), + Err(err) => return Err(err), }; let credential_type = match verify_credential_spec(&req.credential_spec) { Ok(credential_type) => credential_type, Err(err) => { - return PrepareCredentialResponse::Err( - IssueCredentialError::UnsupportedCredentialSpec(err), - ); + return Err(IssueCredentialError::UnsupportedCredentialSpec(err)); } }; let credential = match prepare_credential_payload(&credential_type, &alias_tuple) { Ok(credential) => credential, - Err(err) => return PrepareCredentialResponse::Err(err), + Err(err) => return Result::::Err(err), }; let seed = calculate_seed(&alias_tuple.id_alias); let canister_id = ic_cdk::id(); @@ -221,7 +220,7 @@ async fn prepare_credential(req: PrepareCredentialRequest) -> PrepareCredentialR add_signature(&mut sigs, msg_hash, seed); }); update_root_hash(); - PrepareCredentialResponse::Ok(PreparedCredentialData { + Ok(PreparedCredentialData { prepared_context: Some(ByteBuf::from(credential_jwt.as_bytes())), }) } @@ -242,13 +241,15 @@ fn update_root_hash() { #[query] #[candid_method(query)] -fn get_credential(req: GetCredentialRequest) -> GetCredentialResponse { +fn get_credential(req: GetCredentialRequest) -> Result { let alias_tuple = match authorize_vc_request(&req.signed_id_alias, time().into()) { Ok(alias_tuple) => alias_tuple, - Err(err) => return GetCredentialResponse::Err(err), + Err(err) => return Result::::Err(err), }; if let Err(err) = verify_credential_spec(&req.credential_spec) { - return GetCredentialResponse::Err(IssueCredentialError::UnsupportedCredentialSpec(err)); + return Result::::Err( + IssueCredentialError::UnsupportedCredentialSpec(err), + ); } let subject_principal = alias_tuple.id_alias; let seed = calculate_seed(&subject_principal); @@ -256,11 +257,19 @@ fn get_credential(req: GetCredentialRequest) -> GetCredentialResponse { let canister_sig_pk = CanisterSigPublicKey::new(canister_id, seed.to_vec()); let prepared_context = match req.prepared_context { Some(context) => context, - None => return GetCredentialResponse::Err(internal_error("missing prepared_context")), + None => { + return Result::::Err(internal_error( + "missing prepared_context", + )) + } }; let credential_jwt = match String::from_utf8(prepared_context.into_vec()) { Ok(s) => s, - Err(_) => return GetCredentialResponse::Err(internal_error("invalid prepared_context")), + Err(_) => { + return Result::::Err(internal_error( + "invalid prepared_context", + )) + } }; let signing_input = vc_signing_input(&credential_jwt, &canister_sig_pk).expect("failed getting signing_input"); @@ -278,15 +287,17 @@ fn get_credential(req: GetCredentialRequest) -> GetCredentialResponse { let sig = match sig_result { Ok(sig) => sig, Err(e) => { - return GetCredentialResponse::Err(IssueCredentialError::SignatureNotFound(format!( - "signature not prepared or expired: {}", - e - ))); + return Result::::Err( + IssueCredentialError::SignatureNotFound(format!( + "signature not prepared or expired: {}", + e + )), + ); } }; let vc_jws = vc_jwt_to_jws(&credential_jwt, &canister_sig_pk, &sig).expect("failed constructing JWS"); - GetCredentialResponse::Ok(IssuedCredentialData { vc_jws }) + Result::::Ok(IssuedCredentialData { vc_jws }) } #[update] diff --git a/demos/vc_issuer/tests/issue_credential.rs b/demos/vc_issuer/tests/issue_credential.rs index eb3ed40574..5bd1bae985 100644 --- a/demos/vc_issuer/tests/issue_credential.rs +++ b/demos/vc_issuer/tests/issue_credential.rs @@ -5,8 +5,8 @@ use candid::{CandidType, Deserialize, Principal}; use canister_sig_util::{extract_raw_root_pk_from_der, CanisterSigPublicKey}; use canister_tests::api::http_request; use canister_tests::api::internet_identity::vc_mvp as ii_api; +use canister_tests::flows; use canister_tests::framework::{env, get_wasm_path, principal_1, test_principal, time, II_WASM}; -use canister_tests::{flows, match_value}; use ic_cdk::api::management_canister::provisional::CanisterId; use ic_response_verification::types::{Request, Response, VerificationInfo}; use ic_response_verification::verify_request_response_pair; @@ -25,9 +25,9 @@ use std::collections::HashMap; use std::path::PathBuf; use std::time::{Duration, UNIX_EPOCH}; use vc_util::issuer_api::{ - ArgumentValue, CredentialSpec, GetCredentialRequest, GetCredentialResponse, - Icrc21ConsentPreferences, Icrc21Error, Icrc21VcConsentMessageRequest, IssueCredentialError, - PrepareCredentialRequest, PrepareCredentialResponse, SignedIdAlias as SignedIssuerIdAlias, + ArgumentValue, CredentialSpec, GetCredentialRequest, Icrc21ConsentPreferences, Icrc21Error, + Icrc21VcConsentMessageRequest, IssueCredentialError, PrepareCredentialRequest, + PreparedCredentialData, SignedIdAlias as SignedIssuerIdAlias, }; use vc_util::{ did_for_principal, get_verified_id_alias_from_jws, verify_credential_jws_with_canister_id, @@ -91,7 +91,7 @@ pub fn install_issuer(env: &StateMachine, init: &IssuerInit) -> CanisterId { mod api { use super::*; - use vc_util::issuer_api::Icrc21ConsentInfo; + use vc_util::issuer_api::{Icrc21ConsentInfo, IssuedCredentialData, PreparedCredentialData}; pub fn configure( env: &StateMachine, @@ -146,7 +146,7 @@ mod api { canister_id: CanisterId, sender: Principal, prepare_credential_request: &PrepareCredentialRequest, - ) -> Result { + ) -> Result, CallError> { call_candid_as( env, canister_id, @@ -162,7 +162,7 @@ mod api { canister_id: CanisterId, sender: Principal, get_credential_request: &GetCredentialRequest, - ) -> Result { + ) -> Result, CallError> { query_candid_as( env, canister_id, @@ -360,7 +360,7 @@ fn should_fail_prepare_credential_for_unauthorized_principal() { }, ) .expect("API call failed"); - assert_matches!(response, PrepareCredentialResponse::Err(e) if format!("{:?}", e).contains("unauthorized principal")); + assert_matches!(response, Err(e) if format!("{:?}", e).contains("unauthorized principal")); } #[test] @@ -380,7 +380,7 @@ fn should_fail_prepare_credential_for_wrong_sender() { ) .expect("API call failed"); assert_matches!(response, - PrepareCredentialResponse::Err(IssueCredentialError::UnauthorizedSubject(e)) if e.contains(&format!("Caller {} does not match id alias dapp principal {}.", principal_1(), DUMMY_ALIAS_ID_DAPP_PRINCIPAL)) + Err(IssueCredentialError::UnauthorizedSubject(e)) if e.contains(&format!("Caller {} does not match id alias dapp principal {}.", principal_1(), DUMMY_ALIAS_ID_DAPP_PRINCIPAL)) ); } @@ -393,18 +393,18 @@ fn should_fail_get_credential_for_wrong_sender() { api::add_employee(&env, issuer_id, authorized_principal).expect("failed to add employee"); let unauthorized_principal = test_principal(2); - match_value!( - api::prepare_credential( - &env, - issuer_id, - authorized_principal, - &PrepareCredentialRequest { - credential_spec: employee_credential_spec(), - signed_id_alias: signed_id_alias.clone(), - }, - ), - Ok(PrepareCredentialResponse::Ok(prepare_credential_response)) - ); + let prepare_credential_response = api::prepare_credential( + &env, + issuer_id, + authorized_principal, + &PrepareCredentialRequest { + credential_spec: employee_credential_spec(), + signed_id_alias: signed_id_alias.clone(), + }, + ) + .unwrap() + .unwrap(); + let get_credential_response = api::get_credential( &env, issuer_id, @@ -417,7 +417,7 @@ fn should_fail_get_credential_for_wrong_sender() { ) .expect("API call failed"); assert_matches!(get_credential_response, - GetCredentialResponse::Err(IssueCredentialError::UnauthorizedSubject(e)) if e.contains(&format!("Caller {} does not match id alias dapp principal {}.", unauthorized_principal, authorized_principal)) + Err(IssueCredentialError::UnauthorizedSubject(e)) if e.contains(&format!("Caller {} does not match id alias dapp principal {}.", unauthorized_principal, authorized_principal)) ); } @@ -436,7 +436,7 @@ fn should_fail_prepare_credential_for_anonymous_caller() { ) .expect("API call failed"); assert_matches!(response, - PrepareCredentialResponse::Err(IssueCredentialError::UnauthorizedSubject(e)) if e.contains(&format!("Caller 2vxsx-fae does not match id alias dapp principal {}.", DUMMY_ALIAS_ID_DAPP_PRINCIPAL)) + Err(IssueCredentialError::UnauthorizedSubject(e)) if e.contains(&format!("Caller 2vxsx-fae does not match id alias dapp principal {}.", DUMMY_ALIAS_ID_DAPP_PRINCIPAL)) ); } @@ -460,10 +460,7 @@ fn should_fail_prepare_credential_for_wrong_root_key() { }, ) .expect("API call failed"); - assert_matches!( - response, - PrepareCredentialResponse::Err(IssueCredentialError::InvalidIdAlias(_)) - ); + assert_matches!(response, Err(IssueCredentialError::InvalidIdAlias(_))); } #[test] @@ -486,10 +483,7 @@ fn should_fail_prepare_credential_for_wrong_idp_canister_id() { }, ) .expect("API call failed"); - assert_matches!( - response, - PrepareCredentialResponse::Err(IssueCredentialError::InvalidIdAlias(_)) - ); + assert_matches!(response, Err(IssueCredentialError::InvalidIdAlias(_))); } #[test] @@ -508,7 +502,7 @@ fn should_prepare_employee_credential_for_authorized_principal() { }, ) .expect("API call failed"); - assert_matches!(response, PrepareCredentialResponse::Ok(_)); + assert_matches!(response, Ok(_)); } #[test] @@ -527,7 +521,7 @@ fn should_prepare_degree_credential_for_authorized_principal() { }, ) .expect("API call failed"); - assert_matches!(response, PrepareCredentialResponse::Ok(_)); + assert_matches!(response, Ok(_)); } /// Verifies that different credentials are being created including II interactions. @@ -606,7 +600,9 @@ fn should_issue_credential_e2e() -> Result<(), CallError> { }, )?; let prepared_credential = - if let PrepareCredentialResponse::Ok(data) = prepare_credential_response { + if let Result::::Ok(data) = + prepare_credential_response + { data } else { panic!( @@ -630,12 +626,8 @@ fn should_issue_credential_e2e() -> Result<(), CallError> { prepared_context: prepared_credential.prepared_context, }, )?; - match_value!( - get_credential_response, - GetCredentialResponse::Ok(credential_data) - ); let claims = verify_credential_jws_with_canister_id( - &credential_data.vc_jws, + &get_credential_response.unwrap().vc_jws, &issuer_id, &root_pk_raw, env.time().duration_since(UNIX_EPOCH).unwrap().as_nanos(), diff --git a/src/vc_util/src/issuer_api.rs b/src/vc_util/src/issuer_api.rs index 1de4110426..b7bc4d8a3c 100644 --- a/src/vc_util/src/issuer_api.rs +++ b/src/vc_util/src/issuer_api.rs @@ -17,12 +17,6 @@ pub struct PrepareCredentialRequest { pub credential_spec: CredentialSpec, } -#[derive(Clone, Debug, CandidType, Deserialize, Eq, PartialEq)] -pub enum PrepareCredentialResponse { - Ok(PreparedCredentialData), - Err(IssueCredentialError), -} - #[derive(Clone, Debug, CandidType, Deserialize, Eq, PartialEq)] pub enum IssueCredentialError { UnknownSubject(String), @@ -40,12 +34,6 @@ pub struct GetCredentialRequest { pub prepared_context: Option, } -#[derive(Clone, Debug, CandidType, Deserialize, Eq, PartialEq)] -pub enum GetCredentialResponse { - Ok(IssuedCredentialData), - Err(IssueCredentialError), -} - #[derive(Clone, Debug, CandidType, Deserialize, Eq, PartialEq)] pub struct PreparedCredentialData { pub prepared_context: Option,