diff --git a/lib/src/kdbx_entry.dart b/lib/src/kdbx_entry.dart index ef1c9c8..c61080a 100644 --- a/lib/src/kdbx_entry.dart +++ b/lib/src/kdbx_entry.dart @@ -198,6 +198,7 @@ class KdbxEntry extends KdbxObject { set label(String label) => setString(KdbxKey('Title'), PlainValue(label)); + /// Creates a new binary and adds it to this entry. KdbxBinary createBinary({ @required bool isProtected, @required String name, @@ -219,6 +220,17 @@ class KdbxEntry extends KdbxObject { return binary; } + void removeBinary(KdbxKey binaryKey) { + final binary = _binaries.remove(binaryKey); + if (binary == null) { + throw StateError( + 'Trying to remove binary key $binaryKey does not exist.'); + } + if (!binary.isInline) { + file.ctx.removeBinary(binary); + } + } + KdbxKey _uniqueBinaryName(String fileName) { final lastIndex = fileName.lastIndexOf('.'); final baseName = diff --git a/lib/src/kdbx_format.dart b/lib/src/kdbx_format.dart index d2a5cb3..f4b7fc3 100644 --- a/lib/src/kdbx_format.dart +++ b/lib/src/kdbx_format.dart @@ -118,6 +118,15 @@ class KdbxReadWriteContext { } return id; } + + /// removes the given binary. Does not check if it is still referenced + /// in any [KdbxEntry]!! + void removeBinary(KdbxBinary binary) { + if (!_binaries.remove(binary)) { + throw KdbxCorruptedFileException( + 'Tried to remove binary which is not in this file.'); + } + } } abstract class CredentialsPart { diff --git a/test/kdbx_binaries_test.dart b/test/kdbx_binaries_test.dart index e474877..7f11692 100644 --- a/test/kdbx_binaries_test.dart +++ b/test/kdbx_binaries_test.dart @@ -88,6 +88,23 @@ void main() { test('Add new attachment', () async { await _testAddNewAttachment('test/keepass2binaries.kdbx'); }); + test('Remove attachment', () async { + final saved = await (() async { + final file = await TestUtil.readKdbxFile('test/keepass2binaries.kdbx'); + final entry = file.body.rootGroup.entries.first; + expectKeepass2binariesContents(entry); + expect(file.ctx.binariesIterable, hasLength(3)); + entry.removeBinary(KdbxKey('example1.txt')); + expect(file.ctx.binariesIterable, hasLength(2)); + return await file.save(); + })(); + final file = await TestUtil.readKdbxFileBytes(saved); + final entry = file.body.rootGroup.entries.first; + expect(entry.binaryEntries, hasLength(2)); + expect(entry.binaryEntries.map((e) => (e.key.key)), + ['example2.txt', 'keepasslogo.jpeg']); + expect(file.ctx.binariesIterable, hasLength(2)); + }); }); group('kdbx4 attachment', () { test('read binary', () async { @@ -111,6 +128,27 @@ void main() { expectBinary(file.body.rootGroup.entries.last, 'keepasslogo.jpeg', hasLength(7092)); }); + test('remove attachment kdbx4', () async { + final saved = await (() async { + final file = + await TestUtil.readKdbxFile('test/keepass2kdbx4binaries.kdbx'); + final entry = file.body.rootGroup.entries.first; + expectBinary(file.body.rootGroup.entries.first, 'example2.txt', + IsUtf8String('content2 example\n\n')); + expectBinary(file.body.rootGroup.entries.last, 'keepasslogo.jpeg', + hasLength(7092)); + expect(file.ctx.binariesIterable, hasLength(2)); + entry.removeBinary(KdbxKey('example2.txt')); + expect(file.ctx.binariesIterable, hasLength(1)); + return await file.save(); + })(); + final file = await TestUtil.readKdbxFileBytes(saved); + final entry = file.body.rootGroup.entries.first; + expect(entry.binaryEntries, hasLength(0)); + expectBinary(file.body.rootGroup.entries.last, 'keepasslogo.jpeg', + hasLength(7092)); + expect(file.ctx.binariesIterable, hasLength(1)); + }); test('Add new attachment kdbx4', () async { await _testAddNewAttachment('test/keepass2kdbx4binaries.kdbx'); });