diff --git a/.idea/dictionaries/herbert.xml b/.idea/dictionaries/herbert.xml index c96d2ea..c942ae1 100644 --- a/.idea/dictionaries/herbert.xml +++ b/.idea/dictionaries/herbert.xml @@ -6,6 +6,7 @@ encrypter hmac kdbx + keepass \ No newline at end of file diff --git a/lib/src/kdbx_header.dart b/lib/src/kdbx_header.dart index 2cb7365..06454d0 100644 --- a/lib/src/kdbx_header.dart +++ b/lib/src/kdbx_header.dart @@ -227,18 +227,26 @@ class KdbxHeader { _validateInner(); for (final field in InnerHeaderFields.values .where((f) => f != InnerHeaderFields.EndOfHeader)) { - _writeInnerField(writer, field); + _writeInnerFieldIfExist(writer, field); + } + // write attachments + for (final binary in innerHeader.binaries) { + _writeInnerField(writer, binary); } - // TODO write attachments _setInnerHeaderField(InnerHeaderFields.EndOfHeader, Uint8List(0)); - _writeInnerField(writer, InnerHeaderFields.EndOfHeader); + _writeInnerFieldIfExist(writer, InnerHeaderFields.EndOfHeader); } - void _writeInnerField(WriterHelper writer, InnerHeaderFields field) { + void _writeInnerFieldIfExist(WriterHelper writer, InnerHeaderFields field) { final value = innerHeader.fields[field]; if (value == null) { return; } + _writeInnerField(writer, value); + } + + void _writeInnerField(WriterHelper writer, InnerHeaderField value) { + final field = value.field; _logger.finer( 'Writing header $field (${field.index}) (${value.bytes.lengthInBytes})'); writer.writeUint8(field.index); @@ -438,6 +446,11 @@ class KdbxCorruptedFileException implements KdbxException { KdbxCorruptedFileException([this.message]); final String message; + + @override + String toString() { + return 'KdbxCorruptedFileException{message: $message}'; + } } class KdbxUnsupportedException implements KdbxException { diff --git a/test/internal/test_utils.dart b/test/internal/test_utils.dart index 873d35b..8d788e4 100644 --- a/test/internal/test_utils.dart +++ b/test/internal/test_utils.dart @@ -1,6 +1,7 @@ //typedef HashStuff = Pointer Function(Pointer str); import 'dart:ffi'; import 'dart:io'; +import 'dart:typed_data'; import 'package:ffi/ffi.dart'; import 'package:kdbx/kdbx.dart'; @@ -55,4 +56,12 @@ class TestUtil { data, Credentials(ProtectedValue.fromString(password))); return file; } + + static Future readKdbxFileBytes(Uint8List data, + {String password = 'asdf'}) async { + final kdbxFormat = KdbxFormat(Argon2Test()); + final file = await kdbxFormat.read( + data, Credentials(ProtectedValue.fromString(password))); + return file; + } } diff --git a/test/kdbx_binaries_test.dart b/test/kdbx_binaries_test.dart index 1a92ee4..b05a8ab 100644 --- a/test/kdbx_binaries_test.dart +++ b/test/kdbx_binaries_test.dart @@ -8,14 +8,20 @@ import 'package:test/test.dart'; import 'internal/test_utils.dart'; +void expectBinary(KdbxEntry entry, String key, dynamic matcher) { + final binaries = entry.binaryEntries; + expect(binaries, hasLength(1)); + final binary = binaries.first; + expect(binary.key.key, key); + expect(binary.value.value, matcher); +} + void main() { Logger.root.level = Level.ALL; PrintAppender().attachToLogger(Logger.root); group('kdbx3 attachment', () { - test('read binary', () async { - final file = await TestUtil.readKdbxFile('test/keepass2binaries.kdbx'); - final entry = file.body.rootGroup.entries.first; + void expectKeepass2binariesContents(KdbxEntry entry) { final binaries = entry.binaryEntries; expect(binaries, hasLength(3)); for (final binary in binaries) { @@ -33,19 +39,26 @@ void main() { fail('invalid key. ${binary.key}'); } } + } + + test('read binary', () async { + final file = await TestUtil.readKdbxFile('test/keepass2binaries.kdbx'); + final entry = file.body.rootGroup.entries.first; + expectKeepass2binariesContents(entry); + }); + test('read write read', () async { + final fileRead = + await TestUtil.readKdbxFile('test/keepass2binaries.kdbx'); + final saved = await fileRead.save(); + final file = await TestUtil.readKdbxFileBytes(saved); + final entry = file.body.rootGroup.entries.first; + expectKeepass2binariesContents(entry); }); }); group('kdbx4 attachment', () { test('read binary', () async { final file = await TestUtil.readKdbxFile('test/keepass2kdbx4binaries.kdbx'); - void expectBinary(KdbxEntry entry, String key, dynamic matcher) { - final binaries = entry.binaryEntries; - expect(binaries, hasLength(1)); - final binary = binaries.first; - expect(binary.key.key, key); - expect(binary.value.value, matcher); - } expect(file.body.rootGroup.entries, hasLength(2)); expectBinary(file.body.rootGroup.entries.first, 'example2.txt', @@ -54,6 +67,17 @@ void main() { hasLength(7092)); }); }); + test('read, write, read', () async { + final fileRead = + await TestUtil.readKdbxFile('test/keepass2kdbx4binaries.kdbx'); + final saved = await fileRead.save(); + final file = await TestUtil.readKdbxFileBytes(saved); + expect(file.body.rootGroup.entries, hasLength(2)); + expectBinary(file.body.rootGroup.entries.first, 'example2.txt', + IsUtf8String('content2 example\n\n')); + expectBinary( + file.body.rootGroup.entries.last, 'keepasslogo.jpeg', hasLength(7092)); + }); } class IsUtf8String extends CustomMatcher {