# -*-mode: doctest; tab-width: 0; py-indent-offset: 4; coding: utf-8-unix -*-

== PyKeepass ==

    >>> import os,sys # doctest: +REPORT_ONLY_FIRST_FAILURE

This library allows you to write entries to a KeePass database.
Come chat at `#pykeepass`_ on Freenode or `#pykeepass:matrix.org`_ on Matrix.

.. _#pykeepass: irc://irc.freenode.net
.. _#pykeepass\:matrix.org: https://matrix.to/#/%23pykeepass:matrix.org 

    >>> import pykeepass

    >>> password = 'password'
    >>> key = '12345678'
    >>> new_key_file = '/var/tmp/keyf.txt'
    >>> new_file = '/tmp/twofish.kdbx'
    >>> os.system('rm -f ' +new_file)
    0
    >>> with open(new_key_file, 'wt') as oFd:
    ...    oFd.write(key)
    8

=== Test Construct ===

You can test if this is an error in Construct

    >>> from construct import Struct, Bytes
    >>> s = Struct("field1" / Bytes(16))
    >>> parsed = s.parse(b'\x00' * 16)
    >>> s.build_file(parsed, '/tmp/file.' +str(os.getpid()))
    >>> parsed = s.parse_file('/tmp/file.' +str(os.getpid()))
      
=== run tests ===

    >>> import pykeepass
    >>> tests_dir = os.path.join(os.path.dirname(pykeepass.__file__), 'tests')
    >>> os.chdir('/var/local/src/pykeepass/tests')
    >>> _=sys.stderr.write( 'Running tests in ' +tests_dir +'\n')
    >>> os.system('python3.bash tests.py')
    0

    >>> os.system('ls -1f *4*x|grep -v hex|while read file ;do echo ' +password
    ...   +'| keepassxc-cli db-info -k test4.key $file;done')
    0

    >>> os.system('ls -1f *4*x|grep  hex|while read file ;do echo password| keepassxc-cli db-info -k test4_hex.key $file;done')
    0

=== create_database ===

Assume has boon run

    >>> import pykeepass
    ... # os.path.dirname(pykeepass.__file__),
    >>> egg_dir = '/usr/local/lib/python3.8/site-packages/pykeepass-3.2.0-py3.8.egg/pykeepass'
    >>> blank_database = os.path.join(egg_dir, 'tests', 'blank_twofish.kdbx')
    >>> assert os.path.exists(blank_database), \
    ...    'blank_database not found ' +blank_database

    >>> os.system('cp ' + blank_database +' ' +new_file)
    0
    >>> assert os.path.exists(new_file), 'File not found ' +new_file
    >>> old_key_file = os.path.join(os.path.dirname(pykeepass.__file__),
    ...    'tests', 'test4.key')

    >>> from pykeepass import PyKeePass
    >>> kp = PyKeePass(new_file, password=password, keyfile=old_key_file)
    >>> kp.filename = new_file
    >>> kp.password = password
    >>> kp.keyfile = None
    >>> kp.save()
    ... # keepass_instance.save(transformed_key)
    >>> _=sys.stderr.write( 'File created, keyfile reset ' +new_file +'\n')

=== CLI ===

    >>> import sh
    >>> from sh import keepassxc_cli

    ... if False:
    ...     old_file = '/var/tmp/test.kdbx'
    ...     os.path.exists(old_file): os.unlink(old_file)
    ...     keepassxc_cli('db-create', '-k', new_key_file, old_file,
    ...     _in=password, _tty_in=True, _tty_out=False ) #doctest: +NORMALIZE_WHITESPACE
    ... #    Successfully created new database.
    ... #    <BLANKLINE>

    >>> if True:
    ...     old_key_file = os.path.join(tests_dir, 'test4.key')
    ...     old_file = os.path.join(tests_dir, 'test4_twofish.kdbx')

    >>> _=sys.stderr.write( 'Using ' +old_file +'\n')

=== Example ===

Load the database that we just created.

   >>> from pykeepass import PyKeePass
   >>> kp = PyKeePass(old_file, password=password, keyfile=old_key_file)
   >>> assert kp
   >>> _=sys.stderr.write( 'Opened ' +old_file +'\n')
    

Save database again.

   >>> kp.filename = new_file
   >>> kp.keyfile = None
   >>> kp.save(new_file)
   >>> _=sys.stderr.write( 'Saved with no keyfile ' +new_file +'\n')

Delete old groups.

   >>> for group in kp.groups:
   ...    if group == kp.root_group: continue
   ...    _=sys.stderr.write( 'deleting group ' +str(group) +'\n')
   ...    kp.delete_group(group)

Delete old entries

   >>> for group in kp.groups:
   ...    if group != kp.root_group: continue
   ...    group.name = 'New Twofish' # yes
   ...    group.notes = 'New Notes'  # yes
   ...    entries = kp.entries
   ...    for entry in entries:
   ...        _=sys.stderr.write( 'deleted entries ' +str(entry) +'\n')
   ...        entry.delete()

Create a new group.

   >>> group = kp.add_group(kp.root_group, 'email')
   >>> assert group

Create a new entry.

   >>> kp.add_entry(group, 'gmail', 'myusername', 'myPassw0rdXX')
   Entry: "email/gmail (myusername)"

Save the modified database.

   >>> kp.save()
   >>> assert os.path.exists(old_file)
   >>> os.system("ls -l " +old_file)
   0

Find any group by its name.

   >>> group = kp.find_groups(name='email', first=True)

Get the entries in a group.

   >>> group.entries
   [Entry: "email/gmail (myusername)"]

Find any entry by its title.

   >>> entry = kp.find_entries(title='gmail', first=True)
   >>> assert entry is not None, 'gmail'
   >>> entry.username == 'myusername'
   True

Retrieve the associated password.

   >>> entry.password
   'myPassw0rdXX'

Update an entry.

   >>> import base64

   >>> entry.notes = 'primary gmail account'
   >>> kp.save()
   >>> _=sys.stderr.write( 'Saved with entry.notes ' +new_file +'\n')

   >>> kp.title = 'TwoFish Twofish' # nope
   >>> _=sys.stderr.write( 'Saved with Tmp kp.kdbx ' \
   ...    +repr(dir(kp.kdbx)) +'\n')

   >>> _=sys.stderr.write( ' with kp.kdbx.header.data ' \
   ...    +base64.b64encode(kp.kdbx.header.data).decode() +'\n')

   >>> x = kp._xpath('/KeePassFile/Meta/DatabaseName')[0]
   >>> x.text = 'TwoFishName' # yes
   >>> x = kp._xpath('/KeePassFile/Meta/DatabaseDescription')[0]
   >>> x.text = 'TwoFishDescription' # yes
   >>> kp.save()
   >>> _=sys.stderr.write( 'Saved with TwoFishDb ' +'\n')

   >>> binaries = kp._xpath('/KeePassFile/Meta/Binaries', first=True)
   >>> kp.add_binary('123'.encode(), compressed=False)
   0
   >>> kp.add_binary('456'.encode(), compressed=False)
   1
   >>> kp.save()
   >>> _=sys.stderr.write( 'Saved with a binary ' +'\n')
   
   >>> kp.binaries
   [b'123', b'456']

   >>> xml_file = '/tmp/twofish.xml'
   >>> kp.dump_xml(xml_file)
   >>> _=sys.stderr.write( 'Saved xml ' +xml_file +'\n')

   >>> _=sys.stderr.write( ' with kp ' +repr(dir(kp)))
   