From 36007bbe4a3dc25213b47aba16ef9d1a8f0c90a2 Mon Sep 17 00:00:00 2001 From: Herbert Poul Date: Wed, 8 Sep 2021 09:08:47 +0200 Subject: [PATCH] add support for CustomData in entries. --- CHANGELOG.md | 1 + lib/src/kdbx_custom_data.dart | 16 +++++++++++++++- lib/src/kdbx_entry.dart | 11 ++++++++++- lib/src/kdbx_meta.dart | 9 ++------- lib/src/kdbx_xml.dart | 1 + 5 files changed, 29 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e2b039..4b0031a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - Mark objects only as clean when saving was successful. - Only mark objects as clean if they have not been modified since we started saving. - Make credentials changeable. +- Add support for CustomData in entries. ## 2.2.0 diff --git a/lib/src/kdbx_custom_data.dart b/lib/src/kdbx_custom_data.dart index f5b9e59..c319136 100644 --- a/lib/src/kdbx_custom_data.dart +++ b/lib/src/kdbx_custom_data.dart @@ -17,7 +17,7 @@ class KdbxCustomData extends KdbxNode { })), super.read(node); - static const String TAG_NAME = 'CustomData'; + static const String TAG_NAME = KdbxXml.NODE_CUSTOM_DATA; final Map _data; @@ -43,4 +43,18 @@ class KdbxCustomData extends KdbxNode { ); return el; } + + void merge(KdbxCustomData other, bool otherIsNewer) { + // merge custom data + for (final otherCustomDataEntry in other.entries) { + if (otherIsNewer || !containsKey(otherCustomDataEntry.key)) { + this[otherCustomDataEntry.key] = otherCustomDataEntry.value; + } + } + } + + void overwriteFrom(KdbxCustomData other) { + _data.clear(); + _data.addAll(other._data); + } } diff --git a/lib/src/kdbx_entry.dart b/lib/src/kdbx_entry.dart index 3b3b168..c29c5fa 100644 --- a/lib/src/kdbx_entry.dart +++ b/lib/src/kdbx_entry.dart @@ -5,6 +5,7 @@ import 'package:kdbx/src/crypto/protected_value.dart'; import 'package:kdbx/src/internal/extension_utils.dart'; import 'package:kdbx/src/kdbx_binary.dart'; import 'package:kdbx/src/kdbx_consts.dart'; +import 'package:kdbx/src/kdbx_custom_data.dart'; import 'package:kdbx/src/kdbx_exceptions.dart'; import 'package:kdbx/src/kdbx_file.dart'; import 'package:kdbx/src/kdbx_format.dart'; @@ -127,6 +128,7 @@ extension KdbxEntryInternal on KdbxEntry { )); _binaries.clear(); _binaries.addAll(newBinaries); + customData.overwriteFrom(other.customData); times.overwriteFrom(other.times); if (includeHistory) { for (final historyEntry in other.history) { @@ -157,6 +159,7 @@ class KdbxEntry extends KdbxObject { KdbxGroup parent, { this.isHistoryEntry = false, }) : history = [], + customData = KdbxCustomData.create(), super.create(file.ctx, file, 'Entry', parent) { icon.set(KdbxIcon.Key); } @@ -164,6 +167,10 @@ class KdbxEntry extends KdbxObject { KdbxEntry.read(KdbxReadWriteContext ctx, KdbxGroup? parent, XmlElement node, {this.isHistoryEntry = false}) : history = [], + customData = node + .singleElement(KdbxXml.NODE_CUSTOM_DATA) + ?.let((e) => KdbxCustomData.read(e)) ?? + KdbxCustomData.create(), super.read(ctx, parent, node) { _strings.addEntries(node.findElements(KdbxXml.NODE_STRING).map((el) { final key = KdbxKey(el.findElements(KdbxXml.NODE_KEY).single.text); @@ -210,6 +217,8 @@ class KdbxEntry extends KdbxObject { StringNode get overrideURL => StringNode(this, 'OverrideURL'); StringNode get tags => StringNode(this, 'Tags'); + final KdbxCustomData customData; + @override set file(KdbxFile file) { super.file = file; @@ -233,7 +242,7 @@ class KdbxEntry extends KdbxObject { @override XmlElement toXml() { - final el = super.toXml(); + final el = super.toXml()..replaceSingle(customData.toXml()); XmlUtils.removeChildrenByName(el, KdbxXml.NODE_STRING); XmlUtils.removeChildrenByName(el, KdbxXml.NODE_HISTORY); XmlUtils.removeChildrenByName(el, KdbxXml.NODE_BINARY); diff --git a/lib/src/kdbx_meta.dart b/lib/src/kdbx_meta.dart index 393c726..e314adb 100644 --- a/lib/src/kdbx_meta.dart +++ b/lib/src/kdbx_meta.dart @@ -39,7 +39,7 @@ class KdbxMeta extends KdbxNode implements KdbxNodeContext { KdbxMeta.read(xml.XmlElement node, this.ctx) : customData = node - .singleElement('CustomData') + .singleElement(KdbxXml.NODE_CUSTOM_DATA) ?.let((e) => KdbxCustomData.read(e)) ?? KdbxCustomData.create(), binaries = node @@ -206,13 +206,8 @@ class KdbxMeta extends KdbxNode implements KdbxNodeContext { recycleBinChanged.set(other.recycleBinChanged.get()); } final otherIsNewer = other.settingsChanged.isAfter(settingsChanged); - // merge custom data - for (final otherCustomDataEntry in other.customData.entries) { - if (otherIsNewer || !customData.containsKey(otherCustomDataEntry.key)) { - customData[otherCustomDataEntry.key] = otherCustomDataEntry.value; - } - } + customData.merge(other.customData, otherIsNewer); // merge custom icons for (final otherCustomIcon in other._customIcons.values) { _customIcons[otherCustomIcon.uuid] ??= otherCustomIcon; diff --git a/lib/src/kdbx_xml.dart b/lib/src/kdbx_xml.dart index e745f10..1ee2a7c 100644 --- a/lib/src/kdbx_xml.dart +++ b/lib/src/kdbx_xml.dart @@ -30,6 +30,7 @@ class KdbxXml { static const ATTR_REF = 'Ref'; static const NODE_PREVIOUS_PARENT_GROUP = 'PreviousParentGroup'; static const NODE_CUSTOM_ICONS = 'CustomIcons'; + static const NODE_CUSTOM_DATA = 'CustomData'; /// CustomIcons >> Icon static const NODE_ICON = 'Icon';