[weboob] [PATCH 1/1] Use gpg by default rather than gpgv for signature verification

Mickaël Thomas mickael9 at gmail.com
Tue Dec 29 19:54:27 CET 2015


Current gpgv has a bug where the gpgv command does not work

A patch has already been sent upstream :
https://lists.gnupg.org/pipermail/gnupg-devel/2015-December/030623.html

Using gpg --verify rather than gpgv fixes the issue.
If gpg is not found, gpgv is used as a fallback.
---
 weboob/applications/weboobrepos/weboobrepos.py | 14 ++---------
 weboob/core/repositories.py                    | 35 +++++++++++++++-----------
 weboob/tools/misc.py                           | 28 ++++++++++++++++++++-
 3 files changed, 49 insertions(+), 28 deletions(-)

diff --git a/weboob/applications/weboobrepos/weboobrepos.py b/weboob/applications/weboobrepos/weboobrepos.py
index eb1034d..b243e3e 100644
--- a/weboob/applications/weboobrepos/weboobrepos.py
+++ b/weboob/applications/weboobrepos/weboobrepos.py
@@ -31,6 +31,7 @@ from contextlib import closing
 from weboob.core.repositories import Repository
 
 from weboob.tools.application.repl import ReplApplication
+from weboob.tools.misc import find_exe
 
 
 __all__ = ['WeboobRepos']
@@ -103,7 +104,7 @@ class WeboobRepos(ReplApplication):
 
         if r.signed:
             sigfiles = [r.KEYRING, Repository.INDEX]
-            gpg = self._find_gpg()
+            gpg = find_exe('gpg2') or find_exe('gpg')
             if not gpg:
                 raise Exception('Unable to find the gpg executable.')
             krname = os.path.join(repo_path, r.KEYRING)
@@ -209,17 +210,6 @@ class WeboobRepos(ReplApplication):
                     os.utime(sigpath, (file_mtime, file_mtime))
             print('Signatures are up to date')
 
-    @staticmethod
-    def _find_gpg():
-        if os.getenv('GPG_EXECUTABLE'):
-            return os.getenv('GPG_EXECUTABLE')
-        paths = os.getenv('PATH', os.defpath).split(os.pathsep)
-        for path in paths:
-            for ex in ('gpg2', 'gpg'):
-                fpath = os.path.join(path, ex)
-                if os.path.exists(fpath) and os.access(fpath, os.X_OK):
-                    return fpath
-
     def _archive_excludes(self, filename):
         # Skip *.pyc files in tarballs.
         if filename.endswith('.pyc'):
diff --git a/weboob/core/repositories.py b/weboob/core/repositories.py
index 5afde3e..ac22d35 100644
--- a/weboob/core/repositories.py
+++ b/weboob/core/repositories.py
@@ -35,7 +35,7 @@ from io import BytesIO
 from weboob.exceptions import BrowserHTTPError, BrowserHTTPNotFound
 from .modules import LoadedModule
 from weboob.tools.log import getLogger
-from weboob.tools.misc import get_backtrace, to_unicode
+from weboob.tools.misc import get_backtrace, to_unicode, find_exe
 try:
     from ConfigParser import RawConfigParser, DEFAULTSECT
 except ImportError:
@@ -578,7 +578,7 @@ class Repositories(object):
         for name in os.listdir(self.repos_dir):
             os.remove(os.path.join(self.repos_dir, name))
 
-        gpgv = Keyring.find_gpgv()
+        gpg_found = Keyring.find_gpg() or Keyring.find_gpgv()
         for line in self._parse_source_list():
             progress.progress(0.0, 'Getting %s' % line)
             repository = Repository(line)
@@ -588,11 +588,11 @@ class Repositories(object):
             keyring_path = os.path.join(self.keyrings_dir, filename)
             try:
                 repository.retrieve_index(self.browser, repo_path)
-                if gpgv:
+                if gpg_found:
                     repository.retrieve_keyring(self.browser, keyring_path, progress)
                 else:
-                    progress.error('Cannot find gpgv to check for repository authenticity.\n'
-                                    'You should install GPG for better security.')
+                    progress.error('Cannot find gpg or gpgv to check for repository authenticity.\n'
+                                   'You should install GPG for better security.')
             except RepositoryUnavailable as e:
                 progress.error('Unable to load repository: %s' % e)
             else:
@@ -688,7 +688,7 @@ class Repositories(object):
             raise ModuleInstallError('Unable to fetch module: %s' % e)
 
         # Check signature
-        if module.signed and Keyring.find_gpgv():
+        if module.signed and (Keyring.find_gpg() or Keyring.find_gpgv()):
             progress.progress(0.5, 'Checking module authenticity...')
             sig_data = self.browser.open(posixpath.join(module.url + '.sig')).content
             keyring_path = os.path.join(self.keyrings_dir, self.url2filename(module.repo_url))
@@ -769,21 +769,26 @@ class Keyring(object):
 
     @staticmethod
     def find_gpgv():
-        if os.getenv('GPGV_EXECUTABLE'):
-            return os.getenv('GPGV_EXECUTABLE')
-        paths = os.getenv('PATH', os.defpath).split(os.pathsep)
-        for path in paths:
-            for ex in ('gpgv2', 'gpgv', 'gpgv2.exe', 'gpgv.exe'):
-                fpath = os.path.join(path, ex)
-                if os.path.exists(fpath) and os.access(fpath, os.X_OK):
-                    return fpath
+        return find_exe('gpgv2') or find_exe('gpgv')
+
+    @staticmethod
+    def find_gpg():
+        return find_exe('gpg2') or find_exe('gpg')
 
     def is_valid(self, data, sigdata):
         """
         Check if the data is signed by an accepted key.
         data and sigdata should be strings.
         """
+        gpg = self.find_gpg()
         gpgv = self.find_gpgv()
+
+        if gpg:
+            verify_command = [gpg, '--verify', '--no-options',
+                              '--no-default-keyring', '--quiet']
+        elif gpgv:
+            verify_command = [gpgv]
+
         from tempfile import NamedTemporaryFile
         with NamedTemporaryFile(suffix='.sig', delete=False) as sigfile:
             temp_filename = sigfile.name
@@ -795,7 +800,7 @@ class Keyring(object):
                 sigfile.flush()  # very important
                 assert isinstance(data, basestring)
                 # Yes, all of it is necessary
-                proc = subprocess.Popen([gpgv,
+                proc = subprocess.Popen(verify_command + [
                         '--status-fd', '1',
                         '--keyring', os.path.realpath(self.path),
                         os.path.realpath(sigfile.name),
diff --git a/weboob/tools/misc.py b/weboob/tools/misc.py
index f49d83e..fe01d77 100644
--- a/weboob/tools/misc.py
+++ b/weboob/tools/misc.py
@@ -29,7 +29,7 @@ from .compat import unicode
 
 
 __all__ = ['get_backtrace', 'get_bytes_size', 'iter_fields',
-            'to_unicode', 'limit']
+            'to_unicode', 'limit', 'find_exe']
 
 
 def get_backtrace(empty="Empty backtrace."):
@@ -148,3 +148,29 @@ def ratelimit(group, delay):
         sleep(delay - offset)
 
     os.utime(path, None)
+
+
+def find_exe(basename):
+    """
+    Find the path to an executable by its base name (such as 'gpg').
+
+    The executable can be overriden using an environment variable in the form
+    `NAME_EXECUTABLE` where NAME is the specified base name in upper case.
+
+    If the environment variable is not provided, the PATH will be searched
+    both without and with a ".exe" suffix for Windows compatibility.
+
+    If the executable can not be found, None is returned.
+    """
+
+    env_exe = os.getenv('%s_EXECUTABLE' % basename.upper())
+    if env_exe and os.path.exists(env_exe) and os.access(env_exe, os.X_OK):
+        return env_exe
+
+    paths = os.getenv('PATH', os.defpath).split(os.pathsep)
+    for path in paths:
+        for ex in (basename, basename + '.exe'):
+            fpath = os.path.join(path, ex)
+            if os.path.exists(fpath) and os.access(fpath, os.X_OK):
+                return fpath
+
-- 
2.6.4




More information about the weboob mailing list