for details on the pinentry interface.
Alternatively, you can just watch the logs and guess ;). Here's a
- trace when driven by GnuPG 2.0.17 (libgcrypt 1.4.6)::
+ trace when driven by GnuPG 2.0.28 (libgcrypt 1.6.3)::
S: OK Your orders please
C: OPTION grab
S: OK
C: OPTION lc-messages=en_US.UTF-8
S: OK
+ C: OPTION allow-external-password-cache
+ S: OK
C: OPTION default-ok=_OK
S: OK
C: OPTION default-cancel=_Cancel
S: OK
+ C: OPTION default-yes=_Yes
+ S: OK
+ C: OPTION default-no=_No
+ S: OK
C: OPTION default-prompt=PIN:
S: OK
- C: OPTION touch-file=/tmp/gpg-7lElMX/S.gpg-agent
+ C: OPTION default-pwmngr=_Save in password manager
+ S: OK
+ C: OPTION default-cf-visi=Do you really want to make your passphrase visible on the screen?
+ S: OK
+ C: OPTION default-tt-visi=Make passphrase visible
+ S: OK
+ C: OPTION default-tt-hide=Hide passphrase
S: OK
C: GETINFO pid
S: D 14309
S: OK
+ C: SETKEYINFO u/S9464F2C2825D2FE3
+ S: OK
C: SETDESC Enter passphrase%0A
S: OK
C: SETPROMPT Passphrase
S: OK
C: BYE
S: OK closing connection
-
- Some drivers (e.g. ``gpgme``) have ``gpg-agent`` set ``ttyname``
- to the terminal running ``gpgme``. I don't like this, because the
- pinentry program doesn't always play nicely with whatever is going
- on in that terminal. I'd rather have a free terminal that had
- just been running Bash, and I export ``GPG_TTY`` to point to the
- desired terminal. To ignore the requested ``ttyname`` and use
- whatever is in ``GPG_TTY``, initialize with ``override_ttyname``
- set to ``True``.
"""
_digit_regexp = _re.compile(r'\d+')
_tpgrp_regexp = _re.compile(r'\d+ \(\S+\) . \d+ \d+ \d+ \d+ (\d+)')
def __init__(self, name='pinentry', strict_options=False,
- single_request=True, override_ttyname=False, **kwargs):
+ single_request=True, **kwargs):
self.strings = {}
self.connection = {}
super(PinEntry, self).__init__(
name=name, strict_options=strict_options,
single_request=single_request, **kwargs)
self.valid_options.append('ttyname')
- self.override_ttyname = override_ttyname
def reset(self):
super(PinEntry, self).reset()
def _connect(self):
self.logger.info('connecting to user')
self.logger.debug('options:\n{}'.format(_pprint.pformat(self.options)))
- tty_name = None
- if self.override_ttyname:
- tty_name = _os.getenv('GPG_TTY')
- if tty_name:
- self.logger.debug('override ttyname with {}'.format(tty_name))
- else:
- self.logger.debug(
- 'GPG_TTY not set, fallback to ttyname option')
- if not tty_name:
- tty_name = self.options.get('ttyname', None)
+ tty_name = self.options.get('ttyname', None)
if tty_name:
self.connection['tpgrp'] = self._get_pgrp(tty_name)
self.logger.info(
def _handle_GETINFO(self, arg):
if arg == 'pid':
- yield _common.Response('D', str(_os.getpid()))
+ yield _common.Response('D', str(_os.getpid()).encode('ascii'))
elif arg == 'version':
- yield _common.Response('D', __version__)
+ yield _common.Response('D', __version__.encode('ascii'))
else:
raise _error.AssuanError(message='Invalid parameter')
yield _common.Response('OK')
+ def _handle_SETKEYINFO(self, arg):
+ self.strings['key info'] = arg
+ yield _common.Response('OK')
+
def _handle_SETDESC(self, arg):
self.strings['description'] = arg
yield _common.Response('OK')
This indicator is updated as the passphrase is typed. The
clients needs to implement an inquiry named "QUALITY" which
- gets passed the current passpharse (percent-plus escaped) and
+ gets passed the current passphrase (percent-plus escaped) and
should send back a string with a single numerical vauelue
between -100 and 100. Negative values will be displayed in
red.
S: OK
With STRING being a percent escaped string shown as the tooltip.
+
+ Here is a real world example of these commands in use:
+
+ C: SETQUALITYBAR Quality%3a
+ S: OK
+ C: SETQUALITYBAR_TT The quality of the text entered above.%0aPlease ask your administrator for details about the criteria.
+ S: OK
"""
- raise NotImplementedError()
+ self.strings['qualitybar'] = arg
+ yield _common.Response('OK')
+
+ def _handle_SETQUALITYBAR_TT(self, arg):
+ self.strings['qualitybar_tooltip'] = arg
+ yield _common.Response('OK')
def _handle_GETPIN(self, arg):
try:
self._connect()
self._write(self.strings['description'])
+ if 'key info' in self.strings:
+ self._write('key: {}'.format(self.strings['key info']))
+ if 'qualitybar' in self.strings:
+ self._write(self.strings['qualitybar'])
pin = self._prompt(self.strings['prompt'], add_colon=False)
finally:
self._disconnect()
- yield _common.Response('D', pin)
+ yield _common.Response('D', pin.encode('ascii'))
yield _common.Response('OK')
def _handle_CONFIRM(self, arg):
import logging
import traceback
- parser = argparse.ArgumentParser(description=__doc__, version=__version__)
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument(
+ '-v', '--version', action='version',
+ version='%(prog)s {}'.format(__version__))
parser.add_argument(
'-V', '--verbose', action='count', default=0,
help='increase verbosity')
args = parser.parse_args()
- p = PinEntry(override_ttyname=True)
+ p = PinEntry()
if args.verbose:
p.logger.setLevel(max(