diff --git a/lib/kdbx.dart b/lib/kdbx.dart index f0c3bed..6911f20 100644 --- a/lib/kdbx.dart +++ b/lib/kdbx.dart @@ -9,7 +9,7 @@ export 'src/kdbx_binary.dart' show KdbxBinary; export 'src/kdbx_consts.dart'; export 'src/kdbx_custom_data.dart'; export 'src/kdbx_dao.dart' show KdbxDao; -export 'src/kdbx_entry.dart' show KdbxEntry, KdbxKey; +export 'src/kdbx_entry.dart' show KdbxEntry, KdbxKey, KdbxKeyCommon; export 'src/kdbx_file.dart'; export 'src/kdbx_format.dart' show diff --git a/lib/src/kdbx_entry.dart b/lib/src/kdbx_entry.dart index 35d347a..4ba0d42 100644 --- a/lib/src/kdbx_entry.dart +++ b/lib/src/kdbx_entry.dart @@ -18,9 +18,44 @@ import 'package:xml/xml.dart'; final _logger = Logger('kdbx.kdbx_entry'); +class KdbxKeyCommon { + static const KEY_TITLE = 'Title'; + static const KEY_URL = 'URL'; + static const KEY_USER_NAME = 'UserName'; + static const KEY_PASSWORD = 'Password'; + static const KEY_OTP = 'OTPAuth'; + + static const KdbxKey TITLE = KdbxKey._(KEY_TITLE, 'title'); + static const KdbxKey URL = KdbxKey._(KEY_URL, 'url'); + static const KdbxKey USER_NAME = KdbxKey._(KEY_USER_NAME, 'username'); + static const KdbxKey PASSWORD = KdbxKey._(KEY_PASSWORD, 'password'); + static const KdbxKey OTP = KdbxKey._(KEY_OTP, 'otpauth'); + + static const List all = [ + TITLE, + URL, + USER_NAME, + PASSWORD, + OTP, + ]; +} + +// this is called during initialization of [KdbxFormat] to make sure there are +// no typos in the constant declared above. +bool kdbxKeyCommonAssertConsistency() { + assert((() { + for (final key in KdbxKeyCommon.all) { + assert(key.key.toLowerCase() == key._canonicalKey); + } + return true; + })()); + return true; +} + /// Represents a case insensitive (but case preserving) key. class KdbxKey { KdbxKey(this.key) : _canonicalKey = key.toLowerCase(); + const KdbxKey._(this.key, this._canonicalKey); final String key; final String _canonicalKey; @@ -290,9 +325,9 @@ class KdbxEntry extends KdbxObject { } String get label => - _plainValue(KdbxKey('Title')) ?? _plainValue(KdbxKey('URL')); + _plainValue(KdbxKeyCommon.TITLE) ?? _plainValue(KdbxKeyCommon.URL); - set label(String label) => setString(KdbxKey('Title'), PlainValue(label)); + set label(String label) => setString(KdbxKeyCommon.TITLE, PlainValue(label)); /// Creates a new binary and adds it to this entry. KdbxBinary createBinary({ @@ -386,7 +421,7 @@ class KdbxEntry extends KdbxObject { mergeContext.markAsMerged(this); } - String debugLabel() => label ?? _plainValue(KdbxKey('UserName')); + String debugLabel() => label ?? _plainValue(KdbxKeyCommon.USER_NAME); @override String toString() { diff --git a/lib/src/kdbx_format.dart b/lib/src/kdbx_format.dart index 46a55c9..e46c769 100644 --- a/lib/src/kdbx_format.dart +++ b/lib/src/kdbx_format.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'dart:typed_data'; import 'package:archive/archive.dart'; +import 'package:kdbx/src/kdbx_entry.dart'; import 'package:supercharged_dart/supercharged_dart.dart'; import 'package:argon2_ffi_base/argon2_ffi_base.dart'; import 'package:convert/convert.dart' as convert; @@ -470,7 +471,7 @@ class _KeysV4 { } class KdbxFormat { - KdbxFormat([this.argon2]); + KdbxFormat([this.argon2]) : assert(kdbxKeyCommonAssertConsistency()); final Argon2 argon2; static bool dartWebWorkaround = false; diff --git a/lib/src/utils/print_utils.dart b/lib/src/utils/print_utils.dart index b93c976..8d468ba 100644 --- a/lib/src/utils/print_utils.dart +++ b/lib/src/utils/print_utils.dart @@ -24,7 +24,7 @@ class KdbxPrintUtils { forceDecrypt ? value?.getText() : value?.toString(); for (final entry in group.entries) { - final value = entry.getString(KdbxKey('Password')); + final value = entry.getString(KdbxKeyCommon.PASSWORD); buf.writeln('$indent `- ${entry.debugLabel()}: ' '${valueToSting(value)}'); if (allFields) { diff --git a/test/kdbx4_test.dart b/test/kdbx4_test.dart index e625e5b..b853c2d 100644 --- a/test/kdbx4_test.dart +++ b/test/kdbx4_test.dart @@ -24,7 +24,7 @@ void main() { final file = await kdbxFormat.read( data, Credentials(ProtectedValue.fromString('asdf'))); final firstEntry = file.body.rootGroup.entries.first; - final pwd = firstEntry.getString(KdbxKey('Password')).getText(); + final pwd = firstEntry.getString(KdbxKeyCommon.PASSWORD).getText(); expect(pwd, 'MyPassword'); }); test('Reading kdbx4_keeweb', () async { @@ -32,7 +32,7 @@ void main() { final file = await kdbxFormat.read( data, Credentials(ProtectedValue.fromString('asdf'))); final firstEntry = file.body.rootGroup.entries.first; - final pwd = firstEntry.getString(KdbxKey('Password')).getText(); + final pwd = firstEntry.getString(KdbxKeyCommon.PASSWORD).getText(); expect(pwd, 'def'); }); test('Reading kdbx4_keeweb modification time', () async { @@ -135,7 +135,7 @@ KdbxEntry _createEntry( KdbxFile file, KdbxGroup group, String username, String password) { final entry = KdbxEntry.create(file, group); group.addEntry(entry); - entry.setString(KdbxKey('UserName'), PlainValue(username)); - entry.setString(KdbxKey('Password'), ProtectedValue.fromString(password)); + entry.setString(KdbxKeyCommon.USER_NAME, PlainValue(username)); + entry.setString(KdbxKeyCommon.PASSWORD, ProtectedValue.fromString(password)); return entry; } diff --git a/test/kdbx_binaries_test.dart b/test/kdbx_binaries_test.dart index 9a6fe7d..e1556a4 100644 --- a/test/kdbx_binaries_test.dart +++ b/test/kdbx_binaries_test.dart @@ -90,7 +90,7 @@ void main() { await TestUtil.readKdbxFile('test/keepass2binaries.kdbx'); final updateEntry = (KdbxFile file) { final entry = fileRead.body.rootGroup.entries.first; - entry.setString(KdbxKey('title'), PlainValue('example')); + entry.setString(KdbxKeyCommon.TITLE, PlainValue('example')); }; updateEntry(fileRead); final saved = await fileRead.save(); diff --git a/test/kdbx_test.dart b/test/kdbx_test.dart index 05774e1..45fa15f 100644 --- a/test/kdbx_test.dart +++ b/test/kdbx_test.dart @@ -74,7 +74,7 @@ void main() { final entry = KdbxEntry.create(kdbx, rootGroup); rootGroup.addEntry(entry); entry.setString( - KdbxKey('Password'), ProtectedValue.fromString('LoremIpsum')); + KdbxKeyCommon.PASSWORD, ProtectedValue.fromString('LoremIpsum')); print(kdbx.body .generateXml(FakeProtectedSaltGenerator()) .toXmlString(pretty: true)); @@ -86,7 +86,7 @@ void main() { final file = await TestUtil.readKdbxFile('test/keepass2test.kdbx'); final first = file.body.rootGroup.entries.first; expect(file.header.version.major, 3); - expect(first.getString(KdbxKey('Title')).getText(), 'Sample Entry'); + expect(first.getString(KdbxKeyCommon.TITLE).getText(), 'Sample Entry'); final modTime = first.times.lastModificationTime.get(); expect(modTime, DateTime.utc(2020, 5, 6, 7, 31, 48)); }); @@ -96,7 +96,7 @@ void main() { { final first = file.body.rootGroup.entries.first; expect(file.header.version.major, 3); - expect(first.getString(KdbxKey('Title')).getText(), 'Sample Entry'); + expect(first.getString(KdbxKeyCommon.TITLE).getText(), 'Sample Entry'); first.times.lastModificationTime.set(newModDate); } final saved = await file.save(); @@ -118,7 +118,7 @@ void main() { final entry = KdbxEntry.create(kdbx, rootGroup); rootGroup.addEntry(entry); entry.setString( - KdbxKey('Password'), ProtectedValue.fromString('LoremIpsum')); + KdbxKeyCommon.PASSWORD, ProtectedValue.fromString('LoremIpsum')); return kdbx.save(); })(); @@ -127,7 +127,7 @@ void main() { final kdbx = await kdbxForamt.read(saved, credentials); expect( kdbx.body.rootGroup.entries.first - .getString(KdbxKey('Password')) + .getString(KdbxKeyCommon.PASSWORD) .getText(), 'LoremIpsum'); File('test.kdbx').writeAsBytesSync(saved); diff --git a/test/merge/kdbx_merge_test.dart b/test/merge/kdbx_merge_test.dart index 395522a..9a323b8 100644 --- a/test/merge/kdbx_merge_test.dart +++ b/test/merge/kdbx_merge_test.dart @@ -46,7 +46,7 @@ void main() { final fileMod = await TestUtil.saveAndRead(file); fileMod.body.rootGroup.entries.first - .setString(KdbxKey('UserName'), PlainValue('changed.')); + .setString(KdbxKeyCommon.USER_NAME, PlainValue('changed.')); _logger.info('mod date: ' + fileMod.body.rootGroup.entries.first.times.lastModificationTime .get() @@ -103,7 +103,7 @@ KdbxEntry _createEntry( KdbxFile file, KdbxGroup group, String username, String password) { final entry = KdbxEntry.create(file, group); group.addEntry(entry); - entry.setString(KdbxKey('UserName'), PlainValue(username)); - entry.setString(KdbxKey('Password'), ProtectedValue.fromString(password)); + entry.setString(KdbxKeyCommon.USER_NAME, PlainValue(username)); + entry.setString(KdbxKeyCommon.PASSWORD, ProtectedValue.fromString(password)); return entry; }