Browse Source

Simplistic (enforced) ASKPASS helper

The new `gooey-askpass` command implements the traditional SSH_ASKPASS
API. It opens a simple input dialog with the given prompt, collects
input, and writes it to `stdout`.

Within Gooey this helper is not the enforced method for anything that
honors a normal SSH_ASKPASS setup -- this includes Git and SSH.

So any such requests should now show up in the GUI, rather than
be hidden in the terminal.

Closes datalad/datalad-gooey#177
Michael Hanke 1 year ago
parent
commit
042577d10c
5 changed files with 59 additions and 4 deletions
  1. 2 0
      datalad_gooey/__init__.py
  2. 16 3
      datalad_gooey/app.py
  3. 35 0
      datalad_gooey/askpass.py
  4. 2 0
      docs/source/index.rst
  5. 4 1
      setup.cfg

+ 2 - 0
datalad_gooey/__init__.py

@@ -13,6 +13,8 @@ command_suite = (
     "Gooey (GUI)",
     [
         ('datalad_gooey.gooey', 'Gooey'),
+        ('datalad_gooey.askpass', 'GooeyAskPass',
+         'gooey-askpass', 'gooey_askpass'),
         ('datalad_gooey.lsdir', 'GooeyLsDir', 'gooey-lsdir', 'gooey_lsdir'),
         ('datalad_gooey.status_light', 'GooeyStatusLight',
          'gooey-status-light', 'gooey_status_light'),

+ 16 - 3
datalad_gooey/app.py

@@ -71,11 +71,23 @@ class GooeyApp(QObject):
         # we cannot handle ANSI coloring
         dlcfg.set('datalad.ui.color', 'off', scope='override', force=True)
 
+        # capture what env vars we modified, None means did not exist
+        self._restore_env = {
+            name: environ.get(name)
+            for name in (
+                'GIT_TERMINAL_PROMPT',
+                'SSH_ASKPASS_REQUIRE',
+                'SSH_ASKPASS',
+            )
+        }
         # prevent any terminal-based interaction of Git
         # do it here, not just for command execution to also catch any possible
         # ad-hoc Git calls
-        self._gittermprompt = environ.get('GIT_TERMINAL_PROMPT')
         environ['GIT_TERMINAL_PROMPT'] = '0'
+        # force asking passwords via Gooey
+        # we use SSH* because also Git falls back onto it
+        environ['SSH_ASKPASS_REQUIRE'] = 'force'
+        environ['SSH_ASKPASS'] = 'datalad-gooey-askpass'
 
         # setup themeing before the first dialog goes up
         self._setup_looknfeel()
@@ -182,8 +194,9 @@ class GooeyApp(QObject):
     def deinit(self):
         dlui.ui.set_backend(self._prev_ui_backend)
         # restore any possible term prompt setup
-        if self._gittermprompt:
-            environ['GIT_TERMINAL_PROMPT'] = self._gittermprompt
+        for var, val in self._restore_env.items():
+            if val is not None:
+                environ[var] = val
 
     #@cached_property not available for PY3.7
     @property

+ 35 - 0
datalad_gooey/askpass.py

@@ -0,0 +1,35 @@
+"""DataLad GUI password entry helper"""
+
+__docformat__ = 'restructuredtext'
+
+import logging
+import sys
+
+from datalad.interface.base import Interface
+from datalad.interface.base import build_doc
+
+
+lgr = logging.getLogger('datalad.ext.gooey.askpass')
+
+
+@build_doc
+class GooeyAskPass(Interface):
+    """Internal helper for datalad-gooey"""
+
+    @staticmethod
+    def __call__():
+        # internal import to keep unconditional dependencies low
+        from PySide6.QtWidgets import (
+            QApplication,
+            QInputDialog,
+        )
+
+        QApplication(sys.argv)
+        cred, ok = QInputDialog.getText(
+            None,
+            'DataLad Gooey',
+            sys.argv[1],
+        )
+        if not ok:
+            sys.exit(2)
+        sys.stdout.write(cred)

+ 2 - 0
docs/source/index.rst

@@ -16,6 +16,7 @@ High-level API commands
    :toctree: generated
 
    gooey
+   gooey_askpass
    gooey_lsdir
    gooey_status_light
 
@@ -27,6 +28,7 @@ Command line reference
    :maxdepth: 1
 
    generated/man/datalad-gooey
+   generated/man/datalad-gooey-askpass
    generated/man/datalad-gooey-lsdir
    generated/man/datalad-gooey-status-light
 

+ 4 - 1
setup.cfg

@@ -42,7 +42,10 @@ datalad.extensions =
     gooey = datalad_gooey:command_suite
 # install the GUI starter as a direct entrypoint to avoid the datalad CLI
 # overhead
-gui_scripts = datalad-gooey = datalad_gooey.app:main
+gui_scripts =
+    datalad-gooey = datalad_gooey.app:main
+console_scripts =
+    datalad-gooey-askpass = datalad_gooey.askpass:GooeyAskPass.__call__
 
 [versioneer]
 # See the docstring in versioneer.py for instructions. Note that you must