diff --git a/libagent/device/ui/__init__.py b/libagent/device/ui/__init__.py index 9279d8e..71b6535 100644 --- a/libagent/device/ui/__init__.py +++ b/libagent/device/ui/__init__.py @@ -30,37 +30,36 @@ def _create_default_options_getter(): class UI(object): """UI for PIN/passphrase entry (for TREZOR devices).""" - def __init__(self): + def __init__(self, device_type, config): """C-tor.""" + default_pinentry = 'pinentry' # by default, use GnuPG pinentry tool + self.pin_entry_binary = config.get('pin_entry_binary', + default_pinentry) + self.passphrase_entry_binary = config.get('passphrase_entry_binary', + default_pinentry) self.options_getter = _create_default_options_getter() - self.pin_entry_binary = 'pinentry' - self.passphrase_entry_binary = 'pinentry' - - @classmethod - def from_config_dict(cls, d): - """Simple c-tor from configuration dictionary.""" - obj = cls() - obj.pin_entry_binary = d.get('pin_entry_binary', - obj.pin_entry_binary) - obj.passphrase_entry_binary = d.get('passphrase_entry_binary', - obj.passphrase_entry_binary) - return obj + self.device_name = device_type.__name__ def get_pin(self): """Ask the user for (scrambled) PIN.""" - return pinentry.interact( + description = ( 'Use the numeric keypad to describe number positions.\n' 'The layout is:\n' ' 7 8 9\n' ' 4 5 6\n' - ' 1 2 3\n' - 'Please enter PIN:', + ' 1 2 3') + return pinentry.interact( + title='{} PIN'.format(self.device_name), + prompt='PIN:', + description=description, binary=self.pin_entry_binary, options=self.options_getter()) def get_passphrase(self): """Ask the user for passphrase.""" return pinentry.interact( - 'Please enter passphrase:', + title='{} passphrase'.format(self.device_name), + prompt='Passphrase:', + description=None, binary=self.passphrase_entry_binary, options=self.options_getter()) diff --git a/libagent/device/ui/pinentry.py b/libagent/device/ui/pinentry.py index 5c90ee1..0d308d4 100644 --- a/libagent/device/ui/pinentry.py +++ b/libagent/device/ui/pinentry.py @@ -26,7 +26,7 @@ def expect(p, prefixes): raise ValueError('Unexpected response: {}'.format(resp)) -def interact(description, binary, options): +def interact(title, description, prompt, binary, options): """Use GPG pinentry program to interact with the user.""" p = subprocess.Popen(args=[binary], stdin=subprocess.PIPE, @@ -34,10 +34,20 @@ def interact(description, binary, options): env=os.environ) expect(p, [b'OK']) - description = libagent.gpg.agent.serialize(description.encode('ascii')) - write(p, b'SETDESC ' + description + b'\n') + title = libagent.gpg.agent.serialize(title.encode('ascii')) + write(p, b'SETTITLE ' + title + b'\n') expect(p, [b'OK']) + if description: + description = libagent.gpg.agent.serialize(description.encode('ascii')) + write(p, b'SETDESC ' + description + b'\n') + expect(p, [b'OK']) + + if prompt: + prompt = libagent.gpg.agent.serialize(prompt.encode('ascii')) + write(p, b'SETPROMPT ' + prompt + b'\n') + expect(p, [b'OK']) + log.debug('setting %d options', len(options)) for opt in options: write(p, b'OPTION ' + opt + b'\n') diff --git a/libagent/gpg/__init__.py b/libagent/gpg/__init__.py index a96eeb2..9e2597e 100644 --- a/libagent/gpg/__init__.py +++ b/libagent/gpg/__init__.py @@ -226,7 +226,8 @@ def run_agent(device_type): env = {'GNUPGHOME': args.homedir} sock_path = keyring.get_agent_sock_path(env=env) pubkey_bytes = keyring.export_public_keys(env=env) - device_type.ui = device.ui.UI.from_config_dict(vars(args)) + device_type.ui = device.ui.UI(device_type=device_type, + config=vars(args)) handler = agent.Handler(device=device_type(), pubkey_bytes=pubkey_bytes) with server.unix_domain_socket_server(sock_path) as sock: for conn in agent.yield_connections(sock): @@ -279,6 +280,6 @@ def main(device_type): p.set_defaults(func=run_unlock) args = parser.parse_args() - device_type.ui = device.ui.UI.from_config_dict(vars(args)) + device_type.ui = device.ui.UI(device_type=device_type, config=vars(args)) return args.func(device_type=device_type, args=args) diff --git a/libagent/ssh/__init__.py b/libagent/ssh/__init__.py index c264d92..8c5c894 100644 --- a/libagent/ssh/__init__.py +++ b/libagent/ssh/__init__.py @@ -273,7 +273,7 @@ def main(device_type): sys.stdin.close() # override default PIN/passphrase entry tools (relevant for TREZOR/Keepkey): - device_type.ui = device.ui.UI.from_config_dict(vars(args)) + device_type.ui = device.ui.UI(device_type=device_type, config=vars(args)) conn = JustInTimeConnection( conn_factory=lambda: client.Client(device_type()),