Mountain/Environment/
SecretProvider.rs

1//! # SecretProvider Implementation
2//!
3//! Implements the `SecretProvider` trait for the `MountainEnvironment`. This
4//! provider contains the core logic for secure secret storage using the system
5//! keyring, powered by the `keyring` crate.
6
7#![allow(non_snake_case, non_camel_case_types)]
8
9use Common::{Error::CommonError::CommonError, Secret::SecretProvider::SecretProvider};
10use async_trait::async_trait;
11use keyring::Entry;
12use log::{info, trace};
13
14use super::MountainEnvironment::MountainEnvironment;
15
16/// Constructs the service name for the keyring entry.
17fn GetKeyringServiceName(Environment:&MountainEnvironment, ExtensionIdentifier:&str) -> String {
18	format!("{}.{}", Environment.ApplicationHandle.package_info().name, ExtensionIdentifier)
19}
20
21#[async_trait]
22impl SecretProvider for MountainEnvironment {
23	/// Retrieves a secret by reading from the OS keychain.
24	async fn GetSecret(&self, ExtensionIdentifier:String, Key:String) -> Result<Option<String>, CommonError> {
25		trace!(
26			"[SecretProvider] Getting secret for ext: '{}', key: '{}'",
27			ExtensionIdentifier, Key
28		);
29
30		let ServiceName = GetKeyringServiceName(self, &ExtensionIdentifier);
31
32		let Entry = Entry::new(&ServiceName, &Key)
33			.map_err(|Error| CommonError::SecretsAccess { Key:Key.clone(), Reason:Error.to_string() })?;
34
35		match Entry.get_password() {
36			Ok(Password) => Ok(Some(Password)),
37
38			Err(keyring::Error::NoEntry) => Ok(None),
39
40			Err(Error) => Err(CommonError::SecretsAccess { Key, Reason:Error.to_string() }),
41		}
42	}
43
44	/// Stores a secret by writing to the OS keychain.
45	async fn StoreSecret(&self, ExtensionIdentifier:String, Key:String, Value:String) -> Result<(), CommonError> {
46		info!(
47			"[SecretProvider] Storing secret for ext: '{}', key: '{}'",
48			ExtensionIdentifier, Key
49		);
50
51		let ServiceName = GetKeyringServiceName(self, &ExtensionIdentifier);
52
53		let Entry = Entry::new(&ServiceName, &Key)
54			.map_err(|Error| CommonError::SecretsAccess { Key:Key.clone(), Reason:Error.to_string() })?;
55
56		Entry
57			.set_password(&Value)
58			.map_err(|Error| CommonError::SecretsAccess { Key, Reason:Error.to_string() })
59	}
60
61	/// Deletes a secret by removing it from the OS keychain.
62	async fn DeleteSecret(&self, ExtensionIdentifier:String, Key:String) -> Result<(), CommonError> {
63		info!(
64			"[SecretProvider] Deleting secret for ext: '{}', key: '{}'",
65			ExtensionIdentifier, Key
66		);
67
68		let ServiceName = GetKeyringServiceName(self, &ExtensionIdentifier);
69
70		let Entry = Entry::new(&ServiceName, &Key)
71			.map_err(|Error| CommonError::SecretsAccess { Key:Key.clone(), Reason:Error.to_string() })?;
72
73		match Entry.delete_credential() {
74			Ok(_) | Err(keyring::Error::NoEntry) => Ok(()),
75
76			Err(Error) => Err(CommonError::SecretsAccess { Key, Reason:Error.to_string() }),
77		}
78	}
79}