Skip to content

Commit

Permalink
Merge pull request #117 from vimbaer/passwordeval
Browse files Browse the repository at this point in the history
New general config option: passwordeval
  • Loading branch information
untitaker committed Sep 13, 2014
2 parents 9dbb359 + 23a4a96 commit 3ad598c
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 5 deletions.
32 changes: 31 additions & 1 deletion tests/utils/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import click

from click.testing import CliRunner
import os
import stat
import pytest
import requests

Expand Down Expand Up @@ -108,6 +110,35 @@ def get_password(self, resource, _username):
assert _password == password


def test_get_password_from_command(tmpdir):
username = 'my_username'
resource = 'http://example.com'
password = 'testpassword'
filename = 'command.sh'

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))
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' : filepath},{},{})}
_password = utils.get_password(username, resource)
assert _password == password

runner = CliRunner()
result = runner.invoke(fake_app)
assert not result.exception


def test_get_password_from_prompt():
getpass_calls = []

Expand Down Expand Up @@ -187,7 +218,6 @@ def fake_app(ctx):
]



def test_get_class_init_args():
class Foobar(object):
def __init__(self, foo, bar, baz=None):
Expand Down
2 changes: 1 addition & 1 deletion vdirsyncer/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
PROJECT_HOME = 'https://github.com/untitaker/vdirsyncer'
DOCS_HOME = 'https://vdirsyncer.readthedocs.org/en/latest'

GENERAL_ALL = set(['processes', 'status_path'])
GENERAL_ALL = set(['processes', 'status_path', 'passwordeval'])
GENERAL_REQUIRED = set(['status_path'])


Expand Down
34 changes: 31 additions & 3 deletions vdirsyncer/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,9 @@ def get_password(username, resource, _lock=threading.Lock()):
1. read password from netrc (and only the password, username
in netrc will be ignored)
2. read password from keyring (keyring needs to be installed)
3a ask user for the password
3. read password from the command passed as passwordeval in the
general config section with username and host as parameters
4a ask user for the password
b save in keyring if installed and user agrees
:param username: user's name on the server
Expand All @@ -117,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):
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 {}'
Expand Down Expand Up @@ -166,6 +168,32 @@ def _password_from_keyring(username, host):
return keyring.get_password(password_key_prefix + host, username)


def _password_from_command(username, host):
'''command'''
import subprocess

try:
general, _, _ = ctx.obj['config']
_command = general['passwordeval'].split()
except (IndexError, KeyError):
return None

command = [expand_path(_command[0])]
if len(_command) > 1:
command += _command[1:]

try:
proc = subprocess.Popen(command + [username, host],
stdout=subprocess.PIPE)
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


class _FingerprintAdapter(requests.adapters.HTTPAdapter):
def __init__(self, fingerprint=None, **kwargs):
self.fingerprint = str(fingerprint)
Expand Down

0 comments on commit 3ad598c

Please sign in to comment.