Repository: bilelmoussaoui/oo7 (language: rust)

Issue:
Fallback to the host if the secret portal is not available



Discussion / hints:

Fix patch:
diff --git a/src/keyring.rs b/src/keyring.rs
index 6674edb42..2ef8585e3 100644
--- a/src/keyring.rs
+++ b/src/keyring.rs
@@ -32,30 +32,40 @@ impl Keyring {
     /// Create a new instance of the Keyring.
     pub async fn new() -> Result<Self> {
         let is_sandboxed = crate::is_sandboxed();
-
         if is_sandboxed {
             #[cfg(feature = "tracing")]
             tracing::debug!("Application is sandboxed, using the file backend");
-            Ok(Self::File(Arc::new(portal::Keyring::load_default().await?)))
+
+            match portal::Keyring::load_default().await {
+                Ok(portal) => return Ok(Self::File(Arc::new(portal))),
+                // Do nothing in this case, we are supposed to fallback to the host keyring
+                Err(portal::Error::PortalNotAvailable) => {
+                    #[cfg(feature = "tracing")]
+                    tracing::debug!(
+                        "org.freedesktop.portal.Secrets is not available, falling back to the Sercret Service backend"
+                    );
+                }
+                Err(e) => return Err(crate::Error::Portal(e)),
+            };
         } else {
             #[cfg(feature = "tracing")]
             tracing::debug!(
                 "Application is not sandboxed, falling back to the Sercret Service backend"
             );
-            let service = dbus::Service::new(Algorithm::Encrypted).await?;
-            let collection = match service.default_collection().await {
-                Ok(c) => Ok(c),
-                Err(crate::dbus::Error::NotFound(_)) => {
-                    #[cfg(feature = "tracing")]
-                    tracing::debug!("Default collection doesn't exists, trying to create it");
-                    service
-                        .create_collection("Login", Some(DEFAULT_COLLECTION))
-                        .await
-                }
-                Err(e) => Err(e),
-            }?;
-            Ok(Self::DBus(collection))
         }
+        let service = dbus::Service::new(Algorithm::Encrypted).await?;
+        let collection = match service.default_collection().await {
+            Ok(c) => Ok(c),
+            Err(crate::dbus::Error::NotFound(_)) => {
+                #[cfg(feature = "tracing")]
+                tracing::debug!("Default collection doesn't exists, trying to create it");
+                service
+                    .create_collection("Login", Some(DEFAULT_COLLECTION))
+                    .await
+            }
+            Err(e) => Err(e),
+        }?;
+        Ok(Self::DBus(collection))
     }
 
     /// Unlock the used collection if using the Secret service.
diff --git a/src/migration.rs b/src/migration.rs
index d1b5cb5d8..bbdf89381 100644
--- a/src/migration.rs
+++ b/src/migration.rs
@@ -9,7 +9,15 @@ use crate::{dbus::Service, portal::Keyring, Result};
 /// Secret Service.
 pub async fn migrate(attributes: Vec<HashMap<&str, &str>>, replace: bool) -> Result<()> {
     let service = Service::new(crate::dbus::Algorithm::Encrypted).await?;
-    let file_backend = Keyring::load_default().await?;
+    let file_backend = match Keyring::load_default().await {
+        Ok(portal) => Ok(portal),
+        Err(crate::portal::Error::PortalNotAvailable) => {
+            #[cfg(feature = "tracing")]
+            tracing::debug!("Portal not available, no migration to do");
+            return Ok(());
+        }
+        Err(err) => Err(err),
+    }?;
 
     let collection = service.default_collection().await?;
     let mut all_items = Vec::default();
diff --git a/src/portal/error.rs b/src/portal/error.rs
index 1010875c3..006cd7419 100644
--- a/src/portal/error.rs
+++ b/src/portal/error.rs
@@ -27,6 +27,9 @@ pub enum Error {
     PortalBus(zbus::Error),
     /// Portal request has been cancelled.
     CancelledPortalRequest,
+    /// If the portal is not available on the host.
+    /// Can happen if the host has an old xdg-desktop-portal
+    PortalNotAvailable,
 }
 
 impl From<zvariant::Error> for Error {
@@ -76,6 +79,7 @@ impl std::fmt::Display for Error {
             Error::TargetFileChanged(e) => write!(f, "The target file has changed {e}"),
             Error::PortalBus(e) => write!(f, "Portal communication failed {e}"),
             Error::CancelledPortalRequest => write!(f, "Portal request was cancelled"),
+            Error::PortalNotAvailable => write!(f, "xdg-desktop-portal is too old on the host"),
         }
     }
 }
diff --git a/src/portal/secret.rs b/src/portal/secret.rs
index 28899d3a8..6321c100c 100644
--- a/src/portal/secret.rs
+++ b/src/portal/secret.rs
@@ -35,7 +35,7 @@ pub struct SecretProxy<'a>(zbus::Proxy<'a>);
 
 impl<'a> SecretProxy<'a> {
     /// Create a new instance of [`SecretProxy`].
-    pub async fn new(connection: &zbus::Connection) -> Result<SecretProxy<'a>, Error> {
+    pub async fn new(connection: &zbus::Connection) -> Result<SecretProxy<'a>, zbus::Error> {
         let proxy = zbus::ProxyBuilder::new_bare(connection)
             .interface("org.freedesktop.portal.Secret")?
             .path("/org/freedesktop/portal/desktop")?
@@ -102,7 +102,11 @@ pub async fn retrieve() -> Result<Vec<u8>, Error> {
     let connection = zbus::Connection::session().await?;
     #[cfg(feature = "tracing")]
     tracing::debug!("Retrieve service key using org.freedesktop.portal.Secrets");
-    let proxy = SecretProxy::new(&connection).await?;
+    let proxy = match SecretProxy::new(&connection).await {
+        Ok(proxy) => Ok(proxy),
+        Err(zbus::Error::MethodError(_, _, _)) => Err(Error::PortalNotAvailable),
+        Err(e) => Err(e.into()),
+    }?;
 
     let (mut x1, x2) = std::os::unix::net::UnixStream::pair()?;
     proxy.retrieve_secret(&x2).await?;


Test patch: