Herbert Poul
5 years ago
11 changed files with 345 additions and 39 deletions
@ -0,0 +1,5 @@ |
|||||||
|
<component name="ProjectCodeStyleConfiguration"> |
||||||
|
<state> |
||||||
|
<option name="USE_PER_PROJECT_SETTINGS" value="true" /> |
||||||
|
</state> |
||||||
|
</component> |
@ -0,0 +1,91 @@ |
|||||||
|
import 'dart:async'; |
||||||
|
import 'dart:io'; |
||||||
|
|
||||||
|
import 'package:args/args.dart'; |
||||||
|
import 'package:args/command_runner.dart'; |
||||||
|
import 'package:kdbx/src/crypto/protected_value.dart'; |
||||||
|
import 'package:kdbx/src/kdbx_format.dart'; |
||||||
|
import 'package:kdbx/src/kdbx_header.dart'; |
||||||
|
import 'package:logging/logging.dart'; |
||||||
|
import 'package:logging_appenders/logging_appenders.dart'; |
||||||
|
import 'package:prompts/prompts.dart' as prompts; |
||||||
|
|
||||||
|
final _logger = Logger('kdbx'); |
||||||
|
|
||||||
|
void main(List<String> arguments) { |
||||||
|
exitCode = 0; |
||||||
|
|
||||||
|
final runner = KdbxCommandRunner('kdbx', 'Kdbx Utility'); |
||||||
|
runner.run(arguments).catchError((dynamic error, StackTrace stackTrace) { |
||||||
|
if (error is! UsageException) { |
||||||
|
return Future<dynamic>.error(error, stackTrace); |
||||||
|
} |
||||||
|
print(error); |
||||||
|
exit(64); |
||||||
|
return null; |
||||||
|
}); |
||||||
|
|
||||||
|
// final inputFile = args['input'] as String; |
||||||
|
// if (inputFile == null) { |
||||||
|
// print('Missing Argument --input'); |
||||||
|
// print(parser.usage); |
||||||
|
// exitCode = 1; |
||||||
|
// return; |
||||||
|
// } |
||||||
|
_logger.info('done.'); |
||||||
|
} |
||||||
|
|
||||||
|
class KdbxCommandRunner extends CommandRunner<void> { |
||||||
|
KdbxCommandRunner(String executableName, String description) : super(executableName, description) { |
||||||
|
argParser.addFlag('verbose', abbr: 'v'); |
||||||
|
addCommand(CatCommand()); |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
Future<void> runCommand(ArgResults topLevelResults) { |
||||||
|
PrintAppender().attachToLogger(Logger.root); |
||||||
|
Logger.root.level = Level.INFO; |
||||||
|
if (topLevelResults['verbose'] as bool) { |
||||||
|
Logger.root.level = Level.ALL; |
||||||
|
} |
||||||
|
return super.runCommand(topLevelResults); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
abstract class KdbxFileCommand extends Command<void> { |
||||||
|
KdbxFileCommand() { |
||||||
|
argParser.addOption( |
||||||
|
'input', |
||||||
|
abbr: 'i', |
||||||
|
help: 'Input kdbx file', |
||||||
|
valueHelp: 'foo.kdbx', |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
FutureOr<void> run() async { |
||||||
|
final inputFile = argResults['input'] as String; |
||||||
|
if (inputFile == null) { |
||||||
|
usageException('Required argument: --input'); |
||||||
|
} |
||||||
|
final bytes = await File(inputFile).readAsBytes(); |
||||||
|
final password = prompts.get('Password for $inputFile', conceal: true, validate: (str) => str.isNotEmpty); |
||||||
|
final file = await KdbxFormat.read(bytes, Credentials(ProtectedValue.fromString(password))); |
||||||
|
return runWithFile(file); |
||||||
|
} |
||||||
|
|
||||||
|
Future<void> runWithFile(KdbxFile file); |
||||||
|
} |
||||||
|
|
||||||
|
class CatCommand extends KdbxFileCommand { |
||||||
|
@override |
||||||
|
String get description => 'outputs all entries from file.'; |
||||||
|
|
||||||
|
@override |
||||||
|
String get name => 'cat'; |
||||||
|
|
||||||
|
@override |
||||||
|
Future<void> runWithFile(KdbxFile file) async { |
||||||
|
_logger.severe('running'); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
import 'dart:convert'; |
||||||
|
import 'dart:typed_data'; |
||||||
|
|
||||||
|
import 'package:crypto/crypto.dart'; |
||||||
|
import 'package:pointycastle/export.dart'; |
||||||
|
|
||||||
|
class ProtectedSaltGenerator { |
||||||
|
factory ProtectedSaltGenerator(Uint8List key) { |
||||||
|
final hash = sha256.convert(key).bytes as Uint8List; |
||||||
|
final cipher = Salsa20Engine()..init(false, ParametersWithIV(KeyParameter(hash), SalsaNonce)); |
||||||
|
return ProtectedSaltGenerator._(cipher); |
||||||
|
} |
||||||
|
|
||||||
|
ProtectedSaltGenerator._(this.cipher); |
||||||
|
|
||||||
|
static final SalsaNonce = Uint8List.fromList([0xE8, 0x30, 0x09, 0x4B, 0x97, 0x20, 0x5D, 0x2A]); |
||||||
|
final StreamCipher cipher; |
||||||
|
|
||||||
|
String decryptBase64(String protectedValue) { |
||||||
|
final bytes = base64.decode(protectedValue); |
||||||
|
final result = cipher.process(bytes); |
||||||
|
final decrypted = utf8.decode(result); |
||||||
|
return decrypted; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,122 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8" standalone="yes"?> |
||||||
|
<KeePassFile> |
||||||
|
<Meta> |
||||||
|
<Generator>KdbxWeb</Generator> |
||||||
|
<HeaderHash>r9uD96EiudcSeXq62ma/OqtBBPf+EYX7iMrBaNJBRwo=</HeaderHash> |
||||||
|
<DatabaseName>FooBar</DatabaseName> |
||||||
|
<DatabaseNameChanged>2019-08-20T13:16:06Z</DatabaseNameChanged> |
||||||
|
<DatabaseDescription /> |
||||||
|
<DatabaseDescriptionChanged>2019-08-20T13:15:47Z</DatabaseDescriptionChanged> |
||||||
|
<DefaultUserName /> |
||||||
|
<DefaultUserNameChanged>2019-08-20T13:15:47Z</DefaultUserNameChanged> |
||||||
|
<MaintenanceHistoryDays>365</MaintenanceHistoryDays> |
||||||
|
<Color /> |
||||||
|
<MasterKeyChanged>2019-08-20T13:16:03Z</MasterKeyChanged> |
||||||
|
<MasterKeyChangeRec>-1</MasterKeyChangeRec> |
||||||
|
<MasterKeyChangeForce>-1</MasterKeyChangeForce> |
||||||
|
<RecycleBinEnabled>True</RecycleBinEnabled> |
||||||
|
<RecycleBinUUID>dVSBC/BAx70qcsy6XkrGJA==</RecycleBinUUID> |
||||||
|
<RecycleBinChanged>2019-08-20T13:15:47Z</RecycleBinChanged> |
||||||
|
<EntryTemplatesGroup>AAAAAAAAAAAAAAAAAAAAAA==</EntryTemplatesGroup> |
||||||
|
<EntryTemplatesGroupChanged>2019-08-20T13:15:47Z</EntryTemplatesGroupChanged> |
||||||
|
<HistoryMaxItems>10</HistoryMaxItems> |
||||||
|
<HistoryMaxSize>6291456</HistoryMaxSize> |
||||||
|
<LastSelectedGroup /> |
||||||
|
<LastTopVisibleGroup /> |
||||||
|
<MemoryProtection> |
||||||
|
<ProtectTitle>False</ProtectTitle> |
||||||
|
<ProtectUserName>False</ProtectUserName> |
||||||
|
<ProtectPassword>True</ProtectPassword> |
||||||
|
<ProtectURL>False</ProtectURL> |
||||||
|
<ProtectNotes>False</ProtectNotes> |
||||||
|
</MemoryProtection> |
||||||
|
<CustomIcons /> |
||||||
|
<Binaries /> |
||||||
|
<CustomData /> |
||||||
|
</Meta> |
||||||
|
<Root> |
||||||
|
<Group> |
||||||
|
<UUID>LAQMkihXTkxhA2D2tE40Fg==</UUID> |
||||||
|
<Name>FooBar</Name> |
||||||
|
<Notes /> |
||||||
|
<IconID>49</IconID> |
||||||
|
<Times> |
||||||
|
<CreationTime>2019-08-20T13:15:47Z</CreationTime> |
||||||
|
<LastModificationTime>2019-08-20T13:16:06Z</LastModificationTime> |
||||||
|
<LastAccessTime>2019-08-20T13:16:06Z</LastAccessTime> |
||||||
|
<ExpiryTime>2019-08-20T13:15:47Z</ExpiryTime> |
||||||
|
<Expires>False</Expires> |
||||||
|
<UsageCount>0</UsageCount> |
||||||
|
<LocationChanged>2019-08-20T13:15:47Z</LocationChanged> |
||||||
|
</Times> |
||||||
|
<IsExpanded>True</IsExpanded> |
||||||
|
<DefaultAutoTypeSequence /> |
||||||
|
<EnableAutoType>null</EnableAutoType> |
||||||
|
<EnableSearching>null</EnableSearching> |
||||||
|
<LastTopVisibleEntry>AAAAAAAAAAAAAAAAAAAAAA==</LastTopVisibleEntry> |
||||||
|
<Group> |
||||||
|
<UUID>dVSBC/BAx70qcsy6XkrGJA==</UUID> |
||||||
|
<Name>Recycle Bin</Name> |
||||||
|
<Notes /> |
||||||
|
<IconID>43</IconID> |
||||||
|
<Times> |
||||||
|
<CreationTime>2019-08-20T13:15:47Z</CreationTime> |
||||||
|
<LastModificationTime>2019-08-20T13:15:47Z</LastModificationTime> |
||||||
|
<LastAccessTime>2019-08-20T13:15:47Z</LastAccessTime> |
||||||
|
<ExpiryTime>2019-08-20T13:15:47Z</ExpiryTime> |
||||||
|
<Expires>False</Expires> |
||||||
|
<UsageCount>0</UsageCount> |
||||||
|
<LocationChanged>2019-08-20T13:15:47Z</LocationChanged> |
||||||
|
</Times> |
||||||
|
<IsExpanded>True</IsExpanded> |
||||||
|
<DefaultAutoTypeSequence /> |
||||||
|
<EnableAutoType>False</EnableAutoType> |
||||||
|
<EnableSearching>False</EnableSearching> |
||||||
|
<LastTopVisibleEntry>AAAAAAAAAAAAAAAAAAAAAA==</LastTopVisibleEntry> |
||||||
|
</Group> |
||||||
|
<Entry> |
||||||
|
<UUID>RMUeiV24MDcrIY8qQYRAlg==</UUID> |
||||||
|
<IconID>0</IconID> |
||||||
|
<ForegroundColor /> |
||||||
|
<BackgroundColor /> |
||||||
|
<OverrideURL /> |
||||||
|
<Tags /> |
||||||
|
<Times> |
||||||
|
<CreationTime>2019-08-21T00:17:25Z</CreationTime> |
||||||
|
<LastModificationTime>2019-08-21T00:17:36Z</LastModificationTime> |
||||||
|
<LastAccessTime>2019-08-21T00:17:36Z</LastAccessTime> |
||||||
|
<ExpiryTime>2019-08-21T00:17:25Z</ExpiryTime> |
||||||
|
<Expires>False</Expires> |
||||||
|
<UsageCount>0</UsageCount> |
||||||
|
<LocationChanged>2019-08-21T00:17:25Z</LocationChanged> |
||||||
|
</Times> |
||||||
|
<String> |
||||||
|
<Key>Title</Key> |
||||||
|
<Value>loremipsum.com</Value> |
||||||
|
</String> |
||||||
|
<String> |
||||||
|
<Key>UserName</Key> |
||||||
|
<Value>foo</Value> |
||||||
|
</String> |
||||||
|
<String> |
||||||
|
<Key>Password</Key> |
||||||
|
<Value Protected="True">QcvZ</Value> |
||||||
|
</String> |
||||||
|
<String> |
||||||
|
<Key>URL</Key> |
||||||
|
<Value /> |
||||||
|
</String> |
||||||
|
<String> |
||||||
|
<Key>Notes</Key> |
||||||
|
<Value /> |
||||||
|
</String> |
||||||
|
<AutoType> |
||||||
|
<Enabled>True</Enabled> |
||||||
|
<DataTransferObfuscation>0</DataTransferObfuscation> |
||||||
|
</AutoType> |
||||||
|
<History /> |
||||||
|
</Entry> |
||||||
|
</Group> |
||||||
|
<DeletedObjects /> |
||||||
|
</Root> |
||||||
|
</KeePassFile> |
Loading…
Reference in new issue