Add decryption of credential encrypted fields; refactored config;

add app icon
This commit is contained in:
mitchell 2019-07-08 22:03:44 -04:00
parent 910bdeae12
commit 27215e6596
60 changed files with 370 additions and 151 deletions

View file

@ -105,10 +105,8 @@ class _AuthenticationState extends State<Authentication> {
return () async {
if (await _passwordIsSet) {
if (await _config.matchesPasswordHash(_passwordController.text)) {
Navigator.of(context).pushReplacementNamed(
'/home',
arguments: await _config.connectionConfig,
);
Navigator.of(context).pushReplacementNamed('/home',
arguments: await _config.connectionConfig);
return;
}

View file

@ -1,5 +1,6 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:otp/otp.dart';
import '../types/credential.dart' as types;
@ -19,17 +20,14 @@ class _CredentialState extends State<Credential> {
Map<String, _FieldBuildConfig> _fieldMap;
types.Credential _credential;
_CredentialState(this._credential) : super() {
_controllers = _CredentialControllers.fromCredential(_credential);
_fieldMap = _buildFieldMap(_controllers, _credential);
}
_CredentialState(this._credential) : super();
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(),
child: Container(
margin: const EdgeInsets.only(top: 30, left: 30),
padding: const EdgeInsets.only(top: 15, bottom: 30, left: 30),
child: ListView(
children: _buildFieldRows(context),
),
@ -43,12 +41,12 @@ class _CredentialState extends State<Credential> {
) {
final fieldMap = {
'Id:': _FieldBuildConfig(mutable: false, text: credential.meta.id),
'Created: ': _FieldBuildConfig(
'Created:': _FieldBuildConfig(
mutable: false,
copyable: false,
text: credential.meta.createdAt.toString(),
),
'Updated: ': _FieldBuildConfig(
'Updated:': _FieldBuildConfig(
mutable: false,
copyable: false,
text: credential.meta.updatedAt.toString(),
@ -69,15 +67,26 @@ class _CredentialState extends State<Credential> {
fieldMap['Email:'] = _FieldBuildConfig(controller: controllers.email);
}
fieldMap['Password:'] =
_FieldBuildConfig(controller: controllers.password, obscured: true);
if (credential.otpSecret != null && credential.otpSecret != '') {
fieldMap['OTP Secret:'] = _FieldBuildConfig(
controller: controllers.otpSecret, obscured: true, otp: true);
}
return fieldMap;
}
List<Widget> _buildFieldRows(BuildContext context) {
List<Widget> rows = [];
_controllers = _CredentialControllers.fromCredential(_credential);
_fieldMap = _buildFieldMap(_controllers, _credential);
_fieldMap.forEach((key, value) {
rows.add(Container(
margin: EdgeInsets.only(top: 10),
margin: EdgeInsets.only(top: 2.5),
child: Text(key, style: TextStyle(fontWeight: FontWeight.w600)),
));
@ -85,20 +94,27 @@ class _CredentialState extends State<Credential> {
Expanded(
flex: 3,
child: value.mutable
? TextField(maxLines: 1, controller: value.controller)
? TextField(
maxLines: 1,
controller: value.controller,
obscure: value.obscured)
: Container(
margin: EdgeInsets.symmetric(vertical: 10),
child: Text(value.text),
),
child: Text(value.text)),
),
];
if (value.copyable) {
widgets.add(Flexible(
widgets.add(Expanded(
child: CupertinoButton(
child: Text('Copy'),
child: Text(value.otp ? 'OTP' : 'Copy'),
onPressed: () => Clipboard.setData(ClipboardData(
text: value.mutable ? value.controller.text : value.text,
text: value.otp
? OTP
.generateTOTPCode(value.controller.text,
DateTime.now().millisecondsSinceEpoch)
.toString()
: value.mutable ? value.controller.text : value.text,
)),
),
));
@ -116,10 +132,14 @@ class _FieldBuildConfig {
final String text;
final bool mutable;
final bool copyable;
final bool obscured;
final bool otp;
const _FieldBuildConfig({
this.mutable = true,
this.copyable = true,
this.obscured = false,
this.otp = false,
this.controller,
this.text,
});
@ -151,5 +171,7 @@ class _CredentialControllers {
tag: TextEditingController(text: credential.meta.tag),
username: TextEditingController(text: credential.username),
email: TextEditingController(text: credential.email),
password: TextEditingController(text: credential.password),
otpSecret: TextEditingController(text: credential.otpSecret),
);
}

View file

@ -4,6 +4,8 @@ import 'package:provider/provider.dart';
import '../types/abstracts.dart';
import '../types/credential.dart';
import '../utils/crypto.dart' as crypto;
import '../widgets/tappable_text_list.dart';
class Credentials extends StatelessWidget {
@ -20,10 +22,39 @@ class Credentials extends StatelessWidget {
}
Map<String, GestureTapCallback> _buildTappableText(BuildContext context) {
var makeOnTapHandler = (String id) => () async {
final credential =
await Provider.of<CredentialsRepo>(context).get(id);
Navigator.of(context).pushNamed('/credential', arguments: credential);
final makeOnTapHandler = (String id) => () async {
showCupertinoDialog(
context: context,
builder: (BuildContext context) => CupertinoAlertDialog(
content: Column(
children: [
Text('Decrypting credential...'),
Container(
margin: EdgeInsets.only(top: 10),
child: CupertinoActivityIndicator()),
],
)),
);
final config = Provider.of<ConfigRepo>(context);
final client = Provider.of<CredentialsRepo>(context);
final Future<String> privateKey = config.privateKey;
final String password = config.password;
final credential = await client.get(id);
credential.password = crypto.decryptPassword(
password, await privateKey, credential.password);
if (credential.otpSecret != null && credential.otpSecret != '') {
credential.otpSecret = crypto.decryptPassword(
password, await privateKey, credential.otpSecret);
}
Navigator.of(context)
..pop()
..pushNamed('/credential', arguments: credential);
};
Map<String, GestureTapCallback> tappableText = {};

View file

@ -91,6 +91,7 @@ class _HomeState extends State<Home> {
GestureTapCallback _makeConfigOnTapHandler(BuildContext context) {
return () async => Navigator.of(context).pushNamed('/config',
arguments: ConfigScreenArguments(
await _config.connectionConfig, await _config.privateKey));
connectionConfig: await _config.connectionConfig,
privateKey: await _config.privateKey));
}
}