Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve PIN handling for creating and importing accounts #1623

Merged
merged 7 commits into from
Jan 20, 2024
9 changes: 0 additions & 9 deletions app/lib/modules/account/logic/key_type.dart

This file was deleted.

2 changes: 1 addition & 1 deletion app/lib/modules/account/logic/new_account_result.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ class NewAccountResult {
}
}

enum NewAccountResultType { ok, error, duplicateAccount, emptyPassword }
enum NewAccountResultType { ok, error, duplicateAccount }
48 changes: 13 additions & 35 deletions app/lib/modules/account/logic/new_account_store.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import 'package:flutter/material.dart';
import 'package:mobx/mobx.dart';

import 'package:encointer_wallet/modules/modules.dart';
import 'package:encointer_wallet/modules/account/logic/key_type.dart';
import 'package:encointer_wallet/service/log/log_service.dart';
import 'package:encointer_wallet/service/substrate_api/api.dart';
import 'package:encointer_wallet/store/app.dart';
import 'package:ew_keyring/ew_keyring.dart';
import 'package:provider/provider.dart';

part 'new_account_store.g.dart';

Expand All @@ -23,58 +20,41 @@ abstract class _NewAccountStoreBase with Store {
@observable
String? name;

@observable
String? password;

@observable
String? accountKey;

@observable
KeyType keyType = KeyType.mnemonic;

@readonly
bool _loading = false;

@action
void setName(String? value) => name = value;

@action
void setPassword(String? value) => password = value;

@action
void setKey(String? value) => accountKey = value;

@action
void setKeyType(KeyType value) => keyType = value;

@action
Future<NewAccountResult> generateAccount(BuildContext context) async {
final pin = password ?? context.read<LoginStore>().cachedPin;
if (pin == null) return const NewAccountResult(NewAccountResultType.emptyPassword);
return _generateAccount(context, pin);
Future<NewAccountResult> generateAccount() async {
return _generateAccount();
}

@action
Future<NewAccountResult> importAccount(BuildContext context) async {
final pin = password ?? context.read<LoginStore>().cachedPin;
if (pin == null) return const NewAccountResult(NewAccountResultType.emptyPassword);
return _importAccount(context, pin);
Future<NewAccountResult> importAccount() async {
return _importAccount();
}

@action
Future<NewAccountResult> _generateAccount(BuildContext context, String pin) async {
Future<NewAccountResult> _generateAccount() async {
try {
_loading = true;
final keyringAccount = await KeyringAccount.generate(name!);
final result = await webApi.account.importAccount(key: keyringAccount.uri, password: pin);
// pin is ignored on JS-side
final result = await webApi.account.importAccount(key: keyringAccount.uri, password: '');
if (result['error'] != null) {
_loading = false;
return const NewAccountResult(NewAccountResultType.error);
}

await context.read<LoginStore>().setPin(pin);

return saveAccount(keyringAccount, pin);
return saveAccount(keyringAccount);
} catch (e, s) {
_loading = false;
Log.e('generate account', '$e', s);
Expand All @@ -83,28 +63,26 @@ abstract class _NewAccountStoreBase with Store {
}

@action
Future<NewAccountResult> _importAccount(BuildContext context, String pin) async {
Future<NewAccountResult> _importAccount() async {
try {
_loading = true;
assert(accountKey != null && accountKey!.isNotEmpty, 'accountKey can not be null or empty');
final keyringAccount = await KeyringAccount.fromUri(name!, accountKey!);
final result = await webApi.account.importAccount(
key: accountKey!,
password: pin,
keyType: keyType.name,
password: '', // this is ignored on JS-side
keyType: keyringAccount.seedType.name,
);
if (result['error'] != null) {
_loading = false;
return const NewAccountResult(NewAccountResultType.error);
} else {
await context.read<LoginStore>().setPin(pin);

final index = appStore.account.accountList.indexWhere((i) => i.pubKey == keyringAccount.pubKeyHex);
if (index > -1) {
_loading = false;
return NewAccountResult(NewAccountResultType.duplicateAccount, newAccount: keyringAccount);
}
return saveAccount(keyringAccount, pin);
return saveAccount(keyringAccount);
}
} catch (e, s) {
_loading = false;
Expand All @@ -114,7 +92,7 @@ abstract class _NewAccountStoreBase with Store {
}

@action
Future<NewAccountResult> saveAccount(KeyringAccount account, String pin) async {
Future<NewAccountResult> saveAccount(KeyringAccount account) async {
await appStore.addAccount(account);
await appStore.setCurrentAccount(account.pubKeyHex);
await appStore.loadAccountCache();
Expand Down
74 changes: 11 additions & 63 deletions app/lib/modules/account/logic/new_account_store.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 12 additions & 9 deletions app/lib/modules/account/view/add_account_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@ class AddAccountView extends StatelessWidget {
padding: const EdgeInsets.symmetric(horizontal: 14),
child: Provider(
create: (context) => NewAccountStore(context.read<AppStore>()),
child: AddAcccountForm(),
child: AddAccountForm(),
),
),
);
}
}

class AddAcccountForm extends StatelessWidget with HandleNewAccountResultMixin {
AddAcccountForm({super.key});
class AddAccountForm extends StatelessWidget with HandleNewAccountResultMixin {
AddAccountForm({super.key});

final _formKey = GlobalKey<FormState>();

Expand Down Expand Up @@ -108,12 +108,15 @@ class AddAcccountForm extends StatelessWidget with HandleNewAccountResultMixin {
final newAccount = context.read<NewAccountStore>();
if (_formKey.currentState!.validate() && !newAccount.loading) {
newAccount.setName(_nameCtrl.text.trim());
final res = await newAccount.generateAccount(context);
await navigate(
context: context,
type: res.operationResult,
onOk: () => Navigator.of(context).popUntil((route) => route.isFirst),
);
final pin = await context.read<LoginStore>().getPin(context);
if (pin != null) {
final res = await newAccount.generateAccount();
await navigate(
context: context,
type: res.operationResult,
onOk: () => Navigator.of(context).popUntil((route) => route.isFirst),
);
}
}
},
child: Row(
Expand Down
6 changes: 3 additions & 3 deletions app/lib/modules/account/view/create_account_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ class CreateAccountView extends StatelessWidget {
padding: const EdgeInsets.symmetric(horizontal: 14),
child: Provider(
create: (context) => NewAccountStore(context.read<AppStore>()),
child: CreateAcccountForm(),
child: CreateAccountForm(),
),
),
);
}
}

class CreateAcccountForm extends StatelessWidget with HandleNewAccountResultMixin {
CreateAcccountForm({super.key});
class CreateAccountForm extends StatelessWidget with HandleNewAccountResultMixin {
CreateAccountForm({super.key});

final _formKey = GlobalKey<FormState>();

Expand Down
5 changes: 2 additions & 3 deletions app/lib/modules/account/view/create_pin_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,8 @@ class CreatePinForm extends StatelessWidget with HandleNewAccountResultMixin {
onPressed: () async {
final newAccount = context.read<NewAccountStore>();
if (_formKey.currentState!.validate() && !newAccount.loading) {
newAccount.setPassword(_passCtrl.text.trim());
final res =
fromImportPage ? await newAccount.importAccount(context) : await newAccount.generateAccount(context);
await context.read<LoginStore>().persistNewPin(_passCtrl.text.trim());
final res = fromImportPage ? await newAccount.importAccount() : await newAccount.generateAccount();
await navigate(
context: context,
type: res.operationResult,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import 'package:encointer_wallet/modules/modules.dart';
import 'package:encointer_wallet/utils/alerts/app_alert.dart';
Expand All @@ -19,10 +18,6 @@ mixin HandleNewAccountResultMixin on Widget {
errorText: context.l10n.createError,
buttontext: context.l10n.ok,
),
NewAccountResultType.emptyPassword => await LoginDialog.verifyPinOrBioAuth(
context,
onSuccess: (v) async => context.read<LoginStore>().setPin(v),
),
NewAccountResultType.duplicateAccount => onDuplicateAccount != null ? onDuplicateAccount() : null,
};
}
Expand Down
Loading
Loading