1use CommonLibrary::{Error::CommonError::CommonError, Secret::SecretProvider::SecretProvider};
40use async_trait::async_trait;
41use keyring_core::{Entry, Error as KeyringError};
42#[cfg(feature = "AirIntegration")]
44use AirLibrary::Vine::Generated::air::air_service_client::AirServiceClient;
45
46use super::MountainEnvironment::MountainEnvironment;
47use crate::dev_log;
48
49fn GetKeyringServiceName(Environment:&MountainEnvironment, ExtensionIdentifier:&str) -> String {
51 format!("{}.{}", Environment.ApplicationHandle.package_info().name, ExtensionIdentifier)
52}
53
54#[cfg(feature = "AirIntegration")]
60async fn IsAirAvailable(_AirClient:&AirServiceClient<tonic::transport::Channel>) -> bool {
61 true
65}
66
67#[async_trait]
68impl SecretProvider for MountainEnvironment {
69 #[cfg_attr(not(feature = "AirIntegration"), allow(unused_mut))]
75 async fn GetSecret(&self, ExtensionIdentifier:String, Key:String) -> Result<Option<String>, CommonError> {
76 dev_log!(
77 "storage-verbose",
78 "[SecretProvider] Getting secret for ext: '{}', key: '{}'",
79 ExtensionIdentifier,
80 Key
81 );
82
83 #[cfg(feature = "AirIntegration")]
84 {
85 if let Some(AirClient) = &self.AirClient {
86 if IsAirAvailable(AirClient).await {
87 dev_log!(
88 "storage-verbose",
89 "[SecretProvider] Delegating GetSecret to Air service for key: '{}'",
90 Key
91 );
92
93 return GetSecretFromAir(AirClient, ExtensionIdentifier.clone(), Key).await;
94 } else {
95 dev_log!(
96 "storage",
97 "warn: [SecretProvider] Air client unavailable, falling back to local keyring for key: '{}'",
98 Key
99 );
100 }
101 }
102 }
103
104 dev_log!(
105 "storage-verbose",
106 "[SecretProvider] Using local keyring for ext: '{}'",
107 ExtensionIdentifier
108 );
109
110 let ServiceName = GetKeyringServiceName(self, &ExtensionIdentifier);
111
112 let Entry = match Entry::new(&ServiceName, &Key) {
113 Ok(e) => e,
114
115 Err(KeyringError::NoStorageAccess(_)) | Err(KeyringError::PlatformFailure(_)) => {
116 dev_log!(
117 "storage",
118 "warn: [SecretProvider] Keyring unavailable for key '{}', returning None",
119 Key
120 );
121
122 return Ok(None);
123 },
124
125 Err(Error) => return Err(CommonError::SecretsAccess { Key:Key.clone(), Reason:Error.to_string() }),
126 };
127
128 match Entry.get_password() {
129 Ok(Password) => Ok(Some(Password)),
130
131 Err(KeyringError::NoEntry) => Ok(None),
132
133 Err(Error) => Err(CommonError::SecretsAccess { Key, Reason:Error.to_string() }),
134 }
135 }
136
137 #[cfg_attr(not(feature = "AirIntegration"), allow(unused_mut))]
142 async fn StoreSecret(&self, ExtensionIdentifier:String, Key:String, Value:String) -> Result<(), CommonError> {
143 dev_log!(
144 "storage-verbose",
145 "[SecretProvider] Storing secret for ext: '{}', key: '{}'",
146 ExtensionIdentifier,
147 Key
148 );
149
150 #[cfg(feature = "AirIntegration")]
151 {
152 if let Some(AirClient) = &self.AirClient {
153 if IsAirAvailable(AirClient).await {
154 dev_log!(
155 "storage-verbose",
156 "[SecretProvider] Delegating StoreSecret to Air service for key: '{}'",
157 Key
158 );
159
160 return StoreSecretToAir(AirClient, ExtensionIdentifier.clone(), Key, Value).await;
161 } else {
162 dev_log!(
163 "storage",
164 "warn: [SecretProvider] Air client unavailable, falling back to local keyring for key: '{}'",
165 Key
166 );
167 }
168 }
169 }
170
171 dev_log!(
172 "storage-verbose",
173 "[SecretProvider] Using local keyring for ext: '{}'",
174 ExtensionIdentifier
175 );
176
177 let ServiceName = GetKeyringServiceName(self, &ExtensionIdentifier);
178
179 let Entry = match Entry::new(&ServiceName, &Key) {
180 Ok(e) => e,
181
182 Err(KeyringError::NoStorageAccess(_)) | Err(KeyringError::PlatformFailure(_)) => {
183 dev_log!(
184 "storage",
185 "warn: [SecretProvider] Keyring unavailable for key '{}', cannot store",
186 Key
187 );
188
189 return Ok(());
190 },
191
192 Err(Error) => return Err(CommonError::SecretsAccess { Key:Key.clone(), Reason:Error.to_string() }),
193 };
194
195 Entry
196 .set_password(&Value)
197 .map_err(|Error| CommonError::SecretsAccess { Key, Reason:Error.to_string() })
198 }
199
200 #[cfg_attr(not(feature = "AirIntegration"), allow(unused_mut))]
206 async fn DeleteSecret(&self, ExtensionIdentifier:String, Key:String) -> Result<(), CommonError> {
207 dev_log!(
208 "storage-verbose",
209 "[SecretProvider] Deleting secret for ext: '{}', key: '{}'",
210 ExtensionIdentifier,
211 Key
212 );
213
214 #[cfg(feature = "AirIntegration")]
215 {
216 if let Some(AirClient) = &self.AirClient {
217 if IsAirAvailable(AirClient).await {
218 dev_log!(
219 "storage-verbose",
220 "[SecretProvider] Delegating DeleteSecret to Air service for key: '{}'",
221 Key
222 );
223
224 return DeleteSecretFromAir(AirClient, ExtensionIdentifier.clone(), Key).await;
225 } else {
226 dev_log!(
227 "storage",
228 "warn: [SecretProvider] Air client unavailable, falling back to local keyring for key: '{}'",
229 Key
230 );
231 }
232 }
233 }
234
235 dev_log!(
236 "storage-verbose",
237 "[SecretProvider] Using local keyring for ext: '{}'",
238 ExtensionIdentifier
239 );
240
241 let ServiceName = GetKeyringServiceName(self, &ExtensionIdentifier);
242
243 let Entry = match Entry::new(&ServiceName, &Key) {
244 Ok(e) => e,
245
246 Err(KeyringError::NoStorageAccess(_)) | Err(KeyringError::PlatformFailure(_)) => {
247 dev_log!(
248 "storage",
249 "warn: [SecretProvider] Keyring unavailable for key '{}', cannot delete",
250 Key
251 );
252
253 return Ok(());
254 },
255
256 Err(Error) => return Err(CommonError::SecretsAccess { Key:Key.clone(), Reason:Error.to_string() }),
257 };
258
259 match Entry.delete_credential() {
260 Ok(_) | Err(KeyringError::NoEntry) => Ok(()),
261
262 Err(Error) => Err(CommonError::SecretsAccess { Key, Reason:Error.to_string() }),
263 }
264 }
265}
266
267#[cfg(feature = "AirIntegration")]
277async fn GetSecretFromAir(
278 _AirClient:&AirServiceClient<tonic::transport::Channel>,
279
280 ExtensionIdentifier:String,
281
282 Key:String,
283) -> Result<Option<String>, CommonError> {
284 dev_log!(
285 "storage",
286 "[SecretProvider] Fetching secret from Air: ext='{}', key='{}'",
287 ExtensionIdentifier,
288 Key
289 );
290
291 Err(CommonError::NotImplemented { FeatureName:"GetSecretFromAir".to_string() })
295}
296
297#[cfg(feature = "AirIntegration")]
302async fn StoreSecretToAir(
303 _AirClient:&AirServiceClient<tonic::transport::Channel>,
304
305 ExtensionIdentifier:String,
306
307 Key:String,
308
309 _Value:String,
310) -> Result<(), CommonError> {
311 dev_log!(
312 "storage",
313 "[SecretProvider] Storing secret in Air: ext='{}', key='{}'",
314 ExtensionIdentifier,
315 Key
316 );
317
318 Err(CommonError::NotImplemented { FeatureName:"StoreSecretToAir".to_string() })
321}
322
323#[cfg(feature = "AirIntegration")]
325async fn DeleteSecretFromAir(
326 _AirClient:&AirServiceClient<tonic::transport::Channel>,
327
328 ExtensionIdentifier:String,
329
330 Key:String,
331) -> Result<(), CommonError> {
332 dev_log!(
333 "storage",
334 "[SecretProvider] Deleting secret from Air: ext='{}', key='{}'",
335 ExtensionIdentifier,
336 Key
337 );
338
339 Err(CommonError::NotImplemented { FeatureName:"DeleteSecretFromAir".to_string() })
342}