Bugfix: Actually cache passwords

This commit is contained in:
Markus Unterwaditzer 2015-07-08 16:57:49 +02:00
parent 2d5a230fa4
commit 75d4f08c25
2 changed files with 35 additions and 21 deletions

View file

@ -10,7 +10,7 @@ import pytest
import requests
from vdirsyncer import doubleclick, utils
from vdirsyncer import doubleclick, log, utils
# These modules might be uninitialized and unavailable if not explicitly
# imported
@ -41,6 +41,16 @@ def empty_password_storages(monkeypatch):
monkeypatch.setattr(utils.password, 'keyring', EmptyKeyring())
@pytest.fixture(autouse=True)
def no_debug_output(request):
old = log._level
log.set_level(log.logging.WARNING)
def teardown():
log.set_level(old)
request.addfinalizer(teardown)
def test_get_password_from_netrc(monkeypatch):
username = 'foouser'
password = 'foopass'
@ -124,11 +134,13 @@ def test_get_password_from_prompt():
result = runner.invoke(fake_app, input='my_password\n\n')
assert not result.exception
assert result.output.splitlines() == [
'Server password for {} at host {}: '.format(user, 'example.com'),
'Password is my_password'
'Server password for my_user at host example.com: ',
'Save this password in the keyring? [y/N]: ',
'Password is my_password',
]
def test_set_keyring_password(monkeypatch):
class KeyringMock(object):
def get_password(self, resource, username):
@ -185,7 +197,6 @@ def test_get_password_from_cache(monkeypatch):
'Server password for {} at host {}: '.format(user, 'example.com'),
'Save this password in the keyring? [y/N]: ',
'Password is my_password',
'debug: Got password for my_user from internal cache',
'Password is my_password'
]

View file

@ -42,35 +42,38 @@ def get_password(username, resource, _lock=threading.Lock()):
"""
if ctx:
password_cache = ctx.obj.setdefault('passwords', {})
else:
password_cache = {} # discard passwords
def _password_from_cache(username, host):
'''internal cache'''
return password_cache.get((username, host), None)
with _lock:
host = urlparse.urlsplit(resource).hostname
for func in (_password_from_cache, _password_from_command,
_password_from_netrc, _password_from_keyring):
_password_from_netrc, _password_from_keyring,
_password_from_prompt):
password = func(username, host)
if password is not None:
logger.debug('Got password for {} from {}'
.format(username, func.__doc__))
return password
prompt = ('Server password for {} at host {}'.format(username, host))
password = click.prompt(prompt, hide_input=True)
if ctx and func is not _password_from_cache:
password_cache[(username, host)] = password
if keyring is not None and \
click.confirm('Save this password in the keyring?',
default=False):
keyring.set_password(password_key_prefix + host,
username, password)
break
password_cache[(username, host)] = password
return password
def _password_from_cache(username, host):
'''internal cache'''
if ctx:
return ctx.obj['passwords'].get((username, host), None)
def _password_from_prompt(username, host):
'''prompt'''
prompt = ('Server password for {} at host {}'.format(username, host))
password = click.prompt(prompt, hide_input=True)
if keyring is not None and \
click.confirm('Save this password in the keyring?',
default=False):
keyring.set_password(password_key_prefix + host,
username, password)
return password
def _password_from_netrc(username, host):