Save a secret key (with optional encryption).
(
&self,
identity_dir: &Path,
secret_key: &SecretKey,
password: Option<&str>,
)
| 448 | |
| 449 | /// Save a secret key (with optional encryption). |
| 450 | fn save_secret_key( |
| 451 | &self, |
| 452 | identity_dir: &Path, |
| 453 | secret_key: &SecretKey, |
| 454 | password: Option<&str>, |
| 455 | ) -> Result<(), IdentityError> { |
| 456 | let secret_path = identity_dir.join(Self::SECRET_KEY_FILE); |
| 457 | |
| 458 | if let Some(_password) = password { |
| 459 | // TODO: Implement proper password-based encryption |
| 460 | // For now, we'll store it with a marker that it should be encrypted |
| 461 | let stored = StoredSecretKey { |
| 462 | data: data_encoding::BASE64.encode(secret_key.as_bytes()), |
| 463 | encryption: "none".to_string(), // TODO: Change to "argon2id+chacha20poly1305" |
| 464 | salt: None, |
| 465 | nonce: None, |
| 466 | }; |
| 467 | let content = toml::to_string_pretty(&stored)?; |
| 468 | fs::write(&secret_path, content)?; |
| 469 | } else { |
| 470 | // Store unencrypted (not recommended for production) |
| 471 | let stored = StoredSecretKey { |
| 472 | data: data_encoding::BASE64.encode(secret_key.as_bytes()), |
| 473 | encryption: "none".to_string(), |
| 474 | salt: None, |
| 475 | nonce: None, |
| 476 | }; |
| 477 | let content = toml::to_string_pretty(&stored)?; |
| 478 | fs::write(&secret_path, content)?; |
| 479 | } |
| 480 | |
| 481 | // Set restrictive permissions on Unix |
| 482 | #[cfg(unix)] |
| 483 | { |
| 484 | use std::os::unix::fs::PermissionsExt; |
| 485 | let permissions = fs::Permissions::from_mode(0o600); |
| 486 | fs::set_permissions(&secret_path, permissions)?; |
| 487 | } |
| 488 | |
| 489 | Ok(()) |
| 490 | } |
| 491 | |
| 492 | /// Load an identity by ID. |
| 493 | pub fn load(&self, id: &IdentityId) -> Result<Identity, IdentityError> { |
no test coverage detected