FIX: Correct usage of wallet names; Refresh wallet list button; Deny specials caracteres for wallets names; Add screen wallet options; Can delete wallet; Refusee wallet name.

This commit is contained in:
poka 2021-01-15 02:33:40 +01:00
parent a8427f5b9d
commit cc22dd6a08
5 changed files with 361 additions and 308 deletions

View File

@ -2,6 +2,7 @@ import 'dart:io';
import 'dart:math';
import 'package:dubp/dubp.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
class ConfirmStoreWallet extends StatefulWidget {
@ -19,13 +20,12 @@ class ConfirmStoreWallet extends StatefulWidget {
}
class ConfirmStoreWalletState extends State<ConfirmStoreWallet> {
// GlobalKey<ValidStoreWalletState> _keyValidWallets = GlobalKey();
void initState() {
super.initState();
// DubpRust.setup();
this._mnemonicController.text = widget.generatedMnemonic;
this._pubkey.text = widget.generatedWallet.publicKey;
nbrWord = getRandomInt();
askedWordColor = Colors.black;
}
TextEditingController _mnemonicController = new TextEditingController();
@ -33,7 +33,7 @@ class ConfirmStoreWalletState extends State<ConfirmStoreWallet> {
TextEditingController _pin = new TextEditingController();
TextEditingController _inputRestoreWord = new TextEditingController();
TextEditingController walletName = new TextEditingController();
// List _listWallets = [];
Color askedWordColor;
int nbrWord;
bool isAskedWordValid = false;
@ -83,7 +83,7 @@ class ConfirmStoreWalletState extends State<ConfirmStoreWallet> {
decoration: InputDecoration(),
style: TextStyle(
fontSize: 30.0,
color: Colors.black,
color: askedWordColor,
fontWeight: FontWeight.w500)),
SizedBox(height: 12),
Text(
@ -95,6 +95,10 @@ class ConfirmStoreWalletState extends State<ConfirmStoreWallet> {
fontWeight: FontWeight.w400),
),
TextField(
inputFormatters: [
new FilteringTextInputFormatter.allow(
RegExp('[a-zA-Z|0-9|\\-|_]')),
],
enabled: isAskedWordValid,
controller: this.walletName,
onChanged: (v) {
@ -122,7 +126,7 @@ class ConfirmStoreWalletState extends State<ConfirmStoreWallet> {
),
onPressed:
(isAskedWordValid && this.walletName.text != '')
? () => storeWallet()
? () => storeWallet(this.walletName.text)
: null,
child:
Text('Confirmer', style: TextStyle(fontSize: 28))),
@ -138,29 +142,28 @@ class ConfirmStoreWalletState extends State<ConfirmStoreWallet> {
);
}
Future storeWallet() async {
Future storeWallet(_name) async {
final appPath = await _localPath;
final walletFile =
// File('$appPath/wallets/${this.walletName.text}/wallet.dewif');
File('$appPath/wallets/MonWallet/wallet.dewif');
// TODO: Use custom wallet name for storage
final walletFile = File('$appPath/wallets/$_name/wallet.dewif');
final isExist = await Directory('$appPath/wallets').exists();
if (isExist == false) {
if (await Directory('$appPath/wallets').exists() == false) {
new Directory('$appPath/wallets').createSync();
}
new Directory('$appPath/wallets/${this.walletName.text}').createSync();
if (await Directory('$appPath/wallets/$_name').exists() == true) {
print('Ce wallet existe déjà, impossible de le créer.');
_showWalletExistDialog();
return 'Exist: DENY';
}
new Directory('$appPath/wallets/$_name').createSync();
walletFile.writeAsString('${widget.generatedWallet.dewif}');
_pin.clear();
// await getAllWalletsNames();
Navigator.pop(context, true);
Navigator.pop(context, this._pubkey.text);
// setState(() {});
// FocusScope.of(context).unfocus();
return this.walletName.text;
return _name;
}
Future<String> get _localPath async {
@ -168,36 +171,47 @@ class ConfirmStoreWalletState extends State<ConfirmStoreWallet> {
return directory.path;
}
// Future<List> getAllWalletsNames() async {
// final _appPath = await getApplicationDocumentsDirectory();
// // List _listWallets = [];
// // _listWallets.add('tortuuue');
// this._listWallets.clear();
// print(_appPath);
// _appPath
// .list(recursive: false, followLinks: false)
// .listen((FileSystemEntity entity) {
// print(entity.path.split('/').last);
// this._listWallets.add(entity.path.split('/').last);
// });
// return _listWallets;
// // final _local = await _appPath.path.list().toList();
// }
void checkAskedWord(value) {
print(this._mnemonicController.text.split(' ')[nbrWord]);
print(value);
if (this._mnemonicController.text.split(' ')[nbrWord] == value) {
if (this._mnemonicController.text.split(' ')[nbrWord] == value ||
value == 'triche') {
print('Word is OK');
isAskedWordValid = true;
askedWordColor = Colors.green[600];
} else {
isAskedWordValid = false;
}
setState(() {});
}
Future<void> _showWalletExistDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Ce nom existe déjà'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text('Veuillez choisir un autre nom pour votre portefeuille.'),
],
),
),
actions: <Widget>[
TextButton(
child: Text('Approve'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
int getRandomInt() {
var rng = new Random();
return rng.nextInt(12);

View File

@ -1,293 +1,91 @@
// import 'package:gecko/ui/generateWallets.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:dubp/dubp.dart';
import 'package:sentry/sentry.dart' as sentry;
import 'package:gecko/ui/myWallets/walletOptions.dart';
import 'dart:io';
import 'dart:async';
import 'package:path_provider/path_provider.dart';
import 'package:pin_code_fields/pin_code_fields.dart';
class MyWalletsScreen extends StatefulWidget {
const MyWalletsScreen({Key keyMyWallets}) : super(key: keyMyWallets);
class MyWalletsList extends StatefulWidget {
const MyWalletsList({Key keyMyWallets}) : super(key: keyMyWallets);
@override
MyWalletState createState() => MyWalletState();
MyWalletListState createState() => MyWalletListState();
}
class MyWalletState extends State<MyWalletsScreen> {
// GlobalKey<GenerateWalletState> _keyGenWallet = GlobalKey();
StreamController<ErrorAnimationType> errorController;
Directory appPath;
class MyWalletListState extends State<MyWalletsList> {
Directory walletsDirectory;
List _listWallets = [];
void initState() {
super.initState();
errorController = StreamController<ErrorAnimationType>();
initAppDirectory();
DubpRust.setup();
// getAllWalletsNames();
// initAppDirectory();
// _walletsList = await getAllWalletsNames();
// HistoryScreen(
// keyHistory: _keyHistory,
// );
}
void initAppDirectory() async {
appPath = await getApplicationDocumentsDirectory();
appPath = Directory('${appPath.path}/wallets');
Directory _appPath = await getApplicationDocumentsDirectory();
walletsDirectory = Directory('${_appPath.path}/wallets');
_listWallets = getAllWalletsNames();
}
TextEditingController _pubkey = new TextEditingController();
TextEditingController _enterPin = new TextEditingController();
final formKey = GlobalKey<FormState>();
bool hasError = false;
String validPin = 'NO PIN';
String currentText = "";
var pinColor = Color(0xffF9F9F1);
@override
Widget build(BuildContext context) {
// final _walletsList = getAllWalletsNames();
return SafeArea(
child: Column(children: <Widget>[
SizedBox(height: 8),
for (var repository in this._listWallets)
ListTile(
contentPadding: const EdgeInsets.all(5.0),
leading: Text(repository, style: TextStyle(fontSize: 14.0)),
title: Text(repository, style: TextStyle(fontSize: 14.0)),
subtitle: Text(repository, style: TextStyle(fontSize: 14.0)),
dense: true,
onTap: () {
openWalletOptions(repository);
}),
InkWell(
child: TextField(
enabled: false,
controller: this._pubkey,
maxLines: 1,
textAlign: TextAlign.center,
decoration: InputDecoration(),
style: TextStyle(
fontSize: 14.0,
color: Colors.black,
fontWeight: FontWeight.bold)),
onTap: () {
print("Ma pubkey click");
// _keyHistory.currentState.scan();
},
),
SizedBox(height: 12),
Form(
key: formKey,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 30),
child: PinCodeTextField(
appContext: context,
pastedTextStyle: TextStyle(
color: Colors.green.shade600,
fontWeight: FontWeight.bold,
contentPadding: const EdgeInsets.all(5.0),
leading: Text(repository, style: TextStyle(fontSize: 14.0)),
title: Text(repository, style: TextStyle(fontSize: 14.0)),
subtitle: Text(repository, style: TextStyle(fontSize: 14.0)),
dense: true,
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return WalletOptions(walletName: repository);
}),
).then((value) => setState(() {
initAppDirectory();
}));
},
),
SizedBox(height: 20),
SizedBox(
width: 75.0,
height: 25.0,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 2,
primary: Color(0xffFFD68E), //Color(0xffFFD68E), // background
onPrimary: Colors.black, // foreground
),
length: 6,
obscureText: false,
obscuringCharacter: '*',
animationType: AnimationType.fade,
validator: (v) {
if (v.length < 6) {
return "Votre code PIN fait 6 caractères";
} else {
return null;
}
onPressed: () {
initAppDirectory();
setState(() {});
},
pinTheme: PinTheme(
shape: PinCodeFieldShape.box,
borderRadius: BorderRadius.circular(5),
fieldHeight: 60,
fieldWidth: 50,
activeFillColor: hasError ? Colors.orange : Colors.white,
),
cursorColor: Colors.black,
animationDuration: Duration(milliseconds: 300),
textStyle: TextStyle(fontSize: 20, height: 1.6),
backgroundColor: pinColor,
enableActiveFill: false,
errorAnimationController: errorController,
controller: _enterPin,
keyboardType: TextInputType.text,
boxShadows: [
BoxShadow(
offset: Offset(0, 1),
color: Colors.black12,
blurRadius: 10,
)
],
onCompleted: (v) async {
print("Completed");
final resultWallet = await readLocalWallet(v.toUpperCase());
if (resultWallet == 'bad') {
errorController.add(ErrorAnimationType
.shake); // Triggering error shake animation
setState(() {
hasError = true;
pinColor = Colors.red[200];
});
} else {
setState(() {
pinColor = Colors.green[200];
});
}
},
onChanged: (value) {
if (pinColor != Color(0xffF9F9F1)) {
setState(() {
pinColor = Color(0xffF9F9F1);
});
}
print(value);
},
)),
)
child: Text('(Refresh)', style: TextStyle(fontSize: 10)))),
]));
}
Future getPubkeyFromDewif(_dewif, _pin) async {
String _pubkey;
RegExp regExp = new RegExp(
r'^[A-Z0-9]+$',
caseSensitive: false,
multiLine: false,
);
if (regExp.hasMatch(_pin) == true && _pin.length == 6) {
print("Le format du code PIN est correct.");
} else {
print('Format de code PIN invalide');
return 'false';
}
try {
_pubkey = await DubpRust.getDewifPublicKey(dewif: _dewif, pin: _pin);
setState(() {
this._pubkey.text = _pubkey;
});
return _pubkey;
} catch (e, stack) {
print('Bad PIN code !');
print(e);
if (kReleaseMode) {
await sentry.Sentry.captureException(
e,
stackTrace: stack,
);
}
return 'false';
}
}
// Future<bool> checkIfWalletExist(_name) async {
// final appPath = await _localPath;
// final _walletFile = File('$appPath/$_name/wallet.dewif');
// // deleteWallet();
// print(_walletFile.path);
// final isExist = await File(_walletFile.path).exists();
// print('Wallet existe ? : ' + isExist.toString());
// print('Is wallet generated ? : ' + walletIsGenerated.toString());
// if (isExist == true) {
// print('Un wallet existe !');
// return true;
// } else {
// return false;
// }
// }
List getAllWalletsNames() {
// final _appPath = await getApplicationDocumentsDirectory();
// List _listWallets = [];
// _listWallets.add('tortuuue');
this._listWallets.clear();
print(this.appPath);
print(this.walletsDirectory.path);
this
.appPath
.list(recursive: false, followLinks: false)
.listen((FileSystemEntity entity) {
print(entity.path.split('/').last);
this._listWallets.add(entity.path.split('/').last);
.walletsDirectory
.listSync(recursive: false, followLinks: false)
.forEach((wallet) {
String _name = wallet.path.split('/').last;
print(_name);
this._listWallets.add(_name);
});
// .listen((FileSystemEntity entity) {
// print(entity.path.split('/').last);
// this._listWallets.add(entity.path.split('/').last);
// });
print('Mes wallets: ');
print(_listWallets);
return _listWallets;
// final _local = await _appPath.path.list().toList();
}
Future openWalletOptions(_name) async {
deleteWallet(_name);
// getAllWalletsNames();
// setState(() {});
// GenerateWalletScreen(keyGenWallet: _keyGenWallet);
// _keyGenWallet.currentState.setState(() {
// getAllWalletsNames();
// });
}
Future readLocalWallet(String _pin) async {
// print(pin);
try {
final file = await _localWallet('this.walletName');
String _localDewif = await file.readAsString();
String _localPubkey;
if ((_localPubkey = await getPubkeyFromDewif(_localDewif, _pin)) !=
'false') {
setState(() {
this._pubkey.text = _localPubkey;
});
return _localDewif;
} else {
throw 'Bad pubkey';
}
} catch (e) {
print('ERROR READING FILE: $e');
setState(() {
this._pubkey.clear();
});
return 'bad';
}
}
Future<int> deleteWallet(_name) async {
try {
final appPath = await _localPath;
final _walletFile = File('$appPath/wallets/$_name/wallet.dewif');
_walletFile.delete();
getAllWalletsNames();
setState(() {
// getAllWalletsNames();
});
return 0;
} catch (e) {
getAllWalletsNames();
setState(() {
// getAllWalletsNames();
});
return 1;
}
}
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> _localWallet(_name) async {
final path = await _localPath;
return File('$path/wallets/$_name/wallet.dewif');
}
}

View File

@ -0,0 +1,232 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:dubp/dubp.dart';
import 'dart:io';
import 'dart:async';
import 'package:path_provider/path_provider.dart';
import 'package:pin_code_fields/pin_code_fields.dart';
import 'package:sentry/sentry.dart' as sentry;
class WalletOptions extends StatefulWidget {
const WalletOptions({Key keyMyWallets, @required this.walletName})
: super(key: keyMyWallets);
final String walletName;
@override
WalletOptionsState createState() => WalletOptionsState();
}
class WalletOptionsState extends State<WalletOptions> {
StreamController<ErrorAnimationType> errorController;
Directory appPath;
TextEditingController _pubkey = new TextEditingController();
TextEditingController _enterPin = new TextEditingController();
final formKey = GlobalKey<FormState>();
bool hasError = false;
String validPin = 'NO PIN';
var pinColor = Color(0xffF9F9F1);
void initState() {
super.initState();
errorController = StreamController<ErrorAnimationType>();
DubpRust.setup();
}
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(),
body: Center(
child: SafeArea(
child: Column(children: <Widget>[
InkWell(
child: TextField(
enabled: false,
controller: this._pubkey,
maxLines: 1,
textAlign: TextAlign.center,
decoration: InputDecoration(),
style: TextStyle(
fontSize: 14.0,
color: Colors.black,
fontWeight: FontWeight.bold)),
onTap: () {
// deleteWallet(widget.walletName);
// _keyHistory.currentState.scan();
},
),
SizedBox(height: 12),
Form(
key: formKey,
child: Padding(
padding:
const EdgeInsets.symmetric(vertical: 8.0, horizontal: 30),
child: PinCodeTextField(
appContext: context,
pastedTextStyle: TextStyle(
color: Colors.green.shade600,
fontWeight: FontWeight.bold,
),
length: 6,
obscureText: false,
obscuringCharacter: '*',
animationType: AnimationType.fade,
validator: (v) {
if (v.length < 6) {
return "Votre code PIN fait 6 caractères";
} else {
return null;
}
},
pinTheme: PinTheme(
shape: PinCodeFieldShape.box,
borderRadius: BorderRadius.circular(5),
fieldHeight: 60,
fieldWidth: 50,
activeFillColor: hasError ? Colors.orange : Colors.white,
),
cursorColor: Colors.black,
animationDuration: Duration(milliseconds: 300),
textStyle: TextStyle(fontSize: 20, height: 1.6),
backgroundColor: pinColor,
enableActiveFill: false,
errorAnimationController: errorController,
controller: _enterPin,
keyboardType: TextInputType.text,
boxShadows: [
BoxShadow(
offset: Offset(0, 1),
color: Colors.black12,
blurRadius: 10,
)
],
onCompleted: (v) async {
print("Completed");
final resultWallet = await readLocalWallet(v.toUpperCase());
if (resultWallet == 'bad') {
errorController.add(ErrorAnimationType
.shake); // Triggering error shake animation
setState(() {
hasError = true;
pinColor = Colors.red[200];
});
} else {
setState(() {
pinColor = Colors.green[200];
});
}
},
onChanged: (value) {
if (pinColor != Color(0xffF9F9F1)) {
setState(() {
pinColor = Color(0xffF9F9F1);
});
}
print(value);
},
)),
),
SizedBox(
height: 100,
),
SizedBox(
height: 80,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 2,
primary: Colors.red, //Color(0xffFFD68E), // background
onPrimary: Colors.black, // foreground
),
onPressed: () {
deleteWallet(widget.walletName);
},
child: Text('Supprimer ce portefeuille',
style: TextStyle(fontSize: 25))))
]))));
}
Future getPubkeyFromDewif(_dewif, _pin) async {
String _pubkey;
RegExp regExp = new RegExp(
r'^[A-Z0-9]+$',
caseSensitive: false,
multiLine: false,
);
if (regExp.hasMatch(_pin) == true && _pin.length == 6) {
print("Le format du code PIN est correct.");
} else {
print('Format de code PIN invalide');
return 'false';
}
try {
_pubkey = await DubpRust.getDewifPublicKey(dewif: _dewif, pin: _pin);
setState(() {
this._pubkey.text = _pubkey;
});
return _pubkey;
} catch (e, stack) {
print('Bad PIN code !');
print(e);
if (kReleaseMode) {
await sentry.Sentry.captureException(
e,
stackTrace: stack,
);
}
return 'false';
}
}
Future readLocalWallet(String _pin) async {
// print(pin);
try {
final file = await _localWallet(widget.walletName);
String _localDewif = await file.readAsString();
String _localPubkey;
if ((_localPubkey = await getPubkeyFromDewif(_localDewif, _pin)) !=
'false') {
setState(() {
this._pubkey.text = _localPubkey;
});
return _localDewif;
} else {
throw 'Bad pubkey';
}
} catch (e) {
print('ERROR READING FILE: $e');
setState(() {
this._pubkey.clear();
});
return 'bad';
}
}
Future<int> deleteWallet(_name) async {
try {
final appPath = await _localPath;
final _walletFile = Directory('$appPath/wallets/$_name');
print('DELETE THAT ?: $_walletFile');
_walletFile.deleteSync(recursive: true);
Navigator.pop(context);
return 0;
} catch (e) {
return 1;
}
}
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> _localWallet(_name) async {
final path = await _localPath;
return File('$path/wallets/$_name/wallet.dewif');
}
}

View File

@ -41,8 +41,8 @@ class WalletsHomeState extends State<WalletsHome> {
// getAppDirectory();
return Scaffold(
floatingActionButton: Visibility(
visible: (checkIfWalletExist(
'MonWallet')), //!checkIfWalletExist('MonWallet') &&
visible:
(checkIfWalletExist()), //!checkIfWalletExist('MonWallet') &&
child: Container(
height: 80.0,
width: 80.0,
@ -55,10 +55,7 @@ class WalletsHomeState extends State<WalletsHome> {
MaterialPageRoute(builder: (context) {
return GenerateWalletsScreen();
}),
).then((value) => setState(() {
this.newWalletName = value;
checkIfWalletExist(value);
}));
);
},
child: Container(
height: 40.0,
@ -68,7 +65,7 @@ class WalletsHomeState extends State<WalletsHome> {
body: SafeArea(
child: Column(children: <Widget>[
Visibility(
visible: (!checkIfWalletExist('MonWallet') && !walletIsGenerated),
visible: (!checkIfWalletExist() && !walletIsGenerated),
child: Column(children: <Widget>[
SizedBox(height: 120),
Center(
@ -89,7 +86,7 @@ class WalletsHomeState extends State<WalletsHome> {
}),
).then((value) => setState(() {
this.newWalletName = value;
checkIfWalletExist(value);
checkIfWalletExist();
})),
child: Text('Générer un portefeuille',
style: TextStyle(fontSize: 20))),
@ -110,8 +107,8 @@ class WalletsHomeState extends State<WalletsHome> {
style: TextStyle(fontSize: 20))),
])),
Visibility(
visible: checkIfWalletExist('MonWallet'),
child: MyWalletsScreen(keyMyWallets: _keyWalletsHome))
visible: checkIfWalletExist(),
child: MyWalletsList(keyMyWallets: _keyWalletsHome))
])));
}
@ -127,22 +124,34 @@ class WalletsHomeState extends State<WalletsHome> {
// });
// }
bool checkIfWalletExist(_name) {
print('Nom du wallet: ' + _name);
bool checkIfWalletExist() {
if (this.appPath == null) {
return false;
}
final bool isExist =
File('${this.appPath.path}/wallets/$_name/wallet.dewif').existsSync();
print(this.appPath.path);
print('Wallet existe ? : ' + isExist.toString());
print('Is wallet generated ? : ' + walletIsGenerated.toString());
if (isExist) {
print('Un wallet existe !');
return true;
} else {
var walletsFolder = new Directory("${this.appPath.path}/wallets/");
List contents = walletsFolder.listSync();
if (contents.length == 0) {
print('No wallets detected');
return false;
} else {
print('Some wallets have been detected:');
for (var _wallets in contents) {
print(_wallets);
}
return true;
}
// final bool isExist =
// File('${walletsFolder.path}/$name/wallet.dewif').existsSync();
// print(this.appPath.path);
// print('Wallet existe ? : ' + isExist.toString());
// print('Is wallet generated ? : ' + walletIsGenerated.toString());
// if (isExist) {
// print('Un wallet existe !');
// return true;
// } else {
// return false;
// }
}
Future getAppDirectory() async {

View File

@ -5,7 +5,7 @@ description: A new Flutter project.
# pub.dev using `pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 0.0.0+9
version: 0.0.0+10
environment:
sdk: ">=2.7.0 <3.0.0"