diff --git a/client/lib/main.dart b/client/lib/main.dart index ab60db0..1427586 100644 --- a/client/lib/main.dart +++ b/client/lib/main.dart @@ -1,8 +1,7 @@ import 'package:flutter/cupertino.dart'; import 'package:provider/provider.dart'; -import 'repositories/grpc_credentials_client.dart'; -import 'repositories/encrypted_shared_preferences.dart'; +import 'repositories/repositories.dart'; import 'screens/authentication.dart'; import 'screens/config.dart'; diff --git a/client/lib/repositories/config_base.dart b/client/lib/repositories/config_base.dart index 674432b..3c71bf1 100644 --- a/client/lib/repositories/config_base.dart +++ b/client/lib/repositories/config_base.dart @@ -1,3 +1,5 @@ +part of 'repositories.dart'; + class ConfigBase { static const keyPrivateKey = "private_key"; static const keyConnectionConfig = "connection_config"; @@ -11,8 +13,6 @@ class ConfigBase { return _password; } - set password(String password) => _password = password; - void checkIfPasswordMatched() { if (passwordMatched) return; throw Exception('password not matched yet'); diff --git a/client/lib/repositories/encrypted_shared_preferences.dart b/client/lib/repositories/encrypted_shared_preferences.dart index a739b73..1c6c91c 100644 --- a/client/lib/repositories/encrypted_shared_preferences.dart +++ b/client/lib/repositories/encrypted_shared_preferences.dart @@ -1,13 +1,4 @@ -import 'dart:convert'; - -import 'package:shared_preferences/shared_preferences.dart'; - -import 'config_base.dart'; - -import '../types/abstracts.dart'; -import '../types/connection_config.dart'; - -import '../utils/crypto.dart' as crypto; +part of 'repositories.dart'; class EncryptedSharedPreferences extends ConfigBase implements ConfigRepo { @override @@ -19,7 +10,7 @@ class EncryptedSharedPreferences extends ConfigBase implements ConfigRepo { if (cipherText == null) return null; - final configJson = crypto.decrypt(cipherText, password); + final configJson = crypto.decrypt(cipherText, _password); return ConnectionConfig.fromJson(json.decode(configJson)); } @@ -44,7 +35,7 @@ class EncryptedSharedPreferences extends ConfigBase implements ConfigRepo { password, ); - if (passwordMatched) this.password = password; + if (passwordMatched) _password = password; return passwordMatched; } @@ -66,7 +57,7 @@ class EncryptedSharedPreferences extends ConfigBase implements ConfigRepo { final prefs = await SharedPreferences.getInstance(); final cipherText = prefs.getString(ConfigBase.keyPrivateKey); - return crypto.decrypt(cipherText, password); + return crypto.decrypt(cipherText, _password); } @override @@ -79,7 +70,7 @@ class EncryptedSharedPreferences extends ConfigBase implements ConfigRepo { prefs.setString( ConfigBase.keyConnectionConfig, - crypto.encrypt(configJson, password), + crypto.encrypt(configJson, _password), ); } @@ -87,7 +78,7 @@ class EncryptedSharedPreferences extends ConfigBase implements ConfigRepo { Future setPassword(String password) async { final prefs = await SharedPreferences.getInstance(); - this.password = password; + _password = password; passwordMatched = true; prefs.setString(ConfigBase.keyPassword, crypto.hashPassword(password)); @@ -97,6 +88,6 @@ class EncryptedSharedPreferences extends ConfigBase implements ConfigRepo { Future setPrivateKey(String key) async { final prefs = await SharedPreferences.getInstance(); - prefs.setString(ConfigBase.keyPrivateKey, crypto.encrypt(key, password)); + prefs.setString(ConfigBase.keyPrivateKey, crypto.encrypt(key, _password)); } } diff --git a/client/lib/repositories/grpc_credentials_client.dart b/client/lib/repositories/grpc_credentials_client.dart index 42c3a7b..5da95d9 100644 --- a/client/lib/repositories/grpc_credentials_client.dart +++ b/client/lib/repositories/grpc_credentials_client.dart @@ -1,14 +1,4 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; - -import 'package:grpc/grpc.dart'; -import 'package:selfpass_protobuf/credentials.pbgrpc.dart' as grpc; -import 'package:selfpass_protobuf/credentials.pb.dart' as protobuf; - -import '../types/abstracts.dart'; -import '../types/connection_config.dart'; -import '../types/credential.dart'; +part of 'repositories.dart'; class GRPCCredentialsClient implements CredentialsRepo { static GRPCCredentialsClient _instance; diff --git a/client/lib/repositories/repositories.dart b/client/lib/repositories/repositories.dart new file mode 100644 index 0000000..839d155 --- /dev/null +++ b/client/lib/repositories/repositories.dart @@ -0,0 +1,20 @@ +library repositories; + +import 'dart:convert'; +import 'dart:async'; +import 'dart:io'; + +import 'package:grpc/grpc.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:selfpass_protobuf/credentials.pbgrpc.dart' as grpc; +import 'package:selfpass_protobuf/credentials.pb.dart' as protobuf; + +import '../types/abstracts.dart'; +import '../types/connection_config.dart'; +import '../types/credential.dart'; + +import '../utils/crypto.dart' as crypto; + +part 'config_base.dart'; +part 'encrypted_shared_preferences.dart'; +part 'grpc_credentials_client.dart'; \ No newline at end of file diff --git a/client/lib/screens/authentication.dart b/client/lib/screens/authentication.dart index f2da82f..77b320b 100644 --- a/client/lib/screens/authentication.dart +++ b/client/lib/screens/authentication.dart @@ -11,18 +11,18 @@ class Authentication extends StatefulWidget { } class _AuthenticationState extends State { - final TextEditingController _passwordController = TextEditingController(); - final TextEditingController _confirmController = TextEditingController(); - bool _invalid = false; - bool _passesDontMatch = false; - ConfigRepo _config; - Future _passwordIsSet; + final TextEditingController passwordController = TextEditingController(); + final TextEditingController confirmController = TextEditingController(); + bool invalid = false; + bool passesDontMatch = false; + ConfigRepo config; + Future passwordIsSet; @override didChangeDependencies() { super.didChangeDependencies(); - _config = Provider.of(context); - _passwordIsSet = _config.passwordIsSet; + config = Provider.of(context); + passwordIsSet = config.passwordIsSet; } @override @@ -31,18 +31,18 @@ class _AuthenticationState extends State { child: Container( margin: const EdgeInsets.symmetric(horizontal: 50.0), child: FutureBuilder( - future: _passwordIsSet, + future: passwordIsSet, builder: (BuildContext context, AsyncSnapshot snapshot) => snapshot.connectionState == ConnectionState.done ? Column( - children: _buildColumnChildren(context, snapshot.data)) + children: buildColumnChildren(context, snapshot.data)) : Center(child: CupertinoActivityIndicator()), ), ), ); } - List _buildColumnChildren(BuildContext context, bool passwordIsSet) { + List buildColumnChildren(BuildContext context, bool passwordIsSet) { List children = [ const Spacer(flex: 4), const Flexible(child: Text('Master password:')), @@ -51,7 +51,7 @@ class _AuthenticationState extends State { maxLines: 1, obscure: true, autofocus: true, - controller: _passwordController, + controller: passwordController, ), ), ]; @@ -62,12 +62,12 @@ class _AuthenticationState extends State { child: TextField( maxLines: 1, obscure: true, - controller: _confirmController, + controller: confirmController, ), )); } - if (_invalid) { + if (invalid) { children.add(const Flexible( child: Text( 'invalid masterpass', @@ -76,7 +76,7 @@ class _AuthenticationState extends State { )); } - if (_passesDontMatch) { + if (passesDontMatch) { children.add(const Flexible( child: Text( 'passwords don\'t match', @@ -85,14 +85,17 @@ class _AuthenticationState extends State { )); } - children.add(CupertinoButton( - child: Text('Enter'), - onPressed: _buildEnterPressedBuilder(context), + children.add(Container( + padding: EdgeInsets.only(top: 20), + child: CupertinoButton.filled( + child: Text('Enter'), + onPressed: buildEnterPressedBuilder(context), + ), )); - if (_passesDontMatch) { + if (passesDontMatch) { children.add(const Spacer(flex: 1)); - } else if (_invalid || !passwordIsSet) { + } else if (invalid || !passwordIsSet) { children.add(const Spacer(flex: 2)); } else { children.add(const Spacer(flex: 3)); @@ -101,28 +104,28 @@ class _AuthenticationState extends State { return children; } - VoidCallback _buildEnterPressedBuilder(BuildContext context) { + VoidCallback buildEnterPressedBuilder(BuildContext context) { return () async { - if (await _passwordIsSet) { - if (await _config.matchesPasswordHash(_passwordController.text)) { + if (await passwordIsSet) { + if (await config.matchesPasswordHash(passwordController.text)) { Navigator.of(context).pushReplacementNamed('/home', - arguments: await _config.connectionConfig); + arguments: await config.connectionConfig); return; } - this.setState(() => _invalid = true); + this.setState(() => invalid = true); return; } - if (_passwordController.text != _confirmController.text) { + if (passwordController.text != confirmController.text) { this.setState(() { - _passesDontMatch = true; + passesDontMatch = true; }); return; } - _config.setPassword(_passwordController.text); - _passwordIsSet = Future.value(true); + config.setPassword(passwordController.text); + passwordIsSet = Future.value(true); Navigator.of(context).pushReplacementNamed('/config'); }; } diff --git a/client/lib/screens/config.dart b/client/lib/screens/config.dart index a8f8f70..9d2e2b3 100644 --- a/client/lib/screens/config.dart +++ b/client/lib/screens/config.dart @@ -18,98 +18,106 @@ class Config extends StatefulWidget { } class _ConfigState extends State { - TextEditingController _hostController; - TextEditingController _caCertController; - TextEditingController _certController; - TextEditingController _privateCertController; - TextEditingController _privateKeyController; - ConnectionConfig _connectionConfig; - String _privateKey; - ConfigRepo _config; + TextEditingController hostController; + TextEditingController caCertController; + TextEditingController certController; + TextEditingController privateCertController; + TextEditingController privateKeyController; + ConnectionConfig connectionConfig; + String privateKey; + ConfigRepo config; - _ConfigState(this._connectionConfig, this._privateKey) { - if (_connectionConfig == null) { - _connectionConfig = ConnectionConfig(); + _ConfigState(this.connectionConfig, this.privateKey) { + if (connectionConfig == null) { + connectionConfig = ConnectionConfig(); } - _hostController = TextEditingController(text: _connectionConfig.host); - _certController = - TextEditingController(text: _connectionConfig.certificate); - _caCertController = - TextEditingController(text: _connectionConfig.caCertificate); - _privateCertController = - TextEditingController(text: _connectionConfig.privateCertificate); + hostController = TextEditingController(text: connectionConfig.host); + certController = TextEditingController(text: connectionConfig.certificate); + caCertController = + TextEditingController(text: connectionConfig.caCertificate); + privateCertController = + TextEditingController(text: connectionConfig.privateCertificate); - _privateKeyController = TextEditingController(text: _privateKey); + privateKeyController = TextEditingController(text: privateKey); } @override didChangeDependencies() async { super.didChangeDependencies(); - _config = Provider.of(context); + config = Provider.of(context); } @override Widget build(BuildContext context) { return CupertinoPageScaffold( - navigationBar: _connectionConfig.host == null - ? null - : CupertinoNavigationBar( - trailing: GestureDetector( - onTap: _buildResetAllHandler(context), + navigationBar: CupertinoNavigationBar( + trailing: connectionConfig?.host == null + ? null + : CupertinoButton( child: Text( 'Reset', style: TextStyle(color: CupertinoColors.destructiveRed), ), + onPressed: buildResetAllHandler(context), + padding: EdgeInsets.zero, ), - ), + ), child: Container( margin: const EdgeInsets.symmetric(horizontal: 30), child: ListView(children: [ Container(margin: EdgeInsets.only(top: 10), child: Text('Host:')), - TextField(maxLines: 1, controller: _hostController), + TextField(maxLines: 1, controller: hostController), Container( margin: EdgeInsets.only(top: 5), child: Text('Private key:')), - TextField(maxLines: 1, controller: _privateKeyController), + TextField(maxLines: 1, controller: privateKeyController), Container( margin: EdgeInsets.only(top: 5), child: Text('CA certificate:')), - TextField(maxLines: 5, controller: _caCertController), + TextField(maxLines: 5, controller: caCertController), Container( margin: EdgeInsets.only(top: 5), child: Text('Client certificate:')), - TextField(maxLines: 5, controller: _certController), + TextField(maxLines: 5, controller: certController), Container( margin: EdgeInsets.only(top: 5), child: Text('Private certificate:')), - TextField(maxLines: 5, controller: _privateCertController), - CupertinoButton( - child: Text('Save'), onPressed: _makeSaveOnPressed(context)), + TextField(maxLines: 5, controller: privateCertController), + Container( + padding: EdgeInsets.symmetric(vertical: 20), + margin: EdgeInsets.symmetric(horizontal: 70), + child: CupertinoButton.filled( + child: Text('Save'), + onPressed: makeSaveOnPressed(context), + ), + ), ]), ), ); } - GestureTapCallback _buildResetAllHandler(BuildContext context) { + GestureTapCallback buildResetAllHandler(BuildContext context) { return () { showCupertinoDialog( context: context, builder: (BuildContext context) => CupertinoAlertDialog( - content: Text('Are you sure?'), + content: Text( + 'Are you sure you want to delete all config values and lock the app?', + ), actions: [ CupertinoDialogAction( isDefaultAction: true, - child: Text('Cancel'), + child: Text('No'), onPressed: () => Navigator.of(context).pop(), ), CupertinoDialogAction( isDestructiveAction: true, - child: Text('Confirm'), + child: Text('Yes'), onPressed: () async { - _connectionConfig = null; - await _config.deleteAll(); + connectionConfig = null; + await config.deleteAll(); Navigator.of(context) - .pushNamedAndRemoveUntil('/', ModalRoute.withName('/')); + .pushNamedAndRemoveUntil('/', ModalRoute.withName('/home')); }, ), ], @@ -118,17 +126,17 @@ class _ConfigState extends State { }; } - VoidCallback _makeSaveOnPressed(BuildContext context) { + VoidCallback makeSaveOnPressed(BuildContext context) { return () async { final connConfig = ConnectionConfig( - host: _hostController.text, - certificate: _certController.text, - caCertificate: _caCertController.text, - privateCertificate: _privateCertController.text, + host: hostController.text, + certificate: certController.text, + caCertificate: caCertController.text, + privateCertificate: privateCertController.text, ); - await _config.setConnectionConfig(connConfig); - await _config.setPrivateKey(_privateKeyController.text); + await config.setConnectionConfig(connConfig); + await config.setPrivateKey(privateKeyController.text); Navigator.of(context) .pushReplacementNamed('/home', arguments: connConfig); diff --git a/client/lib/screens/credential.dart b/client/lib/screens/credential.dart index 74f05af..e616452 100644 --- a/client/lib/screens/credential.dart +++ b/client/lib/screens/credential.dart @@ -1,7 +1,9 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; import 'package:otp/otp.dart'; +import 'package:provider/provider.dart'; +import '../types/abstracts.dart'; import '../types/credential.dart' as types; import '../widgets/text_field.dart'; @@ -16,26 +18,122 @@ class Credential extends StatefulWidget { } class _CredentialState extends State { - _CredentialControllers _controllers; - Map _fieldMap; - types.Credential _credential; + _CredentialControllers controllers; + Map fieldMap; + types.Credential credential; + CredentialsRepo client; - _CredentialState(this._credential) : super(); + _CredentialState(this.credential) : super() { + controllers = _CredentialControllers.fromCredential(credential); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + client = Provider.of(context); + } @override Widget build(BuildContext context) { return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar(), + navigationBar: CupertinoNavigationBar( + trailing: CupertinoButton( + child: Text( + 'Delete', + style: TextStyle(color: CupertinoColors.destructiveRed), + ), + onPressed: makeDeleteHandler(context), + padding: EdgeInsets.zero, + ), + ), child: Container( padding: const EdgeInsets.only(top: 15, bottom: 30, left: 30), child: ListView( - children: _buildFieldRows(context), + children: buildFieldRows(context), ), ), ); } - Map _buildFieldMap( + Function makeDeleteHandler(BuildContext context) { + return () { + showCupertinoDialog( + context: context, + builder: (BuildContext context) => CupertinoAlertDialog( + content: Text('Are you sure you want to delete this credential?'), + actions: [ + CupertinoDialogAction( + child: Text('No'), + isDefaultAction: true, + onPressed: () { + Navigator.of(context).pop(); + }, + ), + CupertinoDialogAction( + child: Text('Yes'), + isDestructiveAction: true, + onPressed: () async { + await client.delete(credential.meta.id); + Navigator.of(context).pushNamedAndRemoveUntil( + '/home', + ModalRoute.withName('/home'), + ); + }, + ), + ], + ), + ); + }; + } + + List buildFieldRows(BuildContext context) { + List rows = []; + + fieldMap = buildFieldMap(controllers, credential); + + fieldMap.forEach((String prefix, _FieldBuildConfig config) { + rows.add(Container( + margin: EdgeInsets.only(top: 2.5), + child: Text(prefix, style: TextStyle(fontWeight: FontWeight.w600)), + )); + + final List widgets = [ + Expanded( + flex: 3, + child: config.mutable + ? TextField( + maxLines: 1, + controller: config.controller, + obscure: config.obscured) + : Container( + margin: EdgeInsets.symmetric(vertical: 10), + child: Text(config.text)), + ), + ]; + + if (config.copyable) { + widgets.add(Expanded( + child: CupertinoButton( + child: Text(config.otp ? 'OTP' : 'Copy'), + onPressed: () => Clipboard.setData(ClipboardData( + text: config.otp + ? OTP + .generateTOTPCode(config.controller.text, + DateTime.now().millisecondsSinceEpoch) + .toString() + : config.mutable ? config.controller.text : config.text, + )), + ), + )); + } + + rows.add(Row(children: widgets)); + }); + + return rows; + } + + Map buildFieldMap( _CredentialControllers controllers, types.Credential credential, ) { @@ -55,76 +153,28 @@ class _CredentialState extends State { 'Primary:': _FieldBuildConfig(controller: controllers.primary), }; - if (credential.meta.tag != null && credential.meta.tag != '') { + if (credential.meta.tag?.isNotEmpty ?? false) { fieldMap['Tag'] = _FieldBuildConfig(controller: controllers.tag); } - if (credential.username != null && credential.username != '') { + if (credential.username?.isNotEmpty ?? false) { fieldMap['User:'] = _FieldBuildConfig(controller: controllers.username); } - if (credential.email != null && credential.email != '') { + if (credential.email?.isNotEmpty ?? false) { fieldMap['Email:'] = _FieldBuildConfig(controller: controllers.email); } fieldMap['Password:'] = _FieldBuildConfig(controller: controllers.password, obscured: true); - if (credential.otpSecret != null && credential.otpSecret != '') { - fieldMap['OTP Secret:'] = _FieldBuildConfig( + if (credential.otpSecret?.isNotEmpty ?? false) { + fieldMap['OTP Key:'] = _FieldBuildConfig( controller: controllers.otpSecret, obscured: true, otp: true); } return fieldMap; } - - List _buildFieldRows(BuildContext context) { - List rows = []; - - _controllers = _CredentialControllers.fromCredential(_credential); - _fieldMap = _buildFieldMap(_controllers, _credential); - - _fieldMap.forEach((key, value) { - rows.add(Container( - margin: EdgeInsets.only(top: 2.5), - child: Text(key, style: TextStyle(fontWeight: FontWeight.w600)), - )); - - final List widgets = [ - Expanded( - flex: 3, - child: value.mutable - ? TextField( - maxLines: 1, - controller: value.controller, - obscure: value.obscured) - : Container( - margin: EdgeInsets.symmetric(vertical: 10), - child: Text(value.text)), - ), - ]; - - if (value.copyable) { - widgets.add(Expanded( - child: CupertinoButton( - child: Text(value.otp ? 'OTP' : 'Copy'), - onPressed: () => Clipboard.setData(ClipboardData( - text: value.otp - ? OTP - .generateTOTPCode(value.controller.text, - DateTime.now().millisecondsSinceEpoch) - .toString() - : value.mutable ? value.controller.text : value.text, - )), - ), - )); - } - - rows.add(Row(children: widgets)); - }); - - return rows; - } } class _FieldBuildConfig { diff --git a/client/lib/screens/home.dart b/client/lib/screens/home.dart index 62d28c8..c85fb49 100644 --- a/client/lib/screens/home.dart +++ b/client/lib/screens/home.dart @@ -17,11 +17,11 @@ class Home extends StatefulWidget { } class _HomeState extends State with WidgetsBindingObserver { - CredentialsRepo _client; - ConfigRepo _config; - Future> _metadatas; - bool _stateIsPaused = false; - Timer _pausedStateTimer; + CredentialsRepo client; + ConfigRepo config; + Future> metadatas; + bool stateIsPaused = false; + Timer pausedStateTimer; @override void initState() { @@ -33,49 +33,51 @@ class _HomeState extends State with WidgetsBindingObserver { void didChangeDependencies() { super.didChangeDependencies(); - _config = Provider.of(context); - _client = Provider.of(context); + config = Provider.of(context); + client = Provider.of(context); - _metadatas = _client.getAllMetadata('').toList(); + metadatas = client.getAllMetadata('').toList(); } @override void didChangeAppLifecycleState(AppLifecycleState state) { - _stateIsPaused = state == AppLifecycleState.paused; + stateIsPaused = state == AppLifecycleState.paused; - if (_stateIsPaused) { - _pausedStateTimer = _newPausedStateTimer(); + if (stateIsPaused) { + pausedStateTimer = newPausedStateTimer(); return; } - if (_pausedStateTimer != null) _pausedStateTimer.cancel(); + if (pausedStateTimer != null) pausedStateTimer.cancel(); } @override Widget build(BuildContext context) { return CupertinoPageScaffold( child: FutureBuilder>( - future: _metadatas, + future: metadatas, builder: ( BuildContext context, AsyncSnapshot> snapshot, ) => (snapshot.connectionState == ConnectionState.done) ? TappableTextList( - tappableText: _buildTappableText(context, snapshot.data)) + tappableText: buildTappableText(context, snapshot.data)) : Center(child: CupertinoActivityIndicator()), ), navigationBar: CupertinoNavigationBar( - leading: GestureDetector( - child: Align( - child: Text('Lock', - style: TextStyle(color: CupertinoColors.destructiveRed)), - alignment: Alignment(-0.9, 0)), - onTap: _makeLockOnTapHandler(context), + leading: CupertinoButton( + child: Text( + 'Lock', + style: TextStyle(color: CupertinoColors.destructiveRed), + ), + onPressed: makeLockOnTapHandler(context), + padding: EdgeInsets.zero, ), - trailing: GestureDetector( + trailing: CupertinoButton( child: Icon(CupertinoIcons.gear), - onTap: _makeConfigOnTapHandler(context), + onPressed: makeConfigOnTapHandler(context), + padding: EdgeInsets.zero, ), ), ); @@ -84,21 +86,21 @@ class _HomeState extends State with WidgetsBindingObserver { @override void dispose() { WidgetsBinding.instance.removeObserver(this); - if (_pausedStateTimer != null) _pausedStateTimer.cancel(); + if (pausedStateTimer != null) pausedStateTimer.cancel(); super.dispose(); } - Timer _newPausedStateTimer() { + Timer newPausedStateTimer() { const checkPeriod = 30; return Timer(Duration(seconds: checkPeriod), () { - _config.reset(); + config.reset(); Navigator.of(context) .pushNamedAndRemoveUntil('/', ModalRoute.withName('/home')); }); } - Map _buildTappableText( + Map buildTappableText( BuildContext context, List metadatas, ) { @@ -127,18 +129,18 @@ class _HomeState extends State with WidgetsBindingObserver { return tappableText; } - GestureTapCallback _makeLockOnTapHandler(BuildContext context) { + GestureTapCallback makeLockOnTapHandler(BuildContext context) { return () { - _config.reset(); + config.reset(); Navigator.of(context) .pushNamedAndRemoveUntil('/', ModalRoute.withName('/home')); }; } - GestureTapCallback _makeConfigOnTapHandler(BuildContext context) { + GestureTapCallback makeConfigOnTapHandler(BuildContext context) { return () async => Navigator.of(context).pushNamed('/config', arguments: ConfigScreenArguments( - connectionConfig: await _config.connectionConfig, - privateKey: await _config.privateKey)); + connectionConfig: await config.connectionConfig, + privateKey: await config.privateKey)); } } diff --git a/client/lib/utils/crypto.dart b/client/lib/utils/crypto.dart index 036ee51..ad5cfcd 100644 --- a/client/lib/utils/crypto.dart +++ b/client/lib/utils/crypto.dart @@ -56,11 +56,13 @@ String encrypt(String plainText, String masterpass, [String privateKey]) { ); final random = Random.secure(); - final ivBytes = List.generate(aesBlockSize, (_) => random.nextInt(byteIntMax)); + final ivBytes = + List.generate(aesBlockSize, (_) => random.nextInt(byteIntMax)); final iv = IV(Uint8List.fromList(ivBytes)); final encrypter = Encrypter(AES(Key(key), mode: AESMode.cbc)); - final cipherBytes = List.from(encrypter.encrypt(plainText, iv: iv).bytes); + final cipherBytes = + List.from(encrypter.encrypt(plainText, iv: iv).bytes); cipherBytes.insertAll(0, ivBytes); if (privateKeyWasEmpty) { @@ -72,6 +74,30 @@ String encrypt(String plainText, String masterpass, [String privateKey]) { return base64.encode(cipherBytes); } +String generatePassword(int length, + [bool numbers = true, bool specials = true]) { + const alphaValues = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + const numberValues = '1234567890'; + const specialValues = '!@#\$%^&*()-_=+'; + + final random = Random.secure(); + List values; + + if (numbers && specials) { + values = (alphaValues + numberValues + specialValues).codeUnits; + } else if (numbers) { + values = (alphaValues + numberValues).codeUnits; + } else if (specials) { + values = (alphaValues + specialValues).codeUnits; + } + + final valuesLen = values.length; + final passValues = + List.generate(length, (_) => values[random.nextInt(valuesLen)]); + + return String.fromCharCodes(passValues); +} + const saltSize = 16; const pbkdf2Rounds = 4096; const keySize = 32; diff --git a/client/pubspec.lock b/client/pubspec.lock index 9e3abf9..9802c8c 100644 --- a/client/pubspec.lock +++ b/client/pubspec.lock @@ -35,7 +35,7 @@ packages: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "1.0.5" + version: "1.0.4" charcode: dependency: transitive description: @@ -108,7 +108,7 @@ packages: name: googleapis_auth url: "https://pub.dartlang.org" source: hosted - version: "0.2.8" + version: "0.2.10" grpc: dependency: "direct main" description: @@ -178,7 +178,7 @@ packages: name: pedantic url: "https://pub.dartlang.org" source: hosted - version: "1.8.0+1" + version: "1.7.0" pointycastle: dependency: transitive description: @@ -192,7 +192,7 @@ packages: name: protobuf url: "https://pub.dartlang.org" source: hosted - version: "0.13.12" + version: "0.13.15" provider: dependency: "direct main" description: