v0.2.6-pre.012

This commit is contained in:
2026-08-21 16:22:16 +02:00
parent 8ba554306a
commit ecbd6b746d
21 changed files with 634 additions and 94 deletions

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-wallet-desk/src/app_state.rs
// version: 15
// version: 16
//! Shared backend state owned by the Wallet Desk Tauri application.
@@ -126,7 +126,7 @@ impl AppState {
effective_wallets_directory_created_on_startup: self.wallet_config_startup.effective_directory_created_on_startup(),
fallback_logging_active: runtime.fallback_active,
root_wallets_directory_created_on_startup: self.wallet_config_startup.root_directory_created_on_startup(),
shell_phase: "pre.010-credential-rotation".to_owned(),
shell_phase: "pre.012-owner-transfer-export".to_owned(),
startup_diagnostic: runtime.startup_diagnostic.clone(),
transport_available_endpoint_count,
transport_clusters: self.transport_runtime.clusters(),
@@ -722,6 +722,71 @@ impl AppState {
return self.finish_owner_operation(context, result).await;
}
/// Returns the native save-picker default filename when an OWNER session is currently authorized.
pub(crate) fn wallet_export_picker_filename(&self, format: crate::WalletTransferFormatDto) -> ksp_core_lib::Result<String> {
let session = self.wallet_session.lock();
let session = match session {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return std::result::Result::Err(session_lock_error()),
};
return match &*session {
crate::WalletSession::Owner { wallet_id, .. } => std::result::Result::Ok(crate::wallet_export_default_filename(wallet_id.as_str(), format)),
_ => std::result::Result::Err(ksp_core_lib::Error::new(
crate::ERROR_CODE_WALLET_AUTHORIZATION_REQUIRED,
"Wallet transfer export requires an authorized OWNER session",
)),
};
}
/// Exports the immutable Solana keypair to one Rust-owned native save-picker destination.
pub(crate) async fn export_wallet_transfer(
&self,
destination: std::path::PathBuf,
request: crate::WalletExportRequestDto,
) -> ksp_core_lib::Result<crate::WalletExportResultDto> {
let destination_name = crate::wallet_export_destination_name(destination.as_path());
let destination_name = match destination_name {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let format = request.format;
let context = self.begin_owner_operation("keypair_export");
let context = match context {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet_id = context.wallet_id.clone();
ksp_logging_lib::debug!(
target: crate::TRACING_TARGET,
domain = crate::TRACING_DOMAIN_WALLET_EXPORT,
wallet_id = wallet_id.as_str(),
transfer_format = format.code(),
"Wallet OWNER transfer export started"
);
let result = context.owner.export_transfer_file(destination.as_path(), format.wallet_format()).await;
let restored = self.finish_owner_operation(context, result).await;
if let std::result::Result::Err(error) = restored {
ksp_logging_lib::warn!(
target: crate::TRACING_TARGET,
domain = crate::TRACING_DOMAIN_WALLET_EXPORT,
wallet_id = wallet_id.as_str(),
transfer_format = format.code(),
error_domain = error.code().domain(),
error_code = error.code().code(),
"Wallet OWNER transfer export failed"
);
return std::result::Result::Err(error);
}
ksp_logging_lib::info!(
target: crate::TRACING_TARGET,
domain = crate::TRACING_DOMAIN_WALLET_EXPORT,
wallet_id = wallet_id.as_str(),
transfer_format = format.code(),
"Wallet OWNER transfer export completed"
);
return std::result::Result::Ok(crate::WalletExportResultDto { destination_name, format, wallet_id });
}
/// Strongly disables VIEW from the current OWNER session while preserving OWNER authorization.
pub(crate) async fn disable_wallet_view(&self) -> ksp_core_lib::Result<crate::WalletViewSecurityStatusDto> {
let context = self.begin_owner_operation("view_disable");