Skip to content

Commit

Permalink
Added help topic on secrets.
Browse files Browse the repository at this point in the history
Added docstrings on subclasses of Obscure and Secret.
Added Hide subclass to Obscure.
Changed names of hidden files to make them not hidden (not backward compatible).
Change name of master password to master seed (not backward compatible).
Made field comparison in changed command insensitive to white space.
Fixed several bugs.
  • Loading branch information
KenKundert committed Dec 22, 2016
1 parent 35ab666 commit 5230b9c
Show file tree
Hide file tree
Showing 19 changed files with 820 additions and 148 deletions.
17 changes: 15 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ Avendesora Collaborative Password Utility
.. image:: https://img.shields.io/pypi/dd/avendesora.svg
:target: https://pypi.python.org/pypi/avendesora/

| Version: 0.16.0
| Released: 2016-12-20
| Version: 0.16.1
| Released: 2016-12-21
|
Avendesora is currently in beta. However it is reasonably stable and so you
Expand Down Expand Up @@ -126,6 +126,19 @@ Finally, run::

to confirm that none of your generated passwords have changed.

It is a good idea to run 'avendesora changed' and 'avendesora archive' on
a routine basis to keep your archive up to date.

Upon updating you may find that Avendesora produces a message that a 'hash' has
changed. This is an indication that something has changed in the program that
could affect the generated secrets. Again, care is taken when developing
Avendesora to prevent this from happening. But it is an indication that you
should take extra care. Specifically you should follow the above procedure to
assure that the value of your generated secrets have not changed. Once you have
confirmed that the upgrade has not affected your generated secrets, you should
follow the directions given in the warning and update the appropriate hash
contained in ~/.config/avendesora/.hashes.


Requirements
------------
Expand Down
6 changes: 3 additions & 3 deletions avendesora/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
Password, Passphrase, PIN, Question, MixedPassword, PasswordRecipe,
BirthDate,
)
from .obscure import Hidden, GPG
from .obscure import Hide, Hidden, GPG
try:
from .obscure import Scrypt
except ImportError: # no cover
Expand All @@ -19,5 +19,5 @@
from .generator import PasswordGenerator
from inform import Error as PasswordError

__version__ = '0.16.0'
__released__ = '2016-12-20'
__version__ = '0.16.1'
__released__ = '2016-12-21'
6 changes: 4 additions & 2 deletions avendesora/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,13 @@ def __init__(self, script = 'username: {username}, password: {passcode}'):
def render(self, account):
return str(account.get_value(self.script))

def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.script)

# Account class {{{1
class Account(object):
__NO_MASTER = True
# prevents master password from being added to this base class
# prevents master seed from being added to this base class

# all_accounts() {{{2
@classmethod
Expand Down Expand Up @@ -233,7 +235,7 @@ def initialize(cls, interactive_seed=False):
if cls.master.is_secure():
if not cls._file_info.encrypted:
warn(
'high value master password not contained in encrypted',
'high value master seed not contained in encrypted',
'account file.', culprit=cls.get_name()
)
except AttributeError as err:
Expand Down
27 changes: 17 additions & 10 deletions avendesora/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from .utilities import two_columns
from .writer import get_writer
from inform import (
Error, error, codicil, output, conjoin, os_error,
Error, debug, error, codicil, output, conjoin, os_error, warn,
is_collection, is_str, indent, render,
)
from shlib import chmod, mv, rm, to_path
Expand Down Expand Up @@ -271,12 +271,15 @@ def run(cls, command, args):

# get dictionary that fully describes the contents of each account
entries = []
for account in generator.all_accounts:
seen = set()
for account in generator.all_accounts():
name = account.get_name()
if name in seen:
warn('duplicate account name.', culprit=name)
seen.add(name)
entry = account.archive()
if entry:
entries.append(indent('%r: %s,' % (
account.get_name(), render(entry)
), ' '))
entries.append(indent('%r: %s,' % (name, render(entry)), ' '))

# build file contents
from .preferences import ARCHIVE_FILE_CONTENTS
Expand Down Expand Up @@ -401,6 +404,10 @@ def help(cls):

@classmethod
def run(cls, command, args):
# define white space insensitive compare function:
def differ(a, b):
return str(a).split() != str(b).split()

# read command line
cmdline = docopt(cls.USAGE, argv=[command] + args)

Expand All @@ -424,7 +431,7 @@ def run(cls, command, args):

# determine the account and open the URL
current_accounts = {}
for account in generator.all_accounts:
for account in generator.all_accounts():
entry = account.archive()
if entry:
current_accounts[account.get_name()] = entry
Expand All @@ -449,7 +456,7 @@ def run(cls, command, args):
for each in sorted(new):
output(account_name, 'new field', each, sep=': ')
for each in sorted(missing):
output(account_name, 'new field', each, sep=': ')
output(account_name, 'missing field', each, sep=': ')

# for the common fields, report any differences in the values
shared = set(archive_account.keys()) & set(current_account.keys())
Expand All @@ -471,10 +478,10 @@ def run(cls, command, args):
for each in sorted(missing):
output(account_name, field_name, 'missing member', each, sep=': ')
for k in sorted(archive_keys & current_keys):
if str(archive_value[k]) != str(current_value[k]):
if differ(archive_value[k], current_value[k]):
output(account_name, 'member differs', '%s[%s]' % (field_name, k), sep=': ')
else:
if dedent(str(archive_value)) != dedent(str(current_value)):
if differ(archive_value, current_value):
output(account_name, 'field differs', field_name, sep=': ')
except Exception:
error(
Expand Down Expand Up @@ -721,7 +728,7 @@ def help(cls):
{usage}
Creates a new accounts file. Accounts that share the same file share
the same master password by default and, if the file is encrypted,
the same master seed by default and, if the file is encrypted,
can be decrypted by the same recipients.
Generally you would create a new accounts file for each person or
Expand Down
3 changes: 3 additions & 0 deletions avendesora/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ def read_config():
path = get_setting('config_file')
assert path.suffix.lower() not in ['.gpg', '.asc']
config_file = PythonFile(path)
if not config_file.exists():
# have not yet initialized this account
return
try:
contents = config_file.run()
for k, v in contents.items():
Expand Down
12 changes: 5 additions & 7 deletions avendesora/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ def __init__(self, init=False, gpg_ids=None):
path = to_path(get_setting('settings_dir'), filename)
account_file = PythonFile(path)
contents = account_file.run()
master_password = contents.get('master_password')
master_seed = contents.get('master_seed')

# traverse through all accounts, determine which are new, bind
# required information to new accounts, and update account list.
for account in Account.all_accounts():
if account not in self.accounts:
account.add_fileinfo(master_password, account_file)
account.add_fileinfo(master_seed, account_file)

# save a copy of account so it is not garbage collected
self.accounts.add(account)
Expand Down Expand Up @@ -103,8 +103,7 @@ def split(s, l=72):
gpg_ids = gpg_ids if gpg_ids else get_setting('gpg_ids', [])
fields.update({
'section': '{''{''{''1',
'master_password': split(Hidden.conceal(generate_random_string(72))),
'master_password2': split(Hidden.conceal(generate_random_string(72))),
'master_seed': split(Hidden.conceal(generate_random_string(72))),
'user_key': split(Hidden.conceal(generate_random_string(72))),
'gpg_ids': repr(' '.join(gpg_ids)),
})
Expand Down Expand Up @@ -144,9 +143,8 @@ def split(s, l=72):
try:
log('writing.', culprit=path)
path.write_text(
ACCOUNT_LIST_FILE_CONTENTS.format(**fields).decode(
get_setting('encoding')
)
ACCOUNT_LIST_FILE_CONTENTS.format(**fields),
get_setting('encoding')
)
except OSError as err:
raise Error(os_error(err))
Expand Down
5 changes: 4 additions & 1 deletion avendesora/gpg.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,10 +240,13 @@ def create(self, contents, gpg_ids):
else:
narrate('not encrypting.', culprit=path)
# file is not encrypted
with path.open('w') as f:
with path.open('wb') as f:
f.write(contents.encode(get_setting('encoding')))
except OSError as err:
raise Error(os_error(err))

def exists(self):
return self.path.exists()

def __str__(self):
return str(self.path)

0 comments on commit 5230b9c

Please sign in to comment.