From bb6560b1b82cdb979c2d6b65915d82d920ab5784 Mon Sep 17 00:00:00 2001 From: Herbert Poul Date: Mon, 5 Oct 2020 11:06:20 +0200 Subject: [PATCH] keepassxc compatibility - accept kdbx 3 binaries in arbitrary sort order. --- lib/src/kdbx_entry.dart | 2 ++ lib/src/kdbx_meta.dart | 35 ++++++++++++++-------- test/kdbx_binaries_test.dart | 12 ++++++++ test/test_files/binarytest-keepassxc.kdbx | Bin 0 -> 1614 bytes 4 files changed, 37 insertions(+), 12 deletions(-) create mode 100644 test/test_files/binarytest-keepassxc.kdbx diff --git a/lib/src/kdbx_entry.dart b/lib/src/kdbx_entry.dart index 93db068..5d2f85e 100644 --- a/lib/src/kdbx_entry.dart +++ b/lib/src/kdbx_entry.dart @@ -286,6 +286,8 @@ class KdbxEntry extends KdbxObject { Iterable> get binaryEntries => _binaries.entries; + KdbxBinary getBinary(KdbxKey key) => _binaries[key]; + // Map get strings => UnmodifiableMapView(_strings); Iterable> get stringEntries => diff --git a/lib/src/kdbx_meta.dart b/lib/src/kdbx_meta.dart index 3fcb7c3..02e4dac 100644 --- a/lib/src/kdbx_meta.dart +++ b/lib/src/kdbx_meta.dart @@ -43,18 +43,29 @@ class KdbxMeta extends KdbxNode implements KdbxNodeContext { .singleElement('CustomData') ?.let((e) => KdbxCustomData.read(e)) ?? KdbxCustomData.create(), - binaries = node.singleElement(KdbxXml.NODE_BINARIES)?.let((el) sync* { - var i = 0; - for (final binaryNode in el.findElements(KdbxXml.NODE_BINARY)) { - final id = int.parse(binaryNode.getAttribute(KdbxXml.ATTR_ID)); - if (id != i) { - throw KdbxCorruptedFileException( - 'Invalid ID for binary. expected $i, but was $id'); - } - i++; - yield KdbxBinary.readBinaryXml(binaryNode, isInline: false); - } - })?.toList(), + binaries = node + .singleElement(KdbxXml.NODE_BINARIES) + ?.let((el) sync* { + for (final binaryNode in el.findElements(KdbxXml.NODE_BINARY)) { + final id = int.parse(binaryNode.getAttribute(KdbxXml.ATTR_ID)); + yield MapEntry( + id, + KdbxBinary.readBinaryXml(binaryNode, isInline: false), + ); + } + }) + ?.toList() + ?.let((binaries) { + binaries.sort((a, b) => a.key.compareTo(b.key)); + for (var i = 0; i < binaries.length; i++) { + if (i != binaries[i].key) { + throw KdbxCorruptedFileException( + 'Invalid ID for binary. expected $i,' + ' but was ${binaries[i].key}'); + } + } + return binaries.map((e) => e.value).toList(); + }), _customIcons = node .singleElement(KdbxXml.NODE_CUSTOM_ICONS) ?.let((el) sync* { diff --git a/test/kdbx_binaries_test.dart b/test/kdbx_binaries_test.dart index e1556a4..87746e9 100644 --- a/test/kdbx_binaries_test.dart +++ b/test/kdbx_binaries_test.dart @@ -122,6 +122,18 @@ void main() { // make sure the file can still be saved. await file.save(); }); + test('keepassxc compatibility', () async { + // keepass has files in arbitrary sort order. + final file = await TestUtil.readKdbxFile( + 'test/test_files/binarytest-keepassxc.kdbx'); + final entry = file.body.rootGroup.entries.first; + for (final name in ['a', 'b', 'c', 'd', 'e']) { + expect( + utf8.decode(entry.getBinary(KdbxKey('$name.txt')).value).trim(), + name, + ); + } + }); }, tags: ['kdbx3']); group('kdbx4 attachment', () { test('read binary', () async { diff --git a/test/test_files/binarytest-keepassxc.kdbx b/test/test_files/binarytest-keepassxc.kdbx new file mode 100644 index 0000000000000000000000000000000000000000..59d29c6fb73855a0ca26b8b1f5024dac89c59034 GIT binary patch literal 1614 zcmV-U2C?}A*`k_f`%AR}00RI55CAd3^5(yBLr}h01tDtuTK@wC0096100bZaA`Em+ zbcYvsv~5si1&PwK1*QlI@e4KLi2`*vWItT(1t0*6Mws4rDnzVH!dk$#TJ82fV?s?B zj`e^sw|pXFN`U(Y2mpmnJ^%m!000LN0BLIMXzbQV{arJV=9Oi43a891ybK0ZshBXz;KCZbUvc$lnTdli{PTz9yGXH}Y}Gg#pno~T5$O|pyJ*B+N%#<~nl#C(=7~!7 zml@lNUW<<^)WkKzxS;~IKQT*n)CQ9V*Puz2{!rb3z_}U+B@VvR#fj0aFVbP|`Va|y z1vTI{USie}sq9FTMY%?Lw(-Iy1dDr~-Z9t}7Yxa#@Jno~sHnpWfW7x?7Ff*DL%iUH zBVm0YvKsSQcgSp5!adKg;80PE!B=AHafP_Na2T4~`A-M>5xcH+-F$<6GZ9;o78j z^yqj$tBOLMD#J0zns@tkA9vqr1wL-$4`cry^I44FpHWsG>fsTpH2d&CX-+}sAQkb2( z^LeQ0<6N79(Ht;n7O0<6vD>0~Lfq@zYg!ulHm~69bE27lR-V_QPJpm_MOMDr9q%Ko z6>3UEU>+y%4fH8ct~2DtwIAjL<*kAM#_c;9F6`QYI5B(ajk6wBVC7cz^F+?E>C)?o|?AqH)a^-jw zTIeF3DDf57^3cJrjbNS7j}~b0%xeL{D1k7jZY)oV?-aOI@so!1YcAQ}+a^&*f9DFR z!UB@aArdjh*bYRygP3@BfVl`jQEjROT@1RDuMC8H4{g|Gb=y2(Gy~h7dVy z`y!>foM7n%kagCe>W8I9`b*UT{)%0{wXsJIuyUQ#D5v#&c!psV8@Nsx_ zl&}1^CX-IV*!Ah{jHwL0OCM=844Lqi5I3_Z*g>*)9rA=G&Vt&6_NAS7Q^Ri-4{9Yb zcr MwK#qhbTTE)Ycl5uX#fBK literal 0 HcmV?d00001