runar-serializer-macros
=======================
Derive and helper procedural macros for `runar-serializer`.
What it provides
----------------
- `#[derive(Encrypt)]`: Generates a companion encrypted struct and helper
methods to selectively encrypt/decrypt fields.
- `#[derive(Plain)]`: Implements zero-copy conversions between your types and
`runar_serializer::ArcValue` for efficient serialization.
Install
-------
```toml
[dependencies]
runar-serializer-macros = "0.1"
```
Encrypt derive
--------------
Annotate a struct with `#[derive(Encrypt)]` and mark fields with zones:
- `#[runar(user)]`: encrypted for the user profile key(s)
- `#[runar(system)]`: encrypted for the network/system key
- `#[runar(search)]`: a search index copy (encrypted) for search contexts
- `#[runar(system_only)]`: only available to the system/network context
Example based on real tests:
```rust
use runar_serializer_macros::Encrypt;
#[derive(Clone, PartialEq, Debug, serde::Serialize, serde::Deserialize, Encrypt)]
pub struct Profile {
pub id: String,
#[runar(system)]
pub name: String,
#[runar(user)]
pub private: String,
#[runar(search)]
pub email: String,
#[runar(system_only)]
pub system_metadata: String,
}
// Generated by the macro:
// - EncryptedProfile: encrypted form
// - Profile::encrypt_with_keystore(&self, ks: &dyn EnvelopeCrypto, res: &dyn LabelResolver)
// - EncryptedProfile::decrypt_with_keystore(&self, ks: &dyn EnvelopeCrypto)
```
End-to-end usage (abridged)
---------------------------
```rust
use std::sync::Arc;
use runar_common::logging::{Component, Logger};
use runar_keys::{MobileKeyManager, NodeKeyManager};
use runar_serializer::{
traits::{
ConfigurableLabelResolver, EnvelopeCrypto, KeyMappingConfig, LabelKeyInfo,
SerializationContext,
},
ArcValue, ValueCategory,
};
// Prepare keystores and label resolver
let logger = Arc::new(Logger::new_root(Component::System, "doc-example"));
let mut network_master = MobileKeyManager::new(logger.clone())?;
let network_id = network_master.generate_network_data_key()?;
let network_pub = network_master.get_network_public_key(&network_id)?;
let mut user_mobile = MobileKeyManager::new(logger.clone())?;
user_mobile.initialize_user_root_key()?;
let profile_pk = user_mobile.derive_user_profile_key("user")?;
user_mobile.install_network_public_key(&network_pub)?;
let mut node = NodeKeyManager::new(logger.clone())?;
let token = node.generate_csr()?;
let nk_msg = network_master.create_network_key_message(&network_id, &token.node_agreement_public_key)?;
node.install_network_key(nk_msg)?;
let resolver = Arc::new(ConfigurableLabelResolver::new(KeyMappingConfig {
label_mappings: std::collections::HashMap::from([
("user".into(), LabelKeyInfo { profile_public_keys: vec![profile_pk.clone()], network_id: None }),
("system".into(), LabelKeyInfo { profile_public_keys: vec![profile_pk.clone()], network_id: Some(network_id.clone()) }),
("system_only".into(), LabelKeyInfo { profile_public_keys: vec![], network_id: Some(network_id.clone()) }),
("search".into(), LabelKeyInfo { profile_public_keys: vec![profile_pk.clone()], network_id: Some(network_id.clone()) }),
]),
}));
// Encrypt/decrypt using the generated helpers
let mobile_ks = Arc::new(user_mobile) as Arc<dyn EnvelopeCrypto>;
let node_ks = Arc::new(node) as Arc<dyn EnvelopeCrypto>;
let profile = Profile {
id: "123".into(),
name: "User".into(),
private: "secret".into(),
email: "user@example.com".into(),
system_metadata: "sys".into(),
};
let encrypted: EncryptedProfile = profile.encrypt_with_keystore(&mobile_ks, resolver.as_ref())?;
let decrypted_for_mobile = encrypted.decrypt_with_keystore(&mobile_ks)?;
let decrypted_for_node = encrypted.decrypt_with_keystore(&node_ks)?;
// Integrate with ArcValue and optional encryption during serialization
let ctx = SerializationContext {
keystore: mobile_ks.clone(),
resolver: resolver.clone(),
network_id: network_id.clone(),
profile_public_key: Some(profile_pk.clone()),
};
let av = ArcValue::new_struct(profile);
assert_eq!(av.category(), ValueCategory::Struct);
let ser = av.serialize(Some(&ctx))?; // encrypted serialization
let de = ArcValue::deserialize(&ser, Some(node_ks.clone()))?; // decrypt with node keystore
```
Plain derive
------------
`#[derive(Plain)]` adds efficient conversions to/from `ArcValue` without manual glue.
```rust
use runar_serializer_macros::Plain;
#[derive(Clone, PartialEq, Debug, serde::Serialize, serde::Deserialize, Plain)]
pub struct SimpleStruct {
pub a: i64,
pub b: String,
}
```
License
-------
MIT. See `LICENSE`.