commit 426fba9fdf84d95105d6c055e9c55cbf34358aa0
parent 50c99cefdb531830b99fdee3aa374d7e83be804a
Author: triesap <triesap@radroots.dev>
Date: Mon, 19 Jan 2026 01:45:44 +0000
app-core: add device key material provider
- implement device key material provider with registry storage
- return crypto undefined for non-wasm key material
- expose provider from crypto module exports
- add provider id and non-wasm error tests
Diffstat:
2 files changed, 65 insertions(+), 0 deletions(-)
diff --git a/crates/core/src/crypto/mod.rs b/crates/core/src/crypto/mod.rs
@@ -5,6 +5,7 @@ pub mod random;
pub mod keys;
pub mod kdf;
pub mod registry;
+pub mod provider;
pub use error::{RadrootsClientCryptoError, RadrootsClientCryptoErrorMessage};
pub use types::{
@@ -20,6 +21,7 @@ pub use types::{
RadrootsClientLegacyKeyConfig,
RadrootsClientWebCryptoService,
};
+pub use provider::RadrootsClientDeviceKeyMaterialProvider;
pub use envelope::{crypto_envelope_decode, crypto_envelope_encode};
pub use keys::crypto_key_id_create;
pub use kdf::{crypto_kdf_iterations_default, crypto_kdf_salt_create};
diff --git a/crates/core/src/crypto/provider.rs b/crates/core/src/crypto/provider.rs
@@ -0,0 +1,63 @@
+use async_trait::async_trait;
+
+#[cfg(target_arch = "wasm32")]
+use crate::crypto::random::fill_random;
+#[cfg(target_arch = "wasm32")]
+use crate::crypto::registry::{
+ crypto_registry_get_device_material,
+ crypto_registry_set_device_material,
+};
+
+use super::{RadrootsClientCryptoError, RadrootsClientKeyMaterialProvider};
+
+const DEVICE_PROVIDER_ID: &str = "device";
+#[cfg(target_arch = "wasm32")]
+const DEVICE_MATERIAL_BYTES: usize = 32;
+
+pub struct RadrootsClientDeviceKeyMaterialProvider;
+
+#[async_trait(?Send)]
+impl RadrootsClientKeyMaterialProvider for RadrootsClientDeviceKeyMaterialProvider {
+ async fn get_key_material(&self) -> Result<Vec<u8>, RadrootsClientCryptoError> {
+ #[cfg(not(target_arch = "wasm32"))]
+ {
+ return Err(RadrootsClientCryptoError::CryptoUndefined);
+ }
+ #[cfg(target_arch = "wasm32")]
+ {
+ if let Some(existing) = crypto_registry_get_device_material().await? {
+ return Ok(existing);
+ }
+ let mut material = vec![0u8; DEVICE_MATERIAL_BYTES];
+ fill_random(&mut material)?;
+ crypto_registry_set_device_material(&material).await?;
+ Ok(material)
+ }
+ }
+
+ async fn get_provider_id(&self) -> Result<String, RadrootsClientCryptoError> {
+ Ok(String::from(DEVICE_PROVIDER_ID))
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::RadrootsClientDeviceKeyMaterialProvider;
+ use crate::crypto::{RadrootsClientCryptoError, RadrootsClientKeyMaterialProvider};
+
+ #[test]
+ fn provider_id_is_device() {
+ let provider = RadrootsClientDeviceKeyMaterialProvider;
+ let id = futures::executor::block_on(provider.get_provider_id())
+ .expect("provider id");
+ assert_eq!(id, "device");
+ }
+
+ #[test]
+ fn non_wasm_material_errors() {
+ let provider = RadrootsClientDeviceKeyMaterialProvider;
+ let err = futures::executor::block_on(provider.get_key_material())
+ .expect_err("missing crypto");
+ assert_eq!(err, RadrootsClientCryptoError::CryptoUndefined);
+ }
+}