|
|
@ -1,6 +1,7 @@ |
|
|
|
@Tags(['kdbx3']) |
|
|
|
@Tags(['kdbx3']) |
|
|
|
|
|
|
|
|
|
|
|
import 'dart:io'; |
|
|
|
import 'dart:io'; |
|
|
|
|
|
|
|
import 'dart:typed_data'; |
|
|
|
|
|
|
|
|
|
|
|
import 'package:kdbx/kdbx.dart'; |
|
|
|
import 'package:kdbx/kdbx.dart'; |
|
|
|
import 'package:kdbx/src/crypto/protected_salt_generator.dart'; |
|
|
|
import 'package:kdbx/src/crypto/protected_salt_generator.dart'; |
|
|
@ -8,10 +9,13 @@ import 'package:kdbx/src/crypto/protected_value.dart'; |
|
|
|
import 'package:kdbx/src/kdbx_format.dart'; |
|
|
|
import 'package:kdbx/src/kdbx_format.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:synchronized/synchronized.dart'; |
|
|
|
import 'package:test/test.dart'; |
|
|
|
import 'package:test/test.dart'; |
|
|
|
|
|
|
|
|
|
|
|
import 'internal/test_utils.dart'; |
|
|
|
import 'internal/test_utils.dart'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
final _logger = Logger('kdbx_test'); |
|
|
|
|
|
|
|
|
|
|
|
class FakeProtectedSaltGenerator implements ProtectedSaltGenerator { |
|
|
|
class FakeProtectedSaltGenerator implements ProtectedSaltGenerator { |
|
|
|
@override |
|
|
|
@override |
|
|
|
String decryptBase64(String protectedValue) => 'fake'; |
|
|
|
String decryptBase64(String protectedValue) => 'fake'; |
|
|
@ -23,13 +27,13 @@ class FakeProtectedSaltGenerator implements ProtectedSaltGenerator { |
|
|
|
void main() { |
|
|
|
void main() { |
|
|
|
Logger.root.level = Level.ALL; |
|
|
|
Logger.root.level = Level.ALL; |
|
|
|
PrintAppender().attachToLogger(Logger.root); |
|
|
|
PrintAppender().attachToLogger(Logger.root); |
|
|
|
final kdbxForamt = KdbxFormat(); |
|
|
|
final kdbxFormat = KdbxFormat(); |
|
|
|
group('Reading', () { |
|
|
|
group('Reading', () { |
|
|
|
setUp(() {}); |
|
|
|
setUp(() {}); |
|
|
|
|
|
|
|
|
|
|
|
test('First Test', () async { |
|
|
|
test('First Test', () async { |
|
|
|
final data = await File('test/FooBar.kdbx').readAsBytes(); |
|
|
|
final data = await File('test/FooBar.kdbx').readAsBytes(); |
|
|
|
await kdbxForamt.read( |
|
|
|
await kdbxFormat.read( |
|
|
|
data, Credentials(ProtectedValue.fromString('FooBar'))); |
|
|
|
data, Credentials(ProtectedValue.fromString('FooBar'))); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
@ -41,7 +45,7 @@ void main() { |
|
|
|
final cred = Credentials.composite( |
|
|
|
final cred = Credentials.composite( |
|
|
|
ProtectedValue.fromString('asdf'), keyFileBytes); |
|
|
|
ProtectedValue.fromString('asdf'), keyFileBytes); |
|
|
|
final data = await File('test/password-and-keyfile.kdbx').readAsBytes(); |
|
|
|
final data = await File('test/password-and-keyfile.kdbx').readAsBytes(); |
|
|
|
final file = await kdbxForamt.read(data, cred); |
|
|
|
final file = await kdbxFormat.read(data, cred); |
|
|
|
expect(file.body.rootGroup.entries, hasLength(2)); |
|
|
|
expect(file.body.rootGroup.entries, hasLength(2)); |
|
|
|
}); |
|
|
|
}); |
|
|
|
test('Read with PW and hex keyfile', () async { |
|
|
|
test('Read with PW and hex keyfile', () async { |
|
|
@ -50,14 +54,14 @@ void main() { |
|
|
|
final cred = Credentials.composite( |
|
|
|
final cred = Credentials.composite( |
|
|
|
ProtectedValue.fromString('testing99'), keyFileBytes); |
|
|
|
ProtectedValue.fromString('testing99'), keyFileBytes); |
|
|
|
final data = await File('test/keyfile/newdatabase2.kdbx').readAsBytes(); |
|
|
|
final data = await File('test/keyfile/newdatabase2.kdbx').readAsBytes(); |
|
|
|
final file = await kdbxForamt.read(data, cred); |
|
|
|
final file = await kdbxFormat.read(data, cred); |
|
|
|
expect(file.body.rootGroup.entries, hasLength(3)); |
|
|
|
expect(file.body.rootGroup.entries, hasLength(3)); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
group('Creating', () { |
|
|
|
group('Creating', () { |
|
|
|
test('Simple create', () { |
|
|
|
test('Simple create', () { |
|
|
|
final kdbx = kdbxForamt.create( |
|
|
|
final kdbx = kdbxFormat.create( |
|
|
|
Credentials(ProtectedValue.fromString('FooBar')), 'CreateTest'); |
|
|
|
Credentials(ProtectedValue.fromString('FooBar')), 'CreateTest'); |
|
|
|
expect(kdbx, isNotNull); |
|
|
|
expect(kdbx, isNotNull); |
|
|
|
expect(kdbx.body.rootGroup, isNotNull); |
|
|
|
expect(kdbx.body.rootGroup, isNotNull); |
|
|
@ -68,7 +72,7 @@ void main() { |
|
|
|
.toXmlString(pretty: true)); |
|
|
|
.toXmlString(pretty: true)); |
|
|
|
}); |
|
|
|
}); |
|
|
|
test('Create Entry', () { |
|
|
|
test('Create Entry', () { |
|
|
|
final kdbx = kdbxForamt.create( |
|
|
|
final kdbx = kdbxFormat.create( |
|
|
|
Credentials(ProtectedValue.fromString('FooBar')), 'CreateTest'); |
|
|
|
Credentials(ProtectedValue.fromString('FooBar')), 'CreateTest'); |
|
|
|
final rootGroup = kdbx.body.rootGroup; |
|
|
|
final rootGroup = kdbx.body.rootGroup; |
|
|
|
final entry = KdbxEntry.create(kdbx, rootGroup); |
|
|
|
final entry = KdbxEntry.create(kdbx, rootGroup); |
|
|
@ -113,7 +117,7 @@ void main() { |
|
|
|
test('Simple save and load', () async { |
|
|
|
test('Simple save and load', () async { |
|
|
|
final credentials = Credentials(ProtectedValue.fromString('FooBar')); |
|
|
|
final credentials = Credentials(ProtectedValue.fromString('FooBar')); |
|
|
|
final saved = await (() async { |
|
|
|
final saved = await (() async { |
|
|
|
final kdbx = kdbxForamt.create(credentials, 'CreateTest'); |
|
|
|
final kdbx = kdbxFormat.create(credentials, 'CreateTest'); |
|
|
|
final rootGroup = kdbx.body.rootGroup; |
|
|
|
final rootGroup = kdbx.body.rootGroup; |
|
|
|
final entry = KdbxEntry.create(kdbx, rootGroup); |
|
|
|
final entry = KdbxEntry.create(kdbx, rootGroup); |
|
|
|
rootGroup.addEntry(entry); |
|
|
|
rootGroup.addEntry(entry); |
|
|
@ -124,7 +128,7 @@ void main() { |
|
|
|
|
|
|
|
|
|
|
|
// print(ByteUtils.toHexList(saved)); |
|
|
|
// print(ByteUtils.toHexList(saved)); |
|
|
|
|
|
|
|
|
|
|
|
final kdbx = await kdbxForamt.read(saved, credentials); |
|
|
|
final kdbx = await kdbxFormat.read(saved, credentials); |
|
|
|
expect( |
|
|
|
expect( |
|
|
|
kdbx.body.rootGroup.entries.first |
|
|
|
kdbx.body.rootGroup.entries.first |
|
|
|
.getString(KdbxKeyCommon.PASSWORD) |
|
|
|
.getString(KdbxKeyCommon.PASSWORD) |
|
|
@ -132,5 +136,30 @@ void main() { |
|
|
|
'LoremIpsum'); |
|
|
|
'LoremIpsum'); |
|
|
|
File('test.kdbx').writeAsBytesSync(saved); |
|
|
|
File('test.kdbx').writeAsBytesSync(saved); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
test('concurrent save test', () async { |
|
|
|
|
|
|
|
final file = await TestUtil.readKdbxFile('test/keepass2test.kdbx'); |
|
|
|
|
|
|
|
final readLock = Lock(); |
|
|
|
|
|
|
|
Future<KdbxFile> doSave( |
|
|
|
|
|
|
|
Future<Uint8List> byteFuture, String debug) async { |
|
|
|
|
|
|
|
_logger.fine('$debug: Waiting...'); |
|
|
|
|
|
|
|
final bytes = await byteFuture; |
|
|
|
|
|
|
|
return await readLock.synchronized(() { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
final ret = TestUtil.readKdbxFileBytes(bytes); |
|
|
|
|
|
|
|
_logger.fine('$debug FINISHED: success'); |
|
|
|
|
|
|
|
return ret; |
|
|
|
|
|
|
|
} catch (e, stackTrace) { |
|
|
|
|
|
|
|
_logger.shout( |
|
|
|
|
|
|
|
'$debug FINISHED: error while reading file', e, stackTrace); |
|
|
|
|
|
|
|
rethrow; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
final save1 = doSave(file.save(), 'first '); |
|
|
|
|
|
|
|
final save2 = doSave(file.save(), 'second'); |
|
|
|
|
|
|
|
expect((await save1).body.meta.databaseName.get(), isNotNull); |
|
|
|
|
|
|
|
expect((await save2).body.meta.databaseName.get(), isNotNull); |
|
|
|
|
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|