Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-pykeepass for 
openSUSE:Factory checked in at 2021-06-01 10:37:05
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pykeepass (Old)
 and      /work/SRC/openSUSE:Factory/.python-pykeepass.new.1898 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-pykeepass"

Tue Jun  1 10:37:05 2021 rev:6 rq:895543 version:4.0.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pykeepass/python-pykeepass.changes        
2021-02-18 20:53:10.735482651 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-pykeepass.new.1898/python-pykeepass.changes  
    2021-06-01 10:38:08.108881835 +0200
@@ -1,0 +2,8 @@
+Sun May 23 00:32:17 UTC 2021 - Atri Bhattacharya <[email protected]>
+
+- Update to version 4.0.1:
+  * No release notes.
+- Drop python-pykeepass-fix-version.patch: incorporated upstream.
+- Update dependency versions in keeping with upstream.
+
+-------------------------------------------------------------------

Old:
----
  pykeepass-4.0.0.tar.gz
  python-pykeepass-fix-version.patch

New:
----
  pykeepass-4.0.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-pykeepass.spec ++++++
--- /var/tmp/diff_new_pack.SbX2lh/_old  2021-06-01 10:38:08.716882870 +0200
+++ /var/tmp/diff_new_pack.SbX2lh/_new  2021-06-01 10:38:08.720882876 +0200
@@ -18,32 +18,30 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-pykeepass
-Version:        4.0.0
+Version:        4.0.1
 Release:        0
 Summary:        Low-level library to interact with keepass databases
 License:        GPL-3.0-only
 Group:          Development/Languages/Python
 URL:            https://github.com/libkeepass/pykeepass
 Source:         
https://github.com/libkeepass/pykeepass/archive/%{version}.tar.gz#/pykeepass-%{version}.tar.gz
-# PATCH-FIX-UPSTREAM python-pykeepass-fix-version.patch [email protected] 
-- Fix version so that egg-infos don't end up with the wrong version; patch 
taken from upstream commit
-Patch0:         python-pykeepass-fix-version.patch
 BuildRequires:  %{python_module devel}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
-Requires:       python-argon2-cffi
+Requires:       python-argon2-cffi >= 20.1.0
 Requires:       python-construct >= 2.10.54
 Requires:       python-future
-Requires:       python-lxml
-Requires:       python-pycryptodomex >= 3.6.2
+Requires:       python-lxml >= 4.6.1
+Requires:       python-pycryptodomex >= 3.10.1
 Requires:       python-python-dateutil
 BuildArch:      noarch
 # SECTION test requirements
-BuildRequires:  %{python_module argon2-cffi}
+BuildRequires:  %{python_module argon2-cffi >= 20.1.0}
 BuildRequires:  %{python_module construct >= 2.10.54}
 BuildRequires:  %{python_module future}
-BuildRequires:  %{python_module lxml}
-BuildRequires:  %{python_module pycryptodomex >= 3.6.2}
+BuildRequires:  %{python_module lxml >= 4.6.1}
+BuildRequires:  %{python_module pycryptodomex >= 3.10.1}
 BuildRequires:  %{python_module pytest}
 BuildRequires:  %{python_module python-dateutil}
 # /SECTION

++++++ pykeepass-4.0.0.tar.gz -> pykeepass-4.0.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pykeepass-4.0.0/.github/dependabot.yml 
new/pykeepass-4.0.1/.github/dependabot.yml
--- old/pykeepass-4.0.0/.github/dependabot.yml  2021-02-03 05:02:22.000000000 
+0100
+++ new/pykeepass-4.0.1/.github/dependabot.yml  2021-05-22 09:07:02.000000000 
+0200
@@ -3,4 +3,4 @@
   - package-ecosystem: "pip" # See documentation for possible values
     directory: "/" # Location of package manifests
     schedule:
-      interval: "daily"
+      interval: "monthly"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pykeepass-4.0.0/doc/source/index.rst 
new/pykeepass-4.0.1/doc/source/index.rst
--- old/pykeepass-4.0.0/doc/source/index.rst    2021-02-03 05:02:22.000000000 
+0100
+++ new/pykeepass-4.0.1/doc/source/index.rst    2021-05-22 09:07:02.000000000 
+0200
@@ -13,7 +13,6 @@
    icons
    exceptions
    baseelement
-   kdbx_parsing/*
 
 .. image:: https://travis-ci.org/libkeepass/pykeepass.svg?branch=master
    :target: https://travis-ci.org/libkeepass/pykeepass
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pykeepass-4.0.0/doc/source/kdbx_parsing/common.rst 
new/pykeepass-4.0.1/doc/source/kdbx_parsing/common.rst
--- old/pykeepass-4.0.0/doc/source/kdbx_parsing/common.rst      2021-02-03 
05:02:22.000000000 +0100
+++ new/pykeepass-4.0.1/doc/source/kdbx_parsing/common.rst      1970-01-01 
01:00:00.000000000 +0100
@@ -1,5 +0,0 @@
-kdbx_parsing.common
-===================
-
-.. automodule:: pykeepass.kdbx_parsing.common
-   :members:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pykeepass-4.0.0/doc/source/kdbx_parsing/kdbx.rst 
new/pykeepass-4.0.1/doc/source/kdbx_parsing/kdbx.rst
--- old/pykeepass-4.0.0/doc/source/kdbx_parsing/kdbx.rst        2021-02-03 
05:02:22.000000000 +0100
+++ new/pykeepass-4.0.1/doc/source/kdbx_parsing/kdbx.rst        1970-01-01 
01:00:00.000000000 +0100
@@ -1,5 +0,0 @@
-kdbx_parsing.kdbx
-=================
-
-.. automodule:: pykeepass.kdbx_parsing.kdbx
-   :members:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pykeepass-4.0.0/doc/source/kdbx_parsing/kdbx3.rst 
new/pykeepass-4.0.1/doc/source/kdbx_parsing/kdbx3.rst
--- old/pykeepass-4.0.0/doc/source/kdbx_parsing/kdbx3.rst       2021-02-03 
05:02:22.000000000 +0100
+++ new/pykeepass-4.0.1/doc/source/kdbx_parsing/kdbx3.rst       1970-01-01 
01:00:00.000000000 +0100
@@ -1,5 +0,0 @@
-kdbx_parsing.kdbx3
-==================
-
-.. automodule:: pykeepass.kdbx_parsing.kdbx3
-   :members:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pykeepass-4.0.0/doc/source/kdbx_parsing/kdbx4.rst 
new/pykeepass-4.0.1/doc/source/kdbx_parsing/kdbx4.rst
--- old/pykeepass-4.0.0/doc/source/kdbx_parsing/kdbx4.rst       2021-02-03 
05:02:22.000000000 +0100
+++ new/pykeepass-4.0.1/doc/source/kdbx_parsing/kdbx4.rst       1970-01-01 
01:00:00.000000000 +0100
@@ -1,5 +0,0 @@
-kdbx_parsing.kdbx4
-==================
-
-.. automodule:: pykeepass.kdbx_parsing.kdbx4
-   :members:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pykeepass-4.0.0/doc/source/kdbx_parsing/pytwofish.rst 
new/pykeepass-4.0.1/doc/source/kdbx_parsing/pytwofish.rst
--- old/pykeepass-4.0.0/doc/source/kdbx_parsing/pytwofish.rst   2021-02-03 
05:02:22.000000000 +0100
+++ new/pykeepass-4.0.1/doc/source/kdbx_parsing/pytwofish.rst   1970-01-01 
01:00:00.000000000 +0100
@@ -1,5 +0,0 @@
-kdbx_parsing.pytwofish
-======================
-
-.. automodule:: pykeepass.kdbx_parsing.pytwofish
-   :members:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pykeepass-4.0.0/doc/source/kdbx_parsing/twofish.rst 
new/pykeepass-4.0.1/doc/source/kdbx_parsing/twofish.rst
--- old/pykeepass-4.0.0/doc/source/kdbx_parsing/twofish.rst     2021-02-03 
05:02:22.000000000 +0100
+++ new/pykeepass-4.0.1/doc/source/kdbx_parsing/twofish.rst     1970-01-01 
01:00:00.000000000 +0100
@@ -1,5 +0,0 @@
-kdbx_parsing.twofish
-====================
-
-.. automodule:: pykeepass.kdbx_parsing.twofish
-   :members:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pykeepass-4.0.0/pykeepass/baseelement.py 
new/pykeepass-4.0.1/pykeepass/baseelement.py
--- old/pykeepass-4.0.0/pykeepass/baseelement.py        2021-02-03 
05:02:22.000000000 +0100
+++ new/pykeepass-4.0.1/pykeepass/baseelement.py        2021-05-22 
09:07:02.000000000 +0200
@@ -14,7 +14,7 @@
 class BaseElement(object):
     """Entry and Group inherit from this class"""
 
-    def __init__(self, element=None, kp=None, icon=None, expires=False,
+    def __init__(self, element, kp=None, icon=None, expires=False,
                  expiry_time=None):
 
         self._element = element
@@ -221,3 +221,15 @@
             return self.uuid == other.uuid
         else:
             return False
+
+    def touch(self, modify=False):
+        """
+        Update last access time of an entry/group
+
+        Args:
+            modify (bool): update access time as well a modification time
+        """
+        now = datetime.now()
+        self.atime = now
+        if modify:
+            self.mtime = now
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pykeepass-4.0.0/pykeepass/entry.py 
new/pykeepass-4.0.1/pykeepass/entry.py
--- old/pykeepass-4.0.0/pykeepass/entry.py      2021-02-03 05:02:22.000000000 
+0100
+++ new/pykeepass-4.0.1/pykeepass/entry.py      2021-05-22 09:07:02.000000000 
+0200
@@ -49,7 +49,7 @@
             self._element.append(E.String(E.Key('Title'), E.Value(title)))
             self._element.append(E.String(E.Key('UserName'), 
E.Value(username)))
             self._element.append(
-                E.String(E.Key('Password'), E.Value(password, 
protected="False"))
+                E.String(E.Key('Password'), E.Value(password, 
Protected="True"))
             )
             if url:
                 self._element.append(E.String(E.Key('URL'), E.Value(url)))
@@ -220,6 +220,9 @@
 
     @property
     def path(self):
+        """Path to element as list.  List contains all parent group names
+        ending with entry title.  List may contain strings or NoneTypes."""
+
         # The root group is an orphan
         if self.parentgroup is None:
             return None
@@ -267,15 +270,6 @@
         }
         return '{{REF:{}@I:{}}}'.format(attribute_to_field[attribute], 
self.uuid.hex.upper())
 
-    def touch(self, modify=False):
-        '''
-        Update last access time of an entry
-        '''
-        now = datetime.now()
-        self.atime = now
-        if modify:
-            self.mtime = now
-
     def save_history(self):
         '''
         Save the entry in its history
@@ -291,7 +285,8 @@
             self._element.append(history)
 
     def __str__(self):
-        pathstr = '/'.join(self.path)
+        # filter out NoneTypes and join into string
+        pathstr = '/'.join('' if p==None else p for p in self.path)
         if self.is_a_history_entry:
             return '[History of: {}]'.format(pathstr)
         return 'Entry: "{} ({})"'.format(pathstr, self.username)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pykeepass-4.0.0/pykeepass/group.py 
new/pykeepass-4.0.1/pykeepass/group.py
--- old/pykeepass-4.0.0/pykeepass/group.py      2021-02-03 05:02:22.000000000 
+0100
+++ new/pykeepass-4.0.1/pykeepass/group.py      2021-05-22 09:07:02.000000000 
+0200
@@ -94,5 +94,6 @@
             self._element.append(entries._element)
 
     def __str__(self):
-        pathstr = '/'.join(self.path)
+        # filter out NoneTypes and join into string
+        pathstr = '/'.join('' if p==None else p for p in self.path)
         return 'Group: "{}"'.format(pathstr)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pykeepass-4.0.0/pykeepass/kdbx_parsing/common.py 
new/pykeepass-4.0.1/pykeepass/kdbx_parsing/common.py
--- old/pykeepass-4.0.0/pykeepass/kdbx_parsing/common.py        2021-02-03 
05:02:22.000000000 +0100
+++ new/pykeepass-4.0.1/pykeepass/kdbx_parsing/common.py        2021-05-22 
09:07:02.000000000 +0200
@@ -8,12 +8,16 @@
 from lxml import etree
 from copy import deepcopy
 import base64
+from binascii import Error as BinasciiError
 import unicodedata
 import zlib
 import re
 import codecs
 from io import BytesIO
 from collections import OrderedDict
+import logging
+
+log = logging.getLogger(__name__)
 
 
 class HeaderChecksumError(Exception):
@@ -116,7 +120,17 @@
         try:
             with open(keyfile, 'r') as f:
                 tree = etree.parse(f).getroot()
-                keyfile_composite = 
base64.b64decode(tree.find('Key/Data').text)
+                version = tree.find('Meta/Version').text
+                data_element = tree.find('Key/Data')
+                if version.startswith('1.0'):
+                    keyfile_composite = base64.b64decode(data_element.text)
+                elif version.startswith('2.0'):
+                    # read keyfile data and convert to bytes
+                    keyfile_composite = 
bytes.fromhex(data_element.text.strip())
+                    # validate bytes against hash
+                    hash = bytes.fromhex(data_element.attrib['Hash'])
+                    hash_computed = 
hashlib.sha256(keyfile_composite).digest()[:4]
+                    assert hash == hash_computed, "Keyfile has invalid hash"
         # otherwise, try to read plain keyfile
         except (etree.XMLSyntaxError, UnicodeDecodeError):
             try:
@@ -178,7 +192,6 @@
     provided by get_cipher"""
 
     protected_xpath = '//Value[@Protected=\'True\']'
-    unprotected_xpath = '//Value[@Protected=\'False\']'
 
     def __init__(self, protected_stream_key, subcon):
         super(UnprotectedStream, self).__init__(subcon)
@@ -188,29 +201,33 @@
         cipher = self.get_cipher(self.protected_stream_key(con))
         for elem in tree.xpath(self.protected_xpath):
             if elem.text is not None:
-                result = 
cipher.decrypt(base64.b64decode(elem.text)).decode('utf-8')
-                # strip invalid XML characters - 
https://stackoverflow.com/questions/8733233
-                result = re.sub(
-                    
u'[^\u0020-\uD7FF\u0009\u000A\u000D\uE000-\uFFFD\U00010000-\U0010FFFF]+',
-                    '',
-                    result
-                )
-                elem.text = result
-            elem.attrib['Protected'] = 'False'
+                try:
+                    result = 
cipher.decrypt(base64.b64decode(elem.text)).decode('utf-8')
+                    # strip invalid XML characters - 
https://stackoverflow.com/questions/8733233
+                    result = re.sub(
+                        
u'[^\u0020-\uD7FF\u0009\u000A\u000D\uE000-\uFFFD\U00010000-\U0010FFFF]+',
+                        '',
+                        result
+                    )
+                    elem.text = result
+                except (UnicodeDecodeError, BinasciiError, ValueError):
+                    # FIXME: this should be a warning eventually, need to fix 
all databases in tests/ first
+                    log.error(
+                        "Element at {} marked as protected, but could not 
unprotect".format(tree.getpath(elem))
+                    )
         return tree
 
     def _encode(self, tree, con, path):
         tree_copy = deepcopy(tree)
         cipher = self.get_cipher(self.protected_stream_key(con))
-        for elem in tree_copy.xpath(self.unprotected_xpath):
+        for elem in tree_copy.xpath(self.protected_xpath):
             if elem.text is not None:
                 elem.text = base64.b64encode(
                     cipher.encrypt(
                         elem.text.encode('utf-8')
                     )
                 )
-            elem.attrib['Protected'] = 'True'
-        return tree
+        return tree_copy
 
 
 class ARCFourVariantStream(UnprotectedStream):
@@ -282,7 +299,16 @@
             con._.header.value.dynamic_header.encryption_iv.data
         )
         payload_data = cipher.decrypt(payload_data)
-        payload_data = self.unpad(payload_data)
+        # FIXME: Construct ugliness.  Fixes #244.  First 32 bytes of decrypted 
kdbx3 payload
+        # should be checked against stream_start_bytes for a CredentialsError. 
 Due to construct
+        # limitations, we have to decrypt the whole payload in order to check 
the first 32 bytes.
+        # However, when the credentials are wrong the invalid decrypted 
payload cannot
+        # be unpadded correctly.  Instead, catch the unpad ValueError 
exception raised by unpad()
+        # and allow kdbx3.py to raise a ChecksumError
+        try:
+            payload_data = self.unpad(payload_data)
+        except ValueError:
+            log.debug("Decryption unpadding failed")
 
         return payload_data
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pykeepass-4.0.0/pykeepass/pykeepass.py 
new/pykeepass-4.0.1/pykeepass/pykeepass.py
--- old/pykeepass-4.0.0/pykeepass/pykeepass.py  2021-02-03 05:02:22.000000000 
+0100
+++ new/pykeepass-4.0.1/pykeepass/pykeepass.py  2021-05-22 09:07:02.000000000 
+0200
@@ -123,6 +123,11 @@
             else:
                 raise
 
+    def reload(self):
+        """Reload current database using previous credentials """
+
+        self.read(self.filename, self.password, self.keyfile)
+
     def save(self, filename=None, transformed_key=None):
         """Save current database object to disk.
 
@@ -272,7 +277,7 @@
 
         if tree is None:
             tree = self.tree
-        logger.debug(xpath_str)
+        logger.debug('xpath query: ' + xpath_str)
         elements = tree.xpath(
             xpath_str, namespaces={'re': 
'http://exslt.org/regular-expressions'}
         )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pykeepass-4.0.0/pykeepass/version.py 
new/pykeepass-4.0.1/pykeepass/version.py
--- old/pykeepass-4.0.0/pykeepass/version.py    2021-02-03 05:02:22.000000000 
+0100
+++ new/pykeepass-4.0.1/pykeepass/version.py    2021-05-22 09:07:02.000000000 
+0200
@@ -1,3 +1,3 @@
-__version__ = "3.2.1"
+__version__ = "4.0.1"
 
 __all__= ["__version__"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pykeepass-4.0.0/requirements-rtd.txt 
new/pykeepass-4.0.1/requirements-rtd.txt
--- old/pykeepass-4.0.0/requirements-rtd.txt    2021-02-03 05:02:22.000000000 
+0100
+++ new/pykeepass-4.0.1/requirements-rtd.txt    2021-05-22 09:07:02.000000000 
+0200
@@ -1,7 +1,7 @@
-lxml==4.3.5
-pycryptodomex==3.9.9
+lxml==4.6.2
+pycryptodomex==3.10.1
 construct==2.10.54
-argon2-cffi==19.2.0
+argon2-cffi==20.1.0
 python-dateutil==2.8.1
 future==0.18.2
 Sphinx>=3.2.1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pykeepass-4.0.0/requirements.txt 
new/pykeepass-4.0.1/requirements.txt
--- old/pykeepass-4.0.0/requirements.txt        2021-02-03 05:02:22.000000000 
+0100
+++ new/pykeepass-4.0.1/requirements.txt        2021-05-22 09:07:02.000000000 
+0200
@@ -1,6 +1,6 @@
-lxml==4.3.5
-pycryptodomex==3.9.9
+lxml==4.6.2
+pycryptodomex==3.10.1
 construct==2.10.54
-argon2-cffi==19.2.0
+argon2-cffi==20.1.0
 python-dateutil==2.8.1
 future==0.18.2
Binary files old/pykeepass-4.0.0/tests/test3.kdbx and 
new/pykeepass-4.0.1/tests/test3.kdbx differ
Binary files old/pykeepass-4.0.0/tests/test3_transformed.kdbx and 
new/pykeepass-4.0.1/tests/test3_transformed.kdbx differ
Binary files old/pykeepass-4.0.0/tests/test4.kdbx and 
new/pykeepass-4.0.1/tests/test4.kdbx differ
Binary files old/pykeepass-4.0.0/tests/test4_keyx.kdbx and 
new/pykeepass-4.0.1/tests/test4_keyx.kdbx differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pykeepass-4.0.0/tests/test4_keyx.keyx 
new/pykeepass-4.0.1/tests/test4_keyx.keyx
--- old/pykeepass-4.0.0/tests/test4_keyx.keyx   1970-01-01 01:00:00.000000000 
+0100
+++ new/pykeepass-4.0.1/tests/test4_keyx.keyx   2021-05-22 09:07:02.000000000 
+0200
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<KeyFile>
+       <Meta>
+               <Version>2.0</Version>
+       </Meta>
+       <Key>
+               <Data Hash="F79BE54D">
+                       30D73184 FBE1C7C4 B07EE4D6 BC4F118B
+                       87577CAB 5CB8846F 5FD286FF F98BF9A9
+               </Data>
+       </Key>
+</KeyFile>
\ No newline at end of file
Binary files old/pykeepass-4.0.0/tests/test4_transformed.kdbx and 
new/pykeepass-4.0.1/tests/test4_transformed.kdbx differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pykeepass-4.0.0/tests/tests.py 
new/pykeepass-4.0.1/tests/tests.py
--- old/pykeepass-4.0.0/tests/tests.py  2021-02-03 05:02:22.000000000 +0100
+++ new/pykeepass-4.0.1/tests/tests.py  2021-05-22 09:07:02.000000000 +0200
@@ -277,6 +277,11 @@
         self.assertIsInstance(e.__repr__(), str)
         self.assertIsInstance(e.history.__repr__(), str)
 
+        # issue 250
+        e = self.kp.find_entries(username='blank_title', first=True)
+        self.assertIsNot(e, None)
+        self.assertIsInstance(e.__repr__(), str)
+
 
 class GroupFindTests3(KDBX3Tests):
 
@@ -317,7 +322,7 @@
     def test_groups(self):
         results = self.kp.groups
 
-        self.assertEqual(len(results), 6)
+        self.assertEqual(len(results), 7)
 
     # ---------- Adding/Deleting Groups -----------
 
@@ -349,6 +354,10 @@
     def test_print_groups(self):
         self.assertIsInstance(self.kp.groups.__repr__(), str)
 
+        g = self.kp.find_groups(notes='blank_name')
+        self.assertIsNot(g, None)
+        self.assertIsInstance(g.__repr__(), str)
+
 class RecycleBinTests3(KDBX3Tests):
 
     def test_recyclebincreation(self):
@@ -541,6 +550,15 @@
         self.assertTrue(mtime < entry.mtime)
         self.assertEqual(ctime, entry.ctime)
 
+        group = self.kp.find_groups(name='foobar_group', first=True)
+        atime = group.atime
+        mtime = group.mtime
+        ctime = group.ctime
+        group.touch(modify=True)
+        self.assertTrue(atime < group.atime)
+        self.assertTrue(mtime < group.mtime)
+        self.assertEqual(ctime, group.ctime)
+
 
     def test_add_remove_attachment(self):
         entry = self.kp.add_entry(
@@ -824,6 +842,15 @@
         self.assertTrue(g.name is None)
         self.assertTrue(g in self.kp.groups)
 
+    def test_issue194(self):
+        # entries with Protected=True aren't being protected properly
+
+        self.kp_tmp.add_entry(self.kp_tmp.root_group, 'protect_test', 'user', 
'pass')
+        self.kp_tmp.save()
+        self.kp_tmp.reload()
+        e = self.kp_tmp.find_entries(title='protect_test', first=True)
+        self.assertEqual(e.password, 'pass')
+
 
 
 class EntryFindTests4(KDBX4Tests, EntryFindTests3):
@@ -867,17 +894,17 @@
             stream = BytesIO(file.read())
 
         filenames_in = [
-            os.path.join(base_dir, 'test3.kdbx'),           # KDBX v3 test
-            os.path.join(base_dir, 'test4.kdbx'),           # KDBX v4 test
-            os.path.join(base_dir, 'test4_aes.kdbx'),       # KDBX v4 AES test
-            os.path.join(base_dir, 'test4_aeskdf.kdbx'),    # KDBX v3 AESKDF 
test
-            os.path.join(base_dir, 'test4_chacha20.kdbx'),  # KDBX v4 ChaCha 
test
-            os.path.join(base_dir, 'test4_twofish.kdbx'),   # KDBX v4 Twofish 
test
-            os.path.join(base_dir, 'test4_hex.kdbx'),       # legacy 64 byte 
hexadecimal keyfile test
-            os.path.join(base_dir, 'test3.kdbx'),           # KDBX v3 
transformed_key open test
-            os.path.join(base_dir, 'test4_hex.kdbx'),       # KDBX v4 
transformed_key open test
+            os.path.join(base_dir, 'test3.kdbx'),                 # KDBX v3
+            os.path.join(base_dir, 'test4.kdbx'),                 # KDBX v4
+            os.path.join(base_dir, 'test4_aes.kdbx'),             # KDBX v4 AES
+            os.path.join(base_dir, 'test4_aeskdf.kdbx'),          # KDBX v3 
AESKDF
+            os.path.join(base_dir, 'test4_chacha20.kdbx'),        # KDBX v4 
ChaCha
+            os.path.join(base_dir, 'test4_twofish.kdbx'),         # KDBX v4 
Twofish
+            os.path.join(base_dir, 'test4_hex.kdbx'),             # legacy 64 
byte hexadecimal keyfile
+            os.path.join(base_dir, 'test3_transformed.kdbx'),     # KDBX v3 
transformed_key open
+            os.path.join(base_dir, 'test4_transformed.kdbx'),     # KDBX v4 
transformed_key open
             stream,
-            os.path.join(base_dir, 'test4_aes_uncompressed.kdbx')    # KDBX v4 
AES uncompressed test
+            os.path.join(base_dir, 'test4_aes_uncompressed.kdbx') # KDBX v4 
AES uncompressed
         ]
         filenames_out = [
             os.path.join(base_dir, 'test3.kdbx.out'),
@@ -887,8 +914,8 @@
             os.path.join(base_dir, 'test4_chacha20.kdbx.out'),
             os.path.join(base_dir, 'test4_twofish.kdbx.out'),
             os.path.join(base_dir, 'test4_hex.kdbx.out'),
-            os.path.join(base_dir, 'test3.kdbx.out'),
-            os.path.join(base_dir, 'test4_hex.kdbx.out'),
+            os.path.join(base_dir, 'test3_transformed.kdbx.out'),
+            os.path.join(base_dir, 'test4_transformed.kdbx.out'),
             BytesIO(),
             os.path.join(base_dir, 'test4_aes_uncompressed.kdbx.out'),
             os.path.join(base_dir, 'test4_twofish_uncompressed.kdbx.out'),
@@ -918,7 +945,7 @@
             None,
             None,
             
b'\xfb\xb1!\x0e0\x94\xd4\x868\xa5\x04\xe6T\x9b<\xf9+\xb8\x82EN\xbc\xbe\xbc\xc8\xd3\xbbf\xfb\xde\xff.',
-            
b'M\xb7\x08\xf6\xa7\xd1v\xb1{&\x06\x8f\xae\xe9\r\xeb\x9a\x1b\x02b\xce\xf2\x8aR\xaea)7\x1fs\xe9\xc0',
+            
b'\x95\x0be\x9ca\x9e<\xe0\x07\x02\x7f\xc3\xd8\xa1\xa6&\x985\x8f!\xa6\x18k\x13\xa2\xd2\r=\xf3\xebd\xc5',
             None,
             None,
             None,
@@ -1021,25 +1048,33 @@
                 os.remove(os.path.join(base_dir, filename))
 
 
-    def test_open_error(self):
-        with self.assertRaises(CredentialsError):
-            database = 'test4.kdbx'
-            invalid_password = 'foobar'
-            keyfile = os.path.join(base_dir, 'test4.key')
-            PyKeePass(
-                os.path.join(base_dir, database),
-                password=invalid_password,
-                keyfile=keyfile
-            )
-        with self.assertRaises(CredentialsError):
-            database = 'test4.kdbx'
-            password = 'password'
-            invalid_keyfile = os.path.join(base_dir, 'test3.key')
-            PyKeePass(
-                os.path.join(base_dir, database),
-                password=password,
-                keyfile=invalid_keyfile
-            )
+    def test_credentials_error(self):
+
+        databases = [
+            'test3.kdbx',
+            'test3.kdbx',
+            'test4.kdbx',
+            'test4.kdbx'
+        ]
+        passwords = [
+            'invalid',
+            'password',
+            'invalid',
+            'password',
+        ]
+        keyfiles = [
+            'test3.key',
+            'test4.key',
+            'test4.key',
+            'test3.key',
+        ]
+        for database, password, keyfile in zip(databases, passwords, keyfiles):
+            with self.assertRaises(CredentialsError):
+                PyKeePass(
+                    os.path.join(base_dir, database),
+                    password,
+                    os.path.join(base_dir, keyfile)
+                )
 
 if __name__ == '__main__':
     unittest.main()

Reply via email to