Skip to content

Commit

Permalink
Add extra format upgrade tests
Browse files Browse the repository at this point in the history
  • Loading branch information
luckyrat committed Feb 23, 2024
1 parent 82dc44f commit f8b5408
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 20 deletions.
7 changes: 7 additions & 0 deletions lib/src/kdbx_file.dart
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,13 @@ class KdbxFile {
? header.upgradeMinor(majorVersion, minorVersion)
: header.upgrade(majorVersion, minorVersion);

// Do this even we were already in v4.x since some KDBX software (including
// earlier versions of Kee Vault) skipped this step when upgrading from <v4.
// One probably won't call this upgrade function unless the version is <4.1
// so if there are some 4.1 files with this problem, they won't be fixed.
// If that happens we could develop a "force upgrade" feature in the
// user-facing software (such as Kee Vault) and tell users to activate that
// in order to fix export compatibility with strict clients like KeePass.
upgradeDateTimeFormatV4();

body.meta.settingsChanged.setToNow();
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: kdbx
description: KeepassX format implementation in pure dart. (kdbx 3.x and 4.x support).
version: 0.6.0+3
version: 0.6.0+4
homepage: https://github.com/kee-org/kdbx.dart
publish_to: none

Expand Down
57 changes: 38 additions & 19 deletions test/kdbx_upgrade_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import 'package:kdbx/kdbx.dart';
import 'package:kdbx/src/internal/extension_utils.dart';
import 'package:kdbx/src/kdbx_xml.dart';
Expand Down Expand Up @@ -37,6 +36,7 @@ void main() {
file.upgrade(KdbxVersion.V4.major, 1);
final v4 = await TestUtil.saveAndRead(file);
expect(v4.header.version, KdbxVersion.V4_1);
checkDateValues(v4);
await TestUtil.saveTestOutput('kdbx4upgrade4-41', v4);
}, tags: 'kdbx4');

Expand All @@ -53,30 +53,49 @@ void main() {
file.upgrade(KdbxVersion.V4.major, 1);
final v4 = await TestUtil.saveAndRead(await TestUtil.saveAndRead(file));
expect(v4.header.version, KdbxVersion.V4_1);
checkDateValues(v4);
}, tags: 'kdbx4');

final metaValues = [
v4.body.meta.node.singleElement('DatabaseNameChanged')?.text,
v4.body.meta.node.singleElement('DatabaseDescriptionChanged')?.text,
v4.body.meta.node.singleElement('DefaultUserNameChanged')?.text,
v4.body.meta.node.singleElement('MasterKeyChanged')?.text,
v4.body.meta.node.singleElement('RecycleBinChanged')?.text,
v4.body.meta.node.singleElement('EntryTemplatesGroupChanged')?.text,
v4.body.meta.node.singleElement('SettingsChanged')?.text,
];
metaValues.forEach(checkIsBase64Date);
test('Forced upgrade from v4.1 with bad dates transforms date format',
() async {
final file = await TestUtil.readKdbxFile(
'test/test_files/v4_1-invalid-dates.kdbx',
password: 'asdf');
expect(file.header.version, KdbxVersion.V4_1);
file.upgrade(KdbxVersion.V4.major, 1);
final v4 = await TestUtil.saveAndRead(await TestUtil.saveAndRead(file));
expect(v4.header.version, KdbxVersion.V4_1);
checkDateValues(v4);
}, tags: 'kdbx4');

v4.body.rootGroup
.getAllEntries()
.values
.forEach(checkObjectHasBase64Dates);
v4.body.rootGroup
.getAllGroups()
.values
.forEach(checkObjectHasBase64Dates);
test('Upgrade from v4.0 with good dates', () async {
final file = await TestUtil.readKdbxFile('test/test_files/v4.0.kdbx',
password: 'FooBar');
expect(file.header.version, KdbxVersion.V4);
file.upgrade(KdbxVersion.V4.major, 1);
final v4 = await TestUtil.saveAndRead(await TestUtil.saveAndRead(file));
expect(v4.header.version, KdbxVersion.V4_1);
checkDateValues(v4);
}, tags: 'kdbx4');
}, tags: ['kdbx4']);
}

void checkDateValues(KdbxFile v4) {
final metaValues = [
v4.body.meta.node.singleElement('DatabaseNameChanged')?.text,
v4.body.meta.node.singleElement('DatabaseDescriptionChanged')?.text,
v4.body.meta.node.singleElement('DefaultUserNameChanged')?.text,
v4.body.meta.node.singleElement('MasterKeyChanged')?.text,
v4.body.meta.node.singleElement('RecycleBinChanged')?.text,
v4.body.meta.node.singleElement('EntryTemplatesGroupChanged')?.text,
v4.body.meta.node.singleElement('SettingsChanged')?.text,
];
metaValues.forEach(checkIsBase64Date);

v4.body.rootGroup.getAllEntries().values.forEach(checkObjectHasBase64Dates);
v4.body.rootGroup.getAllGroups().values.forEach(checkObjectHasBase64Dates);
}

// Sometimes the nodes can contain an XmlNodeList with a single element, rather than directly containing an XmlText node. Bug in XML lib?
// Have to work around by using deprecated text property which works no matter which approach the library decides to take this time.
void checkObjectHasBase64Dates(KdbxObject? obj) {
Expand Down
Binary file added test/test_files/v4.0.kdbx
Binary file not shown.
Binary file added test/test_files/v4_1-invalid-dates.kdbx
Binary file not shown.

0 comments on commit f8b5408

Please sign in to comment.