auths_cli/services/
platform_claim.rs1use anyhow::{Context, Result};
2use base64::Engine;
3use base64::engine::general_purpose::URL_SAFE_NO_PAD;
4use serde::{Deserialize, Serialize};
5
6use auths_core::signing::{SecureSigner, StorageSigner};
7use auths_core::storage::keychain::{KeyAlias, get_platform_keychain};
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct PlatformClaim {
11 #[serde(rename = "type")]
12 pub claim_type: String,
13 pub platform: String,
14 pub namespace: String,
15 pub did: String,
16 pub timestamp: String,
17 #[serde(skip_serializing_if = "Option::is_none")]
18 pub signature: Option<String>,
19}
20
21pub fn create_signed_platform_claim(
38 platform: &str,
39 namespace: &str,
40 did: &str,
41 key_alias: &str,
42 passphrase_provider: &dyn auths_core::signing::PassphraseProvider,
43) -> Result<String> {
44 let mut claim = PlatformClaim {
45 claim_type: "platform_claim".to_string(),
46 platform: platform.to_string(),
47 namespace: namespace.to_string(),
48 did: did.to_string(),
49 timestamp: chrono::Utc::now().to_rfc3339(),
50 signature: None,
51 };
52
53 let unsigned_json = serde_json::to_value(&claim).context("Failed to serialize claim")?;
55 let canonical =
56 json_canon::to_string(&unsigned_json).context("Failed to canonicalize claim")?;
57
58 let signer = StorageSigner::new(get_platform_keychain().map_err(|e| anyhow::anyhow!(e))?);
60 let alias_typed = KeyAlias::new_unchecked(key_alias);
61 let signature_bytes = signer
62 .sign_with_alias(&alias_typed, passphrase_provider, canonical.as_bytes())
63 .map_err(|e| anyhow::anyhow!("Failed to sign platform claim: {e}"))?;
64
65 claim.signature = Some(URL_SAFE_NO_PAD.encode(&signature_bytes));
66
67 serde_json::to_string_pretty(&claim).context("Failed to serialize signed claim")
68}