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 2023-06-12 15:27:21
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pykeepass (Old)
and /work/SRC/openSUSE:Factory/.python-pykeepass.new.15902 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pykeepass"
Mon Jun 12 15:27:21 2023 rev:10 rq:1092474 version:4.0.5
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pykeepass/python-pykeepass.changes
2023-05-31 21:54:56.541163173 +0200
+++
/work/SRC/openSUSE:Factory/.python-pykeepass.new.15902/python-pykeepass.changes
2023-06-12 15:27:56.587581503 +0200
@@ -1,0 +2,9 @@
+Sat Jun 10 16:42:35 UTC 2023 - Atri Bhattacharya <[email protected]>
+
+- Update to version 4.0.5:
+ * [gh#libkeepass/pykeepass#344] AttributeError when accessing
+ Times with None value
+ * use __hash__ when evaluating equality
+ * use mtime/uuid for HistoryEntry hashing
+
+-------------------------------------------------------------------
Old:
----
pykeepass-4.0.4.tar.gz
New:
----
pykeepass-4.0.5.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-pykeepass.spec ++++++
--- /var/tmp/diff_new_pack.l43Ozg/_old 2023-06-12 15:27:57.203585148 +0200
+++ /var/tmp/diff_new_pack.l43Ozg/_new 2023-06-12 15:27:57.207585171 +0200
@@ -17,7 +17,7 @@
Name: python-pykeepass
-Version: 4.0.4
+Version: 4.0.5
Release: 0
Summary: Low-level library to interact with keepass databases
License: GPL-3.0-only
++++++ pykeepass-4.0.4.tar.gz -> pykeepass-4.0.5.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pykeepass-4.0.4/CHANGELOG.rst
new/pykeepass-4.0.5/CHANGELOG.rst
--- old/pykeepass-4.0.4/CHANGELOG.rst 2023-05-12 08:00:19.000000000 +0200
+++ new/pykeepass-4.0.5/CHANGELOG.rst 2023-06-05 23:38:19.000000000 +0200
@@ -1,4 +1,10 @@
-4.0.4 -
+4.0.5 -
+------------------
+- fixed #344 - AttributeError when accessing Times with None value
+- use __hash__ when evaluating equality
+- use mtime/uuid for HistoryEntry hashing
+
+4.0.4 - 2023-05-23
------------------
- fixed #314 - correctly handle binaries with no data
- fixed #265 - check for keepass signature
@@ -10,8 +16,8 @@
4.0.3 - 2022-06-21
------------------
-- add otp support
-- add debug_setup() function
+- added otp support
+- added debug_setup() function
4.0.2 - 2022-05-21
------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pykeepass-4.0.4/README.rst
new/pykeepass-4.0.5/README.rst
--- old/pykeepass-4.0.4/README.rst 2023-05-12 08:00:19.000000000 +0200
+++ new/pykeepass-4.0.5/README.rst 2023-06-05 23:38:19.000000000 +0200
@@ -380,7 +380,7 @@
**password**
-string containing database password. Can also be set. Use ``None** for no
password.
+string containing database password. Can also be set. Use ``None`` for no
password.
**filename**
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pykeepass-4.0.4/pykeepass/baseelement.py
new/pykeepass-4.0.5/pykeepass/baseelement.py
--- old/pykeepass-4.0.4/pykeepass/baseelement.py 2023-05-12
08:00:19.000000000 +0200
+++ new/pykeepass-4.0.5/pykeepass/baseelement.py 2023-06-05
23:38:19.000000000 +0200
@@ -93,7 +93,7 @@
times = self._element.find('Times')
if times is not None:
prop = times.find(prop)
- if prop is not None:
+ if prop is not None and prop.text is not None:
return self._kp._decode_time(prop.text)
def _set_times_property(self, prop, value):
@@ -166,11 +166,13 @@
def __repr__(self):
return self.__str__()
+ def __hash__(self):
+ return hash((self.uuid,))
+
def __eq__(self, other):
- if hasattr(other, 'uuid'):
- return self.uuid == other.uuid
- else:
- return False
+ if isinstance(other, BaseElement):
+ return hash(self) == hash(other)
+ return NotImplemented
def touch(self, modify=False):
"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pykeepass-4.0.4/pykeepass/entry.py
new/pykeepass-4.0.5/pykeepass/entry.py
--- old/pykeepass-4.0.4/pykeepass/entry.py 2023-05-12 08:00:19.000000000
+0200
+++ new/pykeepass-4.0.5/pykeepass/entry.py 2023-06-05 23:38:19.000000000
+0200
@@ -57,7 +57,9 @@
if notes:
self._element.append(E.String(E.Key('Notes'), E.Value(notes)))
if otp:
- self._element.append(E.String(E.Key('otp'), E.Value(otp)))
+ self._element.append(
+ E.String(E.Key('otp'), E.Value(otp, Protected="True"))
+ )
if tags:
self._element.append(
E.Tags(';'.join(tags) if type(tags) is list else tags)
@@ -383,6 +385,7 @@
pathstr = super().__str__()
return 'HistoryEntry: {}'.format(pathstr)
- def __eq__(self, other):
- # all history items share the same uuid, so examine xml directly
- return self._element == other._element
+ def __hash__(self):
+ # All history items share the same UUID with themselves and their
+ # parent, so consider the mtime also
+ return hash((self.uuid, self.mtime))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pykeepass-4.0.4/pykeepass/kdbx_parsing/pytwofish.py
new/pykeepass-4.0.5/pykeepass/kdbx_parsing/pytwofish.py
--- old/pykeepass-4.0.4/pykeepass/kdbx_parsing/pytwofish.py 2023-05-12
08:00:19.000000000 +0200
+++ new/pykeepass-4.0.5/pykeepass/kdbx_parsing/pytwofish.py 2023-06-05
23:38:19.000000000 +0200
@@ -137,11 +137,6 @@
#
import struct
-import sys
-
-WORD_BIGENDIAN = 0
-if sys.byteorder == 'big':
- WORD_BIGENDIAN = 1
def rotr32(x, n):
return (x >> n) | ((x << (32 - n)) & 0xFFFFFFFF)
@@ -149,10 +144,6 @@
def rotl32(x, n):
return ((x << n) & 0xFFFFFFFF) | (x >> (32 - n))
-def byteswap32(x):
- return ((x & 0xff) << 24) | (((x >> 8) & 0xff) << 16) | \
- (((x >> 16) & 0xff) << 8) | ((x >> 24) & 0xff)
-
class TWI:
def __init__(self):
self.k_len = 0 # word32
@@ -292,14 +283,9 @@
me_key = [0,0,0,0]
mo_key = [0,0,0,0]
for i in range(pkey.k_len):
- if WORD_BIGENDIAN:
- a = byteswap32(in_key[i + 1])
- me_key[i] = a
- b = byteswap32(in_key[i + i + 1])
- else:
- a = in_key[i + i]
- me_key[i] = a
- b = in_key[i + i + 1]
+ a = in_key[i + i]
+ me_key[i] = a
+ b = in_key[i + i + 1]
mo_key[i] = b
pkey.s_key[pkey.k_len - i - 1] = mds_rem(a, b);
for i in range(0, 40, 2):
@@ -314,16 +300,10 @@
def encrypt(pkey, in_blk):
blk = [0, 0, 0, 0]
- if WORD_BIGENDIAN:
- blk[0] = byteswap32(in_blk[0]) ^ pkey.l_key[0];
- blk[1] = byteswap32(in_blk[1]) ^ pkey.l_key[1];
- blk[2] = byteswap32(in_blk[2]) ^ pkey.l_key[2];
- blk[3] = byteswap32(in_blk[3]) ^ pkey.l_key[3];
- else:
- blk[0] = in_blk[0] ^ pkey.l_key[0];
- blk[1] = in_blk[1] ^ pkey.l_key[1];
- blk[2] = in_blk[2] ^ pkey.l_key[2];
- blk[3] = in_blk[3] ^ pkey.l_key[3];
+ blk[0] = in_blk[0] ^ pkey.l_key[0];
+ blk[1] = in_blk[1] ^ pkey.l_key[1];
+ blk[2] = in_blk[2] ^ pkey.l_key[2];
+ blk[3] = in_blk[3] ^ pkey.l_key[3];
for i in range(8):
t1 = ( pkey.mk_tab[0][byte(blk[1],3)] ^ pkey.mk_tab[1][byte(blk[1],0)]
^ pkey.mk_tab[2][byte(blk[1],1)] ^ pkey.mk_tab[3][byte(blk[1],2)] );
@@ -338,32 +318,20 @@
blk[0] = rotr32(blk[0] ^ ((t0 + t1 + pkey.l_key[4 * (i) + 10]) %
0x100000000), 1);
blk[1] = rotl32(blk[1], 1) ^ ((t0 + 2 * t1 + pkey.l_key[4 * (i) + 11])
% 0x100000000);
- if WORD_BIGENDIAN:
- in_blk[0] = byteswap32(blk[2] ^ pkey.l_key[4]);
- in_blk[1] = byteswap32(blk[3] ^ pkey.l_key[5]);
- in_blk[2] = byteswap32(blk[0] ^ pkey.l_key[6]);
- in_blk[3] = byteswap32(blk[1] ^ pkey.l_key[7]);
- else:
- in_blk[0] = blk[2] ^ pkey.l_key[4];
- in_blk[1] = blk[3] ^ pkey.l_key[5];
- in_blk[2] = blk[0] ^ pkey.l_key[6];
- in_blk[3] = blk[1] ^ pkey.l_key[7];
+ in_blk[0] = blk[2] ^ pkey.l_key[4];
+ in_blk[1] = blk[3] ^ pkey.l_key[5];
+ in_blk[2] = blk[0] ^ pkey.l_key[6];
+ in_blk[3] = blk[1] ^ pkey.l_key[7];
return
def decrypt(pkey, in_blk):
blk = [0, 0, 0, 0]
- if WORD_BIGENDIAN:
- blk[0] = byteswap32(in_blk[0]) ^ pkey.l_key[4];
- blk[1] = byteswap32(in_blk[1]) ^ pkey.l_key[5];
- blk[2] = byteswap32(in_blk[2]) ^ pkey.l_key[6];
- blk[3] = byteswap32(in_blk[3]) ^ pkey.l_key[7];
- else:
- blk[0] = in_blk[0] ^ pkey.l_key[4];
- blk[1] = in_blk[1] ^ pkey.l_key[5];
- blk[2] = in_blk[2] ^ pkey.l_key[6];
- blk[3] = in_blk[3] ^ pkey.l_key[7];
+ blk[0] = in_blk[0] ^ pkey.l_key[4];
+ blk[1] = in_blk[1] ^ pkey.l_key[5];
+ blk[2] = in_blk[2] ^ pkey.l_key[6];
+ blk[3] = in_blk[3] ^ pkey.l_key[7];
for i in range(7, -1, -1):
t1 = ( pkey.mk_tab[0][byte(blk[1],3)] ^ pkey.mk_tab[1][byte(blk[1],0)]
^ pkey.mk_tab[2][byte(blk[1],1)] ^ pkey.mk_tab[3][byte(blk[1],2)] )
@@ -378,16 +346,11 @@
blk[0] = rotl32(blk[0], 1) ^ ((t0 + t1 + pkey.l_key[4 * (i) + 8]) %
0x100000000)
blk[1] = rotr32(blk[1] ^ ((t0 + 2 * t1 + pkey.l_key[4 * (i) + 9]) %
0x100000000), 1)
- if WORD_BIGENDIAN:
- in_blk[0] = byteswap32(blk[2] ^ pkey.l_key[0]);
- in_blk[1] = byteswap32(blk[3] ^ pkey.l_key[1]);
- in_blk[2] = byteswap32(blk[0] ^ pkey.l_key[2]);
- in_blk[3] = byteswap32(blk[1] ^ pkey.l_key[3]);
- else:
- in_blk[0] = blk[2] ^ pkey.l_key[0];
- in_blk[1] = blk[3] ^ pkey.l_key[1];
- in_blk[2] = blk[0] ^ pkey.l_key[2];
- in_blk[3] = blk[1] ^ pkey.l_key[3];
+ in_blk[0] = blk[2] ^ pkey.l_key[0];
+ in_blk[1] = blk[3] ^ pkey.l_key[1];
+ in_blk[2] = blk[0] ^ pkey.l_key[2];
+ in_blk[3] = blk[1] ^ pkey.l_key[3];
+
return
__testkey =
b'\xD4\x3B\xB7\x55\x6E\xA3\x2E\x46\xF2\xA2\x82\xB7\xD4\x5B\x4E\x0D\x57\xFF\x73\x9D\x4D\xC9\x2C\x1B\xD7\xFC\x01\x70\x0C\xC8\x21\x6F'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pykeepass-4.0.4/pykeepass/version.py
new/pykeepass-4.0.5/pykeepass/version.py
--- old/pykeepass-4.0.4/pykeepass/version.py 2023-05-12 08:00:19.000000000
+0200
+++ new/pykeepass-4.0.5/pykeepass/version.py 2023-06-05 23:38:19.000000000
+0200
@@ -1,3 +1,3 @@
-__version__ = "4.0.4"
+__version__ = "4.0.5"
__all__= ["__version__"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pykeepass-4.0.4/setup.py new/pykeepass-4.0.5/setup.py
--- old/pykeepass-4.0.4/setup.py 2023-05-12 08:00:19.000000000 +0200
+++ new/pykeepass-4.0.5/setup.py 2023-06-05 23:38:19.000000000 +0200
@@ -14,6 +14,7 @@
description="Python library to interact with keepass databases "
"(supports KDBX3 and KDBX4)",
long_description=README,
+ long_description_content_type='text/x-rst',
author="Philipp Schmitt",
author_email="[email protected]",
url="https://github.com/libkeepass/pykeepass",
Binary files old/pykeepass-4.0.4/tests/test3.kdbx and
new/pykeepass-4.0.5/tests/test3.kdbx differ
Binary files old/pykeepass-4.0.4/tests/test4.kdbx and
new/pykeepass-4.0.5/tests/test4.kdbx differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pykeepass-4.0.4/tests/tests.py
new/pykeepass-4.0.5/tests/tests.py
--- old/pykeepass-4.0.4/tests/tests.py 2023-05-12 08:00:19.000000000 +0200
+++ new/pykeepass-4.0.5/tests/tests.py 2023-06-05 23:38:19.000000000 +0200
@@ -197,6 +197,8 @@
hist = entry.history
self.assertIsInstance(hist, list)
self.assertEqual(len(hist), 4)
+ self.assertEqual(len(set(hist)), 4)
+ self.assertNotEqual(hist[0], hist[1])
def test_history_path(self):
for title in ["root_entry", "subentry"]:
@@ -469,6 +471,7 @@
def test_references(self):
original_entry = self.kp.find_entries(title='foobar_entry', first=True)
+ original_entry_duplicate = self.kp.find_entries(title='foobar_entry',
first=True)
clone1 = self.kp.find_entries(title='foobar_entry - Clone', first=True)
clone2 = self.kp.find_entries(title='foobar_entry - Clone of clone',
first=True)
prefixed = self.kp.find_entries(title='foobar_entry - Clone with
prefix and suffix', first=True)
@@ -478,6 +481,10 @@
self.assertEqual(original_entry.ref('username'), clone1.username)
self.assertEqual(prefixed.deref('username'),
'domain\\{}2'.format(original_entry.username))
self.assertEqual(prefixed.deref('password'),
'A{}BC'.format(original_entry.password))
+ self.assertEqual(original_entry, original_entry_duplicate)
+ self.assertEqual(hash(original_entry), hash(original_entry_duplicate))
+ self.assertNotEqual(original_entry, clone1)
+ self.assertNotEqual(clone1, clone2)
def test_set_and_get_fields(self):
time = datetime.now().replace(microsecond=0)
@@ -953,6 +960,11 @@
self.assertEqual(results, results2)
+ def test_issue344(self):
+ # accessing expiry_time throws exception when None
+
+ e = self.kp.find_entries(title='none_date', first=True)
+ self.assertEqual(e.expiry_time, None)
class EntryFindTests4(KDBX4Tests, EntryFindTests3):
pass