proton-vpn-gtk-app icon indicating copy to clipboard operation
proton-vpn-gtk-app copied to clipboard

Locked Gnome keyring causes race condition and authentication denied

Open alexandrevicenzi opened this issue 10 months ago • 10 comments

We are happy to answer your questions about the code or discuss technical ideas.

Please complete the following checklist (by adding [x]):

  • [x] I have searched open and closed issues for duplicates
  • [x] This isn't a feature request
  • [ ] This is not a report about my app not working as expected

There's an issue when Gnome keyring is locked and it can be summarized as this:

  1. The Gnome keyring is locked
  2. Open the Proton VPN app
  3. Attempt to Quick Connect
  4. Proton attempts to connect
  5. nmcli prompts to unlock Gnome keyring
  6. While typing the keyring password Proton starts the network
  7. nmcli has no knowledge of any passwords because the keyring is locked and prompts to type OpenVPN credentials (see image below)
  8. Cancel OpenVPN credentials password request
  9. Finish typing the password, this will unlock Gnome keyring
  10. VPN connection failed with Authentication Error and internet access has been blocked
  11. Cancel current connection
  12. Attempt to Quick Connect
  13. Now the connection works because the Gnome keyring has been unlocked

image

I tried to trace the problem, but with so many callbacks and async everywhere it is hard.

There's one solution that works, but it might not be the best.

Here is my solution:

  1. In the file proton/vpn/backend/linux/networkmanager/core/networkmanager.py
  2. On the start method
  3. Make a keyring call, this will prompt it to unlock it
  4. Type the password
  5. This will unlock Gnome keyring
  6. Connection works as expected

As the credentials and other data are stored in the keyring, ideally, in every new connection it should be checked if the keyring is locked or not. The user can manually lock it or another application can lock it.

What I have done in the code is:

diff --git a/proton/vpn/backend/linux/networkmanager/core/networkmanager.py b/proton/vpn/backend/linux/networkmanager/core/networkmanager.py
index 8fd7e55..a5b4149 100644
--- a/proton/vpn/backend/linux/networkmanager/core/networkmanager.py
+++ b/proton/vpn/backend/linux/networkmanager/core/networkmanager.py
@@ -116,6 +116,13 @@ class LinuxNetworkManager(VPNConnection):
             self._notify_subscribers(events.Disconnected(EventContext(connection=self)))
             return
 
+        try:
+            import keyring
+            k = keyring.get_keyring()
+            k.get_credential('ProtonVPN', 'ProtonUser')
+        except:
+            pass
+
         try:
             future_vpn_connection = self.nm_client.start_connection_async(connection)
             vpn_connection = await loop.run_in_executor(

This solves my problem, but if this would be a valid solution, possibly it should be a call to Dbus.

Maybe the issue is somewhere else, it feels like a race condition, the VPN connection should not start while I type the keyring password to unlock the VPN credentials.

With some help, I could possibly patch this properly.

alexandrevicenzi avatar Apr 02 '24 16:04 alexandrevicenzi