Browse Source

merge: move into recyclebin

pull/3/head
Herbert Poul 4 years ago
parent
commit
84f7974b9a
  1. 31
      bin/kdbx.dart
  2. 4
      lib/src/kdbx_entry.dart
  3. 7
      lib/src/kdbx_group.dart
  4. 41
      lib/src/utils/print_utils.dart
  5. 21
      test/merge/kdbx_merge_test.dart

31
bin/kdbx.dart

@ -8,6 +8,7 @@ import 'package:kdbx/kdbx.dart';
import 'package:kdbx/src/crypto/protected_value.dart'; import 'package:kdbx/src/crypto/protected_value.dart';
import 'package:kdbx/src/kdbx_format.dart'; import 'package:kdbx/src/kdbx_format.dart';
import 'package:kdbx/src/kdbx_group.dart'; import 'package:kdbx/src/kdbx_group.dart';
import 'package:kdbx/src/utils/print_utils.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:logging_appenders/logging_appenders.dart'; import 'package:logging_appenders/logging_appenders.dart';
import 'package:prompts/prompts.dart' as prompts; import 'package:prompts/prompts.dart' as prompts;
@ -120,32 +121,10 @@ class CatCommand extends KdbxFileCommand {
@override @override
Future<void> runWithFile(KdbxFile file) async { Future<void> runWithFile(KdbxFile file) async {
catGroup(file.body.rootGroup); final buf = StringBuffer();
} KdbxPrintUtils(forceDecrypt: forceDecrypt, allFields: allFields)
.catGroup(buf, file.body.rootGroup);
void catGroup(KdbxGroup group, {int depth = 0}) { print(buf.toString());
final indent = ' ' * depth;
print('$indent + ${group.name} (${group.uuid})');
for (final group in group.groups) {
catGroup(group, depth: depth + 1);
}
final valueToSting = (StringValue value) =>
forceDecrypt ? value?.getText() : value?.toString();
for (final entry in group.entries) {
final value = entry.getString(KdbxKey('Password'));
print('$indent `- ${entry.getString(KdbxKey('Title'))?.getText()}: '
'${valueToSting(value)}');
if (allFields) {
print(entry.stringEntries
.map((field) =>
'$indent ${field.key} = ${valueToSting(field.value)}')
.join('\n'));
}
print(entry.binaryEntries
.map((b) => '$indent `- file: ${b.key} - ${b.value.value.length}')
.join('\n'));
}
} }
} }

4
lib/src/kdbx_entry.dart

@ -386,9 +386,11 @@ class KdbxEntry extends KdbxObject {
mergeContext.markAsMerged(this); mergeContext.markAsMerged(this);
} }
String debugLabel() => label ?? _plainValue(KdbxKey('UserName'));
@override @override
String toString() { String toString() {
return 'KdbxEntry{uuid=$uuid,' return 'KdbxEntry{uuid=$uuid,'
'name=${label ?? _plainValue(KdbxKey('UserName'))}}'; 'name=${debugLabel()}}';
} }
} }

7
lib/src/kdbx_group.dart

@ -1,4 +1,5 @@
import 'package:kdbx/kdbx.dart'; import 'package:kdbx/kdbx.dart';
import 'package:kdbx/src/internal/extension_utils.dart';
import 'package:kdbx/src/kdbx_consts.dart'; import 'package:kdbx/src/kdbx_consts.dart';
import 'package:kdbx/src/kdbx_entry.dart'; import 'package:kdbx/src/kdbx_entry.dart';
import 'package:kdbx/src/kdbx_format.dart'; import 'package:kdbx/src/kdbx_format.dart';
@ -116,6 +117,7 @@ class KdbxGroup extends KdbxObject {
importToHere: (other) => importToHere: (other) =>
KdbxGroup.create(ctx: ctx, parent: this, name: other.name.get()) KdbxGroup.create(ctx: ctx, parent: this, name: other.name.get())
..forceSetUuid(other.uuid) ..forceSetUuid(other.uuid)
..let((x) => addGroup(x))
.._overwriteFrom(mergeContext, other), .._overwriteFrom(mergeContext, other),
); );
_mergeSubObjects<KdbxEntry>( _mergeSubObjects<KdbxEntry>(
@ -147,12 +149,15 @@ class KdbxGroup extends KdbxObject {
final movedObj = mergeContext.objectIndex[otherObj.uuid]; final movedObj = mergeContext.objectIndex[otherObj.uuid];
if (movedObj == null) { if (movedObj == null) {
// item was created in the other file. we have to import it // item was created in the other file. we have to import it
importToHere(otherObj); final newMeObject = importToHere(otherObj);
mergeContext.trackChange(newMeObject, debug: '(was created)');
newMeObject.merge(mergeContext, otherObj);
} else { } else {
// item was moved. // item was moved.
if (otherObj.wasMovedAfter(movedObj)) { if (otherObj.wasMovedAfter(movedObj)) {
// item was moved in the other file, so we have to move it here. // item was moved in the other file, so we have to move it here.
file.move(movedObj, this); file.move(movedObj, this);
mergeContext.trackChange(movedObj, debug: 'moved to another group');
} else { } else {
// item was moved in this file, so nothing to do. // item was moved in this file, so nothing to do.
} }

41
lib/src/utils/print_utils.dart

@ -0,0 +1,41 @@
import 'package:kdbx/src/crypto/protected_value.dart';
import 'package:kdbx/src/internal/extension_utils.dart';
import 'package:kdbx/src/kdbx_entry.dart';
import 'package:kdbx/src/kdbx_group.dart';
class KdbxPrintUtils {
KdbxPrintUtils({
this.forceDecrypt = false,
this.allFields = false,
});
final bool forceDecrypt;
final bool allFields;
String catGroupToString(KdbxGroup group) =>
(StringBuffer()..let((that) => catGroup(that, group))).toString();
void catGroup(StringBuffer buf, KdbxGroup group, {int depth = 0}) {
final indent = ' ' * depth;
buf.writeln('$indent + ${group.name.get()} (${group.uuid})');
for (final group in group.groups) {
catGroup(buf, group, depth: depth + 1);
}
final valueToSting = (StringValue value) =>
forceDecrypt ? value?.getText() : value?.toString();
for (final entry in group.entries) {
final value = entry.getString(KdbxKey('Password'));
buf.writeln('$indent `- ${entry.debugLabel()}: '
'${valueToSting(value)}');
if (allFields) {
buf.writeln(entry.stringEntries
.map((field) =>
'$indent ${field.key} = ${valueToSting(field.value)}')
.join('\n'));
}
buf.writeln(entry.binaryEntries
.map((b) => '$indent `- file: ${b.key} - ${b.value.value.length}')
.join('\n'));
}
}
}

21
test/merge/kdbx_merge_test.dart

@ -1,5 +1,6 @@
import 'package:clock/clock.dart'; import 'package:clock/clock.dart';
import 'package:kdbx/kdbx.dart'; import 'package:kdbx/kdbx.dart';
import 'package:kdbx/src/utils/print_utils.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
@ -75,6 +76,26 @@ void main() {
expect(merge.changes, hasLength(1)); expect(merge.changes, hasLength(1));
}), }),
); );
test(
'Move Entry to recycle bin',
() async => await withClock(fakeClock, () async {
final file = await createSimpleFile();
final fileMod = await TestUtil.saveAndRead(file);
expect(fileMod.recycleBin, isNull);
fileMod.deleteEntry(fileMod.body.rootGroup.entries.first);
expect(fileMod.recycleBin, isNotNull);
final file2 = await TestUtil.saveAndRead(fileMod);
final merge = file.merge(file2);
_logger.info('Merged file:\n'
'${KdbxPrintUtils().catGroupToString(file.body.rootGroup)}');
final set = Set<KdbxUuid>.from(merge.merged.keys);
expect(set, hasLength(5));
expect(Set<KdbxNode>.from(merge.changes.map<KdbxNode>((e) => e.object)),
hasLength(2));
}),
);
}); });
} }

Loading…
Cancel
Save