Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support to reconfigure derivation_origin for VC issuer #2528

Merged
merged 8 commits into from
Jul 4, 2024
1 change: 1 addition & 0 deletions demos/vc_issuer/app/generated/vc_issuer_idl.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 })],
Expand Down
1 change: 1 addition & 0 deletions demos/vc_issuer/app/generated/vc_issuer_types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 } |
Expand Down
24 changes: 14 additions & 10 deletions demos/vc_issuer/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u8>,
Expand Down Expand Up @@ -143,7 +143,7 @@ struct IssuerInit {
#[candid_method(init)]
fn init(init_arg: Option<IssuerInit>) {
if let Some(init) = init_arg {
apply_config(init);
apply_config(IssuerConfig::from(init));
};

init_assets();
Expand All @@ -156,17 +156,21 @@ fn post_upgrade(init_arg: Option<IssuerInit>) {

#[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");
}

Expand Down
72 changes: 49 additions & 23 deletions demos/vc_issuer/tests/issue_credential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the need to specify the sender as these methods can now be called anonymously again.

}

pub fn vc_consent_message(
Expand All @@ -138,19 +135,31 @@ mod api {
pub fn derivation_origin(
env: &StateMachine,
canister_id: CanisterId,
sender: Principal,
derivation_origin_req: &DerivationOriginRequest,
) -> Result<Result<DerivationOriginData, DerivationOriginError>, 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,
Expand Down Expand Up @@ -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)
frederikrothenberger marked this conversation as resolved.
Show resolved Hide resolved
.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();
Expand All @@ -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(),
},
Expand Down Expand Up @@ -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]
Expand Down
1 change: 1 addition & 0 deletions demos/vc_issuer/vc_demo_issuer.did
Original file line number Diff line number Diff line change
Expand Up @@ -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) -> ();

Expand Down
1 change: 1 addition & 0 deletions src/frontend/generated/vc_issuer_idl.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 })],
Expand Down
1 change: 1 addition & 0 deletions src/vc-api/src/generated/vc_issuer_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
Loading