From 83cf3f8f59a102011ba8ed925a9eec5d980f5da1 Mon Sep 17 00:00:00 2001 From: Frederik Rothenberger Date: Thu, 4 Jul 2024 17:51:30 +0200 Subject: [PATCH] Add support to reconfigure derivation_origin for VC issuer (#2528) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add support to reconfigure derivation_origin for VC issuer This PR allows to reconfigure the expected frontend hostname as well as the derivation origin. This will be used in the future to simplify the e2e tests. Since this is most useful in e2e tests if the configuration is _not_ guarded by the controller, the guard is removed for the `configure` method too for consistency. * Remove test for controller access gate on configure * Add test * 🤖 cargo-fmt auto-update * Assert previous value * 🤖 npm run generate auto-update --------- Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> --- .../vc_issuer/app/generated/vc_issuer_idl.js | 1 + .../app/generated/vc_issuer_types.d.ts | 1 + demos/vc_issuer/src/main.rs | 24 ++++--- demos/vc_issuer/tests/issue_credential.rs | 72 +++++++++++++------ demos/vc_issuer/vc_demo_issuer.did | 1 + src/frontend/generated/vc_issuer_idl.js | 1 + src/vc-api/src/generated/vc_issuer_types.ts | 1 + 7 files changed, 68 insertions(+), 33 deletions(-) diff --git a/demos/vc_issuer/app/generated/vc_issuer_idl.js b/demos/vc_issuer/app/generated/vc_issuer_idl.js index 64bf91a5a9..a39b387ab9 100644 --- a/demos/vc_issuer/app/generated/vc_issuer_idl.js +++ b/demos/vc_issuer/app/generated/vc_issuer_idl.js @@ -108,6 +108,7 @@ export const idlFactory = ({ IDL }) => { [], ), 'set_alternative_origins' : IDL.Func([IDL.Text], [], []), + 'set_derivation_origin' : IDL.Func([IDL.Text, IDL.Text], [], []), 'vc_consent_message' : IDL.Func( [Icrc21VcConsentMessageRequest], [IDL.Variant({ 'Ok' : Icrc21ConsentInfo, 'Err' : Icrc21Error })], diff --git a/demos/vc_issuer/app/generated/vc_issuer_types.d.ts b/demos/vc_issuer/app/generated/vc_issuer_types.d.ts index 07f4fe3eff..64f056a427 100644 --- a/demos/vc_issuer/app/generated/vc_issuer_types.d.ts +++ b/demos/vc_issuer/app/generated/vc_issuer_types.d.ts @@ -88,6 +88,7 @@ export interface _SERVICE { { 'Err' : IssueCredentialError } >, 'set_alternative_origins' : ActorMethod<[string], undefined>, + 'set_derivation_origin' : ActorMethod<[string, string], undefined>, 'vc_consent_message' : ActorMethod< [Icrc21VcConsentMessageRequest], { 'Ok' : Icrc21ConsentInfo } | diff --git a/demos/vc_issuer/src/main.rs b/demos/vc_issuer/src/main.rs index d338b8f81e..794f7c680b 100644 --- a/demos/vc_issuer/src/main.rs +++ b/demos/vc_issuer/src/main.rs @@ -77,7 +77,7 @@ fn config_memory() -> Memory { #[cfg(target_arch = "wasm32")] use ic_cdk::println; -#[derive(CandidType, Deserialize)] +#[derive(CandidType, Deserialize, Clone)] struct IssuerConfig { /// Root of trust for checking canister signatures. ic_root_key_raw: Vec, @@ -143,7 +143,7 @@ struct IssuerInit { #[candid_method(init)] fn init(init_arg: Option) { if let Some(init) = init_arg { - apply_config(init); + apply_config(IssuerConfig::from(init)); }; init_assets(); @@ -156,17 +156,21 @@ fn post_upgrade(init_arg: Option) { #[update] #[candid_method] -fn configure(config: IssuerInit) { - if ic_cdk::api::is_controller(&caller()) { - apply_config(config); - } else { - panic!("Only a controller can call configure()."); - } +fn configure(init: IssuerInit) { + apply_config(IssuerConfig::from(init)); +} + +#[update] +fn set_derivation_origin(frontend_hostname: String, derivation_origin: String) { + let mut config: IssuerConfig = CONFIG.with_borrow(|config| config.get().clone()); + config.derivation_origin = derivation_origin; + config.frontend_hostname = frontend_hostname; + apply_config(config); } -fn apply_config(init: IssuerInit) { +fn apply_config(config: IssuerConfig) { CONFIG - .with_borrow_mut(|config_cell| config_cell.set(IssuerConfig::from(init))) + .with_borrow_mut(|config_cell| config_cell.set(config)) .expect("failed to apply issuer config"); } diff --git a/demos/vc_issuer/tests/issue_credential.rs b/demos/vc_issuer/tests/issue_credential.rs index bccaab2293..bd4f31bd4a 100644 --- a/demos/vc_issuer/tests/issue_credential.rs +++ b/demos/vc_issuer/tests/issue_credential.rs @@ -6,9 +6,7 @@ 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, principal_2, test_principal, time, II_WASM, -}; +use canister_tests::framework::{env, get_wasm_path, principal_1, test_principal, time, II_WASM}; use ic_cdk::api::management_canister::provisional::CanisterId; use ic_response_verification::types::VerificationInfo; use ic_response_verification::verify_request_response_pair; @@ -113,10 +111,9 @@ mod api { pub fn configure( env: &StateMachine, canister_id: CanisterId, - sender: Principal, config: &IssuerInit, ) -> Result<(), CallError> { - call_candid_as(env, canister_id, sender, "configure", (config,)) + call_candid(env, canister_id, "configure", (config,)) } pub fn vc_consent_message( @@ -138,19 +135,31 @@ mod api { pub fn derivation_origin( env: &StateMachine, canister_id: CanisterId, - sender: Principal, derivation_origin_req: &DerivationOriginRequest, ) -> Result, CallError> { - call_candid_as( + call_candid( env, canister_id, - sender, "derivation_origin", (derivation_origin_req,), ) .map(|(x,)| x) } + pub fn set_derivation_origin( + env: &StateMachine, + canister_id: CanisterId, + frontend_hostname: &str, + derivation_origin: &str, + ) -> Result<(), CallError> { + call_candid( + env, + canister_id, + "set_derivation_origin", + (frontend_hostname, derivation_origin), + ) + } + pub fn set_alternative_origins( env: &StateMachine, canister_id: CanisterId, @@ -366,12 +375,41 @@ fn should_return_derivation_origin() { let canister_id = install_canister(&env, VC_ISSUER_WASM.clone()); let frontend_hostname = format!("https://{}.icp0.io", canister_id.to_text()); let req = DerivationOriginRequest { frontend_hostname }; - let response = api::derivation_origin(&env, canister_id, principal_1(), &req) + let response = api::derivation_origin(&env, canister_id, &req) .expect("API call failed") .expect("derivation_origin error"); assert_eq!(response.origin, req.frontend_hostname); } +#[test] +fn should_set_derivation_origin() { + let env = env(); + let canister_id = install_canister(&env, VC_ISSUER_WASM.clone()); + let req = DerivationOriginRequest { + frontend_hostname: "frontend_hostname.com".to_string(), + }; + + let response = api::derivation_origin(&env, canister_id, &req) + .expect("API call failed") + .expect("derivation_origin error"); + let default_derivation_origin = format!("https://{}.icp0.io", canister_id.to_text()); + assert_eq!(response.origin, default_derivation_origin); + + let derivation_origin = "https://derivation.origin"; + api::set_derivation_origin( + &env, + canister_id, + "frontend_hostname.com".to_string().as_str(), + derivation_origin, + ) + .expect("failed to set derivation_origin"); + + let response = api::derivation_origin(&env, canister_id, &req) + .expect("API call failed") + .expect("derivation_origin error"); + assert_eq!(response.origin, derivation_origin); +} + #[test] fn should_return_derivation_origin_with_custom_init() { let env = env(); @@ -385,7 +423,6 @@ fn should_return_derivation_origin_with_custom_init() { let response = api::derivation_origin( &env, issuer_id, - principal_1(), &DerivationOriginRequest { frontend_hostname: custom_init.frontend_hostname.clone(), }, @@ -730,19 +767,8 @@ fn should_issue_credential_e2e() -> Result<(), CallError> { #[test] fn should_configure() { let env = env(); - let controller = principal_1(); - let issuer_id = install_canister_as(&env, VC_ISSUER_WASM.clone(), Some(controller)); - api::configure(&env, issuer_id, controller, &DUMMY_ISSUER_INIT).expect("API call failed"); -} - -#[test] -fn should_fail_configure_if_not_controller() { - let env = env(); - let controller = principal_1(); - let not_controller = principal_2(); - let issuer_id = install_canister_as(&env, VC_ISSUER_WASM.clone(), Some(controller)); - let result = api::configure(&env, issuer_id, not_controller, &DUMMY_ISSUER_INIT); - assert_matches!(result, Err(e) if format!("{:?}", e).contains("Only a controller can call configure")); + let issuer_id = install_canister(&env, VC_ISSUER_WASM.clone()); + api::configure(&env, issuer_id, &DUMMY_ISSUER_INIT).expect("API call failed"); } #[test] diff --git a/demos/vc_issuer/vc_demo_issuer.did b/demos/vc_issuer/vc_demo_issuer.did index e4c945d276..1e8227317c 100644 --- a/demos/vc_issuer/vc_demo_issuer.did +++ b/demos/vc_issuer/vc_demo_issuer.did @@ -120,6 +120,7 @@ service: (opt IssuerConfig) -> { /// Configure the issuer (e.g. set the root key), used for deployment/testing. configure: (IssuerConfig) -> (); + set_derivation_origin: (frontend_hostname: text, derivation_origin: text) -> (); // Sets the content of the alternative origins file. set_alternative_origins: (alternative_origins: text) -> (); diff --git a/src/frontend/generated/vc_issuer_idl.js b/src/frontend/generated/vc_issuer_idl.js index 64bf91a5a9..a39b387ab9 100644 --- a/src/frontend/generated/vc_issuer_idl.js +++ b/src/frontend/generated/vc_issuer_idl.js @@ -108,6 +108,7 @@ export const idlFactory = ({ IDL }) => { [], ), 'set_alternative_origins' : IDL.Func([IDL.Text], [], []), + 'set_derivation_origin' : IDL.Func([IDL.Text, IDL.Text], [], []), 'vc_consent_message' : IDL.Func( [Icrc21VcConsentMessageRequest], [IDL.Variant({ 'Ok' : Icrc21ConsentInfo, 'Err' : Icrc21Error })], diff --git a/src/vc-api/src/generated/vc_issuer_types.ts b/src/vc-api/src/generated/vc_issuer_types.ts index 07f4fe3eff..6fbe791dbb 100644 --- a/src/vc-api/src/generated/vc_issuer_types.ts +++ b/src/vc-api/src/generated/vc_issuer_types.ts @@ -87,6 +87,7 @@ export interface _SERVICE { { 'Ok' : PreparedCredentialData } | { 'Err' : IssueCredentialError } >, + 'set_derivation_origin' : ActorMethod<[string, string], undefined>, 'set_alternative_origins' : ActorMethod<[string], undefined>, 'vc_consent_message' : ActorMethod< [Icrc21VcConsentMessageRequest],