fix: remove export/import commands, rewrite test to use invite/join

This commit is contained in:
Moudy 2026-05-08 20:16:10 +02:00
parent cf699fde7c
commit 6e376900f7
2 changed files with 31 additions and 63 deletions

View File

@ -2,6 +2,10 @@
clippy::tests_outside_test_module,
reason = "Integration test file, not inside a #[cfg(test)] module"
)]
#![expect(
clippy::shadow_unrelated,
reason = "Sequential wallet commands naturally reuse the `command` binding"
)]
//! Shared account integration tests.
//!
@ -75,34 +79,48 @@ async fn group_create_and_shared_account_registration() -> Result<()> {
Ok(())
}
/// GMS seal/unseal round-trip: export GMS, re-import under a new name, verify key agreement.
/// GMS seal/unseal round-trip via invite/join, verify key agreement.
#[test]
async fn group_export_import_key_agreement() -> Result<()> {
async fn group_invite_join_key_agreement() -> Result<()> {
let mut ctx = TestContext::new().await?;
// Generate a sealing key
let command = Command::Group(GroupSubcommand::NewSealingKey);
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
// Create a group
let command = Command::Group(GroupSubcommand::New {
name: "alice-group".into(),
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
// Export the GMS
// Seal GMS for ourselves (simulating invite to another wallet)
let sealing_sk = ctx
.wallet()
.storage()
.user_data
.sealing_secret_key
.context("Sealing key not found")?;
let sealing_pk =
nssa_core::encryption::shared_key_derivation::Secp256k1Point::from_scalar(sealing_sk);
let holder = ctx
.wallet()
.storage()
.user_data
.group_key_holder("alice-group")
.context("Group not found")?;
let gms_hex = hex::encode(holder.dangerous_raw_gms());
let sealed = holder.seal_for(&sealing_pk);
let sealed_hex = hex::encode(&sealed);
// Import under a different name (simulating Bob receiving the GMS)
let command = Command::Group(GroupSubcommand::Import {
// Join under a different name (simulating Bob receiving the sealed GMS)
let command = Command::Group(GroupSubcommand::Join {
name: "bob-copy".into(),
gms: gms_hex,
sealed: sealed_hex,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
// Both derive the same keys for the same tag
// Both derive the same keys for the same derivation seed
let alice_holder = ctx
.wallet()
.storage()
@ -116,12 +134,12 @@ async fn group_export_import_key_agreement() -> Result<()> {
.group_key_holder("bob-copy")
.unwrap();
let tag = [42_u8; 32];
let seed = [42_u8; 32];
let alice_npk = alice_holder
.derive_keys_for_shared_account(&tag)
.derive_keys_for_shared_account(&seed)
.generate_nullifier_public_key();
let bob_npk = bob_holder
.derive_keys_for_shared_account(&tag)
.derive_keys_for_shared_account(&seed)
.generate_nullifier_public_key();
assert_eq!(
@ -129,14 +147,14 @@ async fn group_export_import_key_agreement() -> Result<()> {
"Key agreement: same GMS produces same keys"
);
info!("Key agreement verified");
info!("Key agreement verified via invite/join");
Ok(())
}
/// Fund a shared account from a public account via auth-transfer, then sync.
/// TODO: Requires auth-transfer init to work with shared accounts (authorization flow).
#[test]
#[ignore]
#[ignore = "Requires auth-transfer init to work with shared accounts (authorization flow)"]
async fn fund_shared_account_from_public() -> Result<()> {
let mut ctx = TestContext::new().await?;

View File

@ -15,19 +15,6 @@ pub enum GroupSubcommand {
/// Human-readable name for the group.
name: String,
},
/// Import a group from raw GMS bytes.
Import {
/// Human-readable name for the group.
name: String,
/// Raw GMS as 64-character hex string.
#[arg(long)]
gms: String,
},
/// Export the raw GMS hex for backup or manual distribution.
Export {
/// Group name.
name: String,
},
/// List all groups.
#[command(visible_alias = "ls")]
List,
@ -82,43 +69,6 @@ impl WalletSubcommand for GroupSubcommand {
Ok(SubcommandReturnValue::Empty)
}
Self::Import { name, gms } => {
if wallet_core
.storage()
.user_data
.group_key_holder(&name)
.is_some()
{
anyhow::bail!("Group '{name}' already exists");
}
let gms_bytes: [u8; 32] = hex::decode(&gms)
.context("Invalid GMS hex")?
.try_into()
.map_err(|_err| anyhow::anyhow!("GMS must be exactly 32 bytes"))?;
let holder = GroupKeyHolder::from_gms(gms_bytes);
wallet_core.insert_group_key_holder(name.clone(), holder);
wallet_core.store_persistent_data().await?;
println!("Imported group '{name}'");
Ok(SubcommandReturnValue::Empty)
}
Self::Export { name } => {
let holder = wallet_core
.storage()
.user_data
.group_key_holder(&name)
.context(format!("Group '{name}' not found"))?;
let gms_hex = hex::encode(holder.dangerous_raw_gms());
println!("Group: {name}");
println!("GMS: {gms_hex}");
Ok(SubcommandReturnValue::Empty)
}
Self::List => {
let holders = &wallet_core.storage().user_data.group_key_holders;
if holders.is_empty() {