From 0265f99dea23732f7b559a94b1be5e5139ef3ff5 Mon Sep 17 00:00:00 2001 From: Herbert Poul Date: Mon, 26 Aug 2019 17:23:38 +0200 Subject: [PATCH] support for creating entries. --- lib/src/kdbx_consts.dart | 71 ++++++++++++++++++++++++++++++++++++++++ lib/src/kdbx_entry.dart | 5 +++ lib/src/kdbx_group.dart | 17 ++++++++-- lib/src/kdbx_object.dart | 2 ++ lib/src/kdbx_xml.dart | 43 ++++++++++++++++++++++-- test/kdbx_test.dart | 6 ++++ 6 files changed, 140 insertions(+), 4 deletions(-) create mode 100644 lib/src/kdbx_consts.dart diff --git a/lib/src/kdbx_consts.dart b/lib/src/kdbx_consts.dart new file mode 100644 index 0000000..48a05c7 --- /dev/null +++ b/lib/src/kdbx_consts.dart @@ -0,0 +1,71 @@ +enum KdbxIcon { + Key, // : 0, + World, // : 1, + Warning, // : 2, + NetworkServer, // : 3, + MarkedDirectory, // : 4, + UserCommunication, // : 5, + Parts, // : 6, + Notepad, // : 7, + WorldSocket, // : 8, + Identity, // : 9, + PaperReady, // : 10, + Digicam, // : 11, + IRCommunication, // : 12, + MultiKeys, // : 13, + Energy, // : 14, + Scanner, // : 15, + WorldStar, // : 16, + CDRom, // : 17, + Monitor, // : 18, + EMail, // : 19, + Configuration, // : 20, + ClipboardReady, // : 21, + PaperNew, // : 22, + Screen, // : 23, + EnergyCareful, // : 24, + EMailBox, // : 25, + Disk, // : 26, + Drive, // : 27, + PaperQ, // : 28, + TerminalEncrypted, // : 29, + Console, // : 30, + Printer, // : 31, + ProgramIcons, // : 32, + Run, // : 33, + Settings, // : 34, + WorldComputer, // : 35, + Archive, // : 36, + Homebanking, // : 37, + DriveWindows, // : 39, + Clock, // : 39, + EMailSearch, // : 40, + PaperFlag, // : 41, + Memory, // : 42, + TrashBin, // : 43, + Note, // : 44, + Expired, // : 45, + Info, // : 46, + Package, // : 47, + Folder, // : 48, + FolderOpen, // : 49, + FolderPackage, // : 50, + LockOpen, // : 51, + PaperLocked, // : 52, + Checked, // : 53, + Pen, // : 54, + Thumbnail, // : 55, + Book, // : 56, + List, // : 57, + UserKey, // : 58, + Tool, // : 59, + Home, // : 60, + Star, // : 61, + Tux, // : 62, + Feather, // : 63, + Apple, // : 64, + Wiki, // : 65, + Money, // : 66, + Certificate, // : 67, + BlackBerry, // : 68 +} diff --git a/lib/src/kdbx_entry.dart b/lib/src/kdbx_entry.dart index c3d72db..ba4e3a9 100644 --- a/lib/src/kdbx_entry.dart +++ b/lib/src/kdbx_entry.dart @@ -1,5 +1,6 @@ import 'package:collection/collection.dart'; import 'package:kdbx/src/crypto/protected_value.dart'; +import 'package:kdbx/src/kdbx_consts.dart'; import 'package:kdbx/src/kdbx_format.dart'; import 'package:kdbx/src/kdbx_group.dart'; import 'package:kdbx/src/kdbx_object.dart'; @@ -23,6 +24,10 @@ class KdbxKey { } class KdbxEntry extends KdbxObject { + KdbxEntry.create(this.parent) : super.create('Entry') { + icon.set(KdbxIcon.Key); + } + KdbxEntry.read(this.parent, XmlElement node) : super.read(node) { strings.addEntries(node.findElements('String').map((el) { final key = KdbxKey(el.findElements('Key').single.text); diff --git a/lib/src/kdbx_group.dart b/lib/src/kdbx_group.dart index 5678f06..362dec2 100644 --- a/lib/src/kdbx_group.dart +++ b/lib/src/kdbx_group.dart @@ -1,3 +1,4 @@ +import 'package:kdbx/src/kdbx_consts.dart'; import 'package:kdbx/src/kdbx_entry.dart'; import 'package:kdbx/src/kdbx_xml.dart'; import 'package:meta/meta.dart'; @@ -8,6 +9,8 @@ import 'kdbx_object.dart'; class KdbxGroup extends KdbxObject { KdbxGroup.create({@required this.parent, @required String name}) : super.create('Group') { this.name.set(name); + icon.set(KdbxIcon.Folder); + expanded.set(true); } KdbxGroup.read(this.parent, XmlElement node) : super.read(node) { @@ -18,7 +21,7 @@ class KdbxGroup extends KdbxObject { node .findElements('Entry') .map((el) => KdbxEntry.read(this, el)) - .forEach(entries.add); + .forEach(_entries.add); } /// Returns all groups plus this group itself. @@ -33,8 +36,18 @@ class KdbxGroup extends KdbxObject { /// null if this is the root group. final KdbxGroup parent; final List groups = []; - final List entries = []; + List get entries => List.unmodifiable(_entries); + final List _entries = []; + + void addEntry(KdbxEntry entry) { + if (entry.parent != this) { + throw StateError('Invalid operation. Trying to add entry which is already in another group.'); + } + _entries.add(entry); + node.children.add(entry.node); + } StringNode get name => StringNode(this, 'Name'); // String get name => text('Name') ?? ''; + BooleanNode get expanded => BooleanNode(this, 'IsExpanded'); } diff --git a/lib/src/kdbx_object.dart b/lib/src/kdbx_object.dart index 6a7b3d3..66965ba 100644 --- a/lib/src/kdbx_object.dart +++ b/lib/src/kdbx_object.dart @@ -41,6 +41,8 @@ abstract class KdbxObject extends KdbxNode { KdbxUuid get uuid => _uuid.get(); UuidNode get _uuid => UuidNode(this, 'UUID'); + + IconNode get icon => IconNode(this, 'IconID'); } class KdbxUuid { diff --git a/lib/src/kdbx_xml.dart b/lib/src/kdbx_xml.dart index ca4a739..ccc24ca 100644 --- a/lib/src/kdbx_xml.dart +++ b/lib/src/kdbx_xml.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'dart:typed_data'; import 'package:kdbx/kdbx.dart'; +import 'package:kdbx/src/kdbx_consts.dart'; import 'package:meta/meta.dart'; import 'package:xml/xml.dart'; @@ -30,12 +31,15 @@ abstract class KdbxSubTextNode extends KdbxSubNode { @override T get() { - return decode(_opt(name)?.text); + final textValue = _opt(name)?.text; + if (textValue == null) { + return null; + } + return decode(textValue); } @override void set(T value) { - final stringValue = encode(value); final el = node.node.findElements(name).singleWhere((x) => true, orElse: () { final el = XmlElement(XmlName(name)); @@ -43,6 +47,13 @@ abstract class KdbxSubTextNode extends KdbxSubNode { return el; }); el.children.clear(); + if (value == null) { + return; + } + final stringValue = encode(value); + if (stringValue == null) { + return; + } el.children.add(XmlText(stringValue)); } } @@ -76,3 +87,31 @@ class UuidNode extends KdbxSubTextNode { @override String encode(KdbxUuid value) => value.uuid; } + +class IconNode extends KdbxSubTextNode { + IconNode(KdbxNode node, String name) : super(node, name); + + @override + KdbxIcon decode(String value) => KdbxIcon.values[int.tryParse(value)]; + + @override + String encode(KdbxIcon value) => value.index.toString(); +} + +class BooleanNode extends KdbxSubTextNode { + BooleanNode(KdbxNode node, String name) : super(node, name); + + @override + bool decode(String value) { + switch (value) { + case 'null': return null; + case 'true': return true; + case 'false': return false; + } + throw KdbxCorruptedFileException('Invalid boolean value $value for $name'); + } + + @override + String encode(bool value) => value ? 'true' : 'false'; + +} diff --git a/test/kdbx_test.dart b/test/kdbx_test.dart index 18e2f0b..a448707 100644 --- a/test/kdbx_test.dart +++ b/test/kdbx_test.dart @@ -30,5 +30,11 @@ void main() { expect(kdbx.body.meta.databaseName.get(), 'CreateTest'); print(kdbx.body.toXml().toXmlString(pretty: true)); }); + test('Create Entry', () { + final kdbx = KdbxFormat.create(Credentials(ProtectedValue.fromString('FooBar')), 'CreateTest'); + final rootGroup = kdbx.body.rootGroup; + rootGroup.addEntry(KdbxEntry.create(rootGroup)); + print(kdbx.body.toXml().toXmlString(pretty: true)); + }); }); }