diff --git a/tests/utils/test_main.py b/tests/utils/test_main.py index bd01019..0b0d7f7 100644 --- a/tests/utils/test_main.py +++ b/tests/utils/test_main.py @@ -10,7 +10,6 @@ import click from click.testing import CliRunner -from tempfile import mkstemp import os import stat import pytest @@ -111,33 +110,33 @@ def test_get_password_from_system_keyring(monkeypatch): assert _password == password -def test_get_password_from_evalcmd(): +def test_get_password_from_command(tmpdir): username = 'my_username' resource = 'http://example.com' password = 'testpassword' + filename = 'command.sh' - fd, temp_path = mkstemp() - os.close(fd) - fp = open(temp_path, 'w') - fp.write('#!/bin/sh\n' + filepath = str(tmpdir) + '/' + filename + f = open(filepath, 'w') + f.write('#!/bin/sh\n' '[ "$1" != "my_username" ] && exit 1\n' '[ "$2" != "example.com" ] && exit 1\n' 'echo "{}"'.format(password)) - fp.close() - st = os.stat(temp_path) - os.chmod(temp_path, st.st_mode | stat.S_IEXEC) + f.close() + + st = os.stat(filepath) + os.chmod(filepath, st.st_mode | stat.S_IEXEC) @doubleclick.click.command() @doubleclick.click.pass_context def fake_app(ctx): - ctx.obj = {'config' : ({'passwordeval' : temp_path},{},{})} + ctx.obj = {'config' : ({'passwordeval' : filepath},{},{})} _password = utils.get_password(username, resource) assert _password == password runner = CliRunner() result = runner.invoke(fake_app) assert not result.exception - os.remove(temp_path) def test_get_password_from_prompt(): diff --git a/vdirsyncer/utils/__init__.py b/vdirsyncer/utils/__init__.py index 8c86d25..57815b7 100644 --- a/vdirsyncer/utils/__init__.py +++ b/vdirsyncer/utils/__init__.py @@ -119,8 +119,8 @@ def get_password(username, resource, _lock=threading.Lock()): with _lock: host = urlparse.urlsplit(resource).hostname - for func in (_password_from_cache, _password_from_netrc, - _password_from_keyring, _password_from_evalcmd): + for func in (_password_from_command, _password_from_cache, + _password_from_netrc, _password_from_keyring): password = func(username, host) if password is not None: logger.debug('Got password for {} from {}' @@ -168,28 +168,27 @@ def _password_from_keyring(username, host): return keyring.get_password(password_key_prefix + host, username) -def _password_from_evalcmd(username, host): - '''evalcmd''' +def _password_from_command(username, host): + '''command''' import subprocess try: general, _, _ = ctx.obj['config'] - _evalcmd = general.get('passwordeval', '') - except (KeyError, IndexError): + _command = general['passwordeval'].split() + except (IndexError, KeyError): return None - if _evalcmd == '': - return None - - evalcmd = expand_path(_evalcmd) + command = [expand_path(_command[0])] + if len(_command) > 1: + command += _command[1:] try: - proc = subprocess.Popen([evalcmd, username, host], + proc = subprocess.Popen(command + [username, host], stdout=subprocess.PIPE) - password = proc.stdout.read().strip() - except OSError, e: - logger.debug('Failed to execute evalcmd: {}\n{}'. - format(evalcmd, str(e))) + password = proc.stdout.read().decode('utf-8').strip() + except OSError as e: + logger.debug('Failed to execute command: {}\n{}'. + format(" ".join(command), str(e))) return None return password