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 Err(KeyringError::NoStorageAccess(_)) | Err(KeyringError::PlatformFailure(_)) => {
115 dev_log!(
116 "storage",
117 "warn: [SecretProvider] Keyring unavailable for key '{}', returning None",
118 Key
119 );
120 return Ok(None);
121 },
122 Err(Error) => return Err(CommonError::SecretsAccess { Key:Key.clone(), Reason:Error.to_string() }),
123 };
124
125 match Entry.get_password() {
126 Ok(Password) => Ok(Some(Password)),
127
128 Err(KeyringError::NoEntry) => Ok(None),
129
130 Err(Error) => Err(CommonError::SecretsAccess { Key, Reason:Error.to_string() }),
131 }
132 }
133
134 #[cfg_attr(not(feature = "AirIntegration"), allow(unused_mut))]
139 async fn StoreSecret(&self, ExtensionIdentifier:String, Key:String, Value:String) -> Result<(), CommonError> {
140 dev_log!(
141 "storage-verbose",
142 "[SecretProvider] Storing secret for ext: '{}', key: '{}'",
143 ExtensionIdentifier,
144 Key
145 );
146
147 #[cfg(feature = "AirIntegration")]
148 {
149 if let Some(AirClient) = &self.AirClient {
150 if IsAirAvailable(AirClient).await {
151 dev_log!(
152 "storage-verbose",
153 "[SecretProvider] Delegating StoreSecret to Air service for key: '{}'",
154 Key
155 );
156
157 return StoreSecretToAir(AirClient, ExtensionIdentifier.clone(), Key, Value).await;
158 } else {
159 dev_log!(
160 "storage",
161 "warn: [SecretProvider] Air client unavailable, falling back to local keyring for key: '{}'",
162 Key
163 );
164 }
165 }
166 }
167
168 dev_log!(
169 "storage-verbose",
170 "[SecretProvider] Using local keyring for ext: '{}'",
171 ExtensionIdentifier
172 );
173
174 let ServiceName = GetKeyringServiceName(self, &ExtensionIdentifier);
175
176 let Entry = match Entry::new(&ServiceName, &Key) {
177 Ok(e) => e,
178 Err(KeyringError::NoStorageAccess(_)) | Err(KeyringError::PlatformFailure(_)) => {
179 dev_log!(
180 "storage",
181 "warn: [SecretProvider] Keyring unavailable for key '{}', cannot store",
182 Key
183 );
184 return Ok(());
185 },
186 Err(Error) => return Err(CommonError::SecretsAccess { Key:Key.clone(), Reason:Error.to_string() }),
187 };
188
189 Entry
190 .set_password(&Value)
191 .map_err(|Error| CommonError::SecretsAccess { Key, Reason:Error.to_string() })
192 }
193
194 #[cfg_attr(not(feature = "AirIntegration"), allow(unused_mut))]
200 async fn DeleteSecret(&self, ExtensionIdentifier:String, Key:String) -> Result<(), CommonError> {
201 dev_log!(
202 "storage-verbose",
203 "[SecretProvider] Deleting secret for ext: '{}', key: '{}'",
204 ExtensionIdentifier,
205 Key
206 );
207
208 #[cfg(feature = "AirIntegration")]
209 {
210 if let Some(AirClient) = &self.AirClient {
211 if IsAirAvailable(AirClient).await {
212 dev_log!(
213 "storage-verbose",
214 "[SecretProvider] Delegating DeleteSecret to Air service for key: '{}'",
215 Key
216 );
217
218 return DeleteSecretFromAir(AirClient, ExtensionIdentifier.clone(), Key).await;
219 } else {
220 dev_log!(
221 "storage",
222 "warn: [SecretProvider] Air client unavailable, falling back to local keyring for key: '{}'",
223 Key
224 );
225 }
226 }
227 }
228
229 dev_log!(
230 "storage-verbose",
231 "[SecretProvider] Using local keyring for ext: '{}'",
232 ExtensionIdentifier
233 );
234
235 let ServiceName = GetKeyringServiceName(self, &ExtensionIdentifier);
236
237 let Entry = match Entry::new(&ServiceName, &Key) {
238 Ok(e) => e,
239 Err(KeyringError::NoStorageAccess(_)) | Err(KeyringError::PlatformFailure(_)) => {
240 dev_log!(
241 "storage",
242 "warn: [SecretProvider] Keyring unavailable for key '{}', cannot delete",
243 Key
244 );
245 return Ok(());
246 },
247 Err(Error) => return Err(CommonError::SecretsAccess { Key:Key.clone(), Reason:Error.to_string() }),
248 };
249
250 match Entry.delete_credential() {
251 Ok(_) | Err(KeyringError::NoEntry) => Ok(()),
252
253 Err(Error) => Err(CommonError::SecretsAccess { Key, Reason:Error.to_string() }),
254 }
255 }
256}
257
258#[cfg(feature = "AirIntegration")]
268async fn GetSecretFromAir(
269 _AirClient:&AirServiceClient<tonic::transport::Channel>,
270
271 ExtensionIdentifier:String,
272
273 Key:String,
274) -> Result<Option<String>, CommonError> {
275 dev_log!(
276 "storage",
277 "[SecretProvider] Fetching secret from Air: ext='{}', key='{}'",
278 ExtensionIdentifier,
279 Key
280 );
281
282 Err(CommonError::NotImplemented { FeatureName:"GetSecretFromAir".to_string() })
286}
287
288#[cfg(feature = "AirIntegration")]
293async fn StoreSecretToAir(
294 _AirClient:&AirServiceClient<tonic::transport::Channel>,
295
296 ExtensionIdentifier:String,
297
298 Key:String,
299
300 _Value:String,
301) -> Result<(), CommonError> {
302 dev_log!(
303 "storage",
304 "[SecretProvider] Storing secret in Air: ext='{}', key='{}'",
305 ExtensionIdentifier,
306 Key
307 );
308
309 Err(CommonError::NotImplemented { FeatureName:"StoreSecretToAir".to_string() })
312}
313
314#[cfg(feature = "AirIntegration")]
316async fn DeleteSecretFromAir(
317 _AirClient:&AirServiceClient<tonic::transport::Channel>,
318
319 ExtensionIdentifier:String,
320
321 Key:String,
322) -> Result<(), CommonError> {
323 dev_log!(
324 "storage",
325 "[SecretProvider] Deleting secret from Air: ext='{}', key='{}'",
326 ExtensionIdentifier,
327 Key
328 );
329
330 Err(CommonError::NotImplemented { FeatureName:"DeleteSecretFromAir".to_string() })
333}