From a098d83e92fa807d95ee160b1506c4561b28eb2b Mon Sep 17 00:00:00 2001 From: Michał Górny Date: Sat, 29 Apr 2023 15:57:58 +0200 Subject: openpgp: Support specifying connection timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support specifying connection timeout for key refresh operations. Set the default to 3 minutes. This affects both WKD requests (via requests, supports sub-second timeouts) and GPG requests (via dirmngr, supports second precision). Closes: https://github.com/projg2/gemato/issues/26 Signed-off-by: Michał Górny --- gemato/cli.py | 11 ++++++++++- gemato/openpgp.py | 26 +++++++++++++++++++++----- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/gemato/cli.py b/gemato/cli.py index 7c67a35..276b6b0 100644 --- a/gemato/cli.py +++ b/gemato/cli.py @@ -99,12 +99,20 @@ class BaseOpenPGPMixin: def add_options(self, subp): super().add_options(subp) + default_timeout = 180 + subp.add_argument( '-K', '--openpgp-key', help='Use only the OpenPGP key(s) from a specific file') subp.add_argument( '--proxy', help='Use HTTP proxy') + subp.add_argument( + "--timeout", + default=default_timeout, + type=float, + help="Connection timeout (for WKD requests, in seconds, " + f"default: {default_timeout})") def parse_args(self, args, argp): super().parse_args(args, argp) @@ -116,7 +124,8 @@ class BaseOpenPGPMixin: else: env_class = OpenPGPSystemEnvironment self.openpgp_env = env_class(debug=args.log_level == logging.DEBUG, - proxy=args.proxy) + proxy=args.proxy, + timeout=args.timeout) if args.openpgp_key is not None: with open(args.openpgp_key, 'rb') as f: diff --git a/gemato/openpgp.py b/gemato/openpgp.py index b1b8eb6..483e15f 100644 --- a/gemato/openpgp.py +++ b/gemato/openpgp.py @@ -10,6 +10,7 @@ import enum import errno import hashlib import logging +import math import os import os.path import shutil @@ -112,7 +113,7 @@ class SystemGPGEnvironment: (user's home directory or GNUPGHOME). """ - def __init__(self, debug=False, proxy=None): + def __init__(self, debug=False, proxy=None, timeout=None): self.debug = debug self._trusted_keys = set() @@ -402,9 +403,10 @@ class IsolatedGPGEnvironment(SystemGPGEnvironment): or use as a context manager (via 'with'). """ - def __init__(self, debug=False, proxy=None): + def __init__(self, debug=False, proxy=None, timeout=None): super().__init__(debug=debug) self.proxy = proxy + self.timeout = timeout self._home = tempfile.mkdtemp(prefix='gemato.') with open(os.path.join(self._home, 'dirmngr.conf'), 'w') as f: @@ -423,6 +425,19 @@ standard-resolver log-file {os.path.join(self._home, 'dirmngr.log')} debug-level guru ''') + + if timeout is not None: + # GPG doesn't accept sub-second timeouts + gpg_timeout = math.ceil(timeout) + f.write(f""" +# respect user-specified timeouts +resolver-timeout {gpg_timeout} +connect-timeout {gpg_timeout} +""") + + with open(os.path.join(self._home, 'dirmngr.conf'), 'r') as f: + print(f.read()) + with open(os.path.join(self._home, 'gpg.conf'), 'w') as f: f.write('''# autogenerated by gemato @@ -445,7 +460,8 @@ debug-level guru self.close() def clone(self): - return IsolatedGPGEnvironment(debug=self.debug, proxy=self.proxy) + return IsolatedGPGEnvironment(debug=self.debug, proxy=self.proxy, + timeout=self.timeout) def close(self): if self._home is not None: @@ -573,7 +589,7 @@ debug-level guru for a in addrs: url = get_wkd_url(a) try: - resp = requests.get(url, proxies=proxies) + resp = requests.get(url, proxies=proxies, timeout=self.timeout) resp.raise_for_status() except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError, @@ -660,7 +676,7 @@ class PGPyEnvironment: __slots__ = ['debug', 'keyring', 'proxy'] - def __init__(self, debug=False, proxy=None): + def __init__(self, debug=False, proxy=None, timeout=None): if pgpy is None: raise OpenPGPNoImplementation('install PGPy') self.debug = debug -- cgit v1.2.3