Skip to content

Commit

Permalink
bruig: Seed verification
Browse files Browse the repository at this point in the history
  • Loading branch information
alexlyp committed Mar 17, 2023
1 parent acca7d5 commit 8952def
Show file tree
Hide file tree
Showing 5 changed files with 2,297 additions and 1 deletion.
60 changes: 60 additions & 0 deletions bruig/flutterui/bruig/lib/models/newconfig.dart
@@ -1,6 +1,8 @@
import 'dart:io';
import 'dart:math';

import 'package:bruig/config.dart';
import 'package:bruig/wordlist.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:golib_plugin/definitions.dart';
Expand All @@ -22,6 +24,14 @@ String NetworkTypeStr(NetworkType net) {
}
}

class ConfirmSeedWords {
final int position;
final String correctSeedWord;
final List<String> seedWordChoices;

ConfirmSeedWords(this.position, this.correctSeedWord, this.seedWordChoices);
}

class NewConfigModel extends ChangeNotifier {
final List<String> appArgs;
NewConfigModel(this.appArgs);
Expand All @@ -42,6 +52,7 @@ class NewConfigModel extends ChangeNotifier {
bool advancedSetup = false;
List<String> seedToRestore = [];
Uint8List? multichanBackupRestore;
List<ConfirmSeedWords> confirmSeedWords = [];

Future<LNInfo> tryExternalDcrlnd(
String host, String tlsPath, String macaroonPath) async {
Expand Down Expand Up @@ -69,6 +80,54 @@ class NewConfigModel extends ChangeNotifier {
return cfg;
}

List<ConfirmSeedWords> createConfirmSeedWords(String seed) {
List<ConfirmSeedWords> confirmSeedWords = [];
var seedWords = seed.split(' ');
var numWords = 5;
var numChoices = 3;
for (int i = 0; i < numWords; i++) {
int position;
bool positionUsed;
// Keep generating new positions until we have one that isn't used yet.
do {
positionUsed = false;
position = Random().nextInt(seedWords.length);
for (int k = 0; k < confirmSeedWords.length; k++) {
if (position == confirmSeedWords[k].position) {
positionUsed = true;
}
}
} while (positionUsed);
List<String> seedWordChoices = [seedWords[position]];
// Keep generating new words in the seedWordChoice list until its length
// is equal to the number of choices set above.
do {
var randomSeedWord = Random().nextInt(defaultWordList.length);
var found = false;
for (int j = 0; j < seedWordChoices.length; j++) {
if (defaultWordList[randomSeedWord] == seedWordChoices[j]) {
// Skip word if it's already in the list.
found = true;
}
}
if (!found) {
seedWordChoices.add(defaultWordList[randomSeedWord]);
}
} while (seedWordChoices.length < numChoices);
// Sort the word choices alphabetically each
seedWordChoices.sort((a, b) {
return a.toLowerCase().compareTo(b.toLowerCase());
});
confirmSeedWords.add(
ConfirmSeedWords(position, seedWords[position], seedWordChoices));
}
// Sort the questions by position
confirmSeedWords.sort((a, b) {
return a.position.compareTo(b.position);
});
return confirmSeedWords;
}

Future<void> createNewWallet(
String password, List<String> existingSeed) async {
var rootPath = await lnWalletDir();
Expand All @@ -80,6 +139,7 @@ class NewConfigModel extends ChangeNotifier {
NetworkTypeStr(netType), "admin.macaroon");
rpcHost = res.rpcHost;
newWalletSeed = res.seed;
confirmSeedWords = createConfirmSeedWords(newWalletSeed);
}

Future<bool> hasLNWalletDB() async {
Expand Down
2 changes: 2 additions & 0 deletions bruig/flutterui/bruig/lib/screens/new_config.dart
Expand Up @@ -7,6 +7,7 @@ import 'package:bruig/screens/newconfig/ln_choice.dart';
import 'package:bruig/screens/newconfig/ln_choice_external.dart';
import 'package:bruig/screens/newconfig/ln_choice_internal.dart';
import 'package:bruig/screens/newconfig/ln_wallet_seed.dart';
import 'package:bruig/screens/newconfig/ln_wallet_seed_confirm.dart';
import 'package:bruig/screens/newconfig/network_choice.dart';
import 'package:bruig/screens/newconfig/restore_wallet.dart';
import 'package:bruig/screens/newconfig/server.dart';
Expand Down Expand Up @@ -48,6 +49,7 @@ class _NewConfigScreenState extends State<NewConfigScreen> {
routes: {
"/newconf/initializing": (context) =>
InitializingNewConfPage(newconf),
"/newconf/confirmseed": (context) => ConfirmLNWalletSeedPage(newconf),
"/newconf/deleteOldWallet": (context) => DeleteOldWalletPage(newconf),
"/newconf/networkChoice": (context) => NetworkChoicePage(newconf),
"/newconf/lnChoice": (context) => LNChoicePage(newconf),
Expand Down
Expand Up @@ -18,7 +18,7 @@ class NewLNWalletSeedPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
void done() {
Navigator.of(context).pushNamed("/newconf/server");
Navigator.of(context).pushNamed("/newconf/confirmseed");
}

var backgroundColor = const Color(0xFF19172C);
Expand Down
@@ -0,0 +1,181 @@
import 'dart:async';

import 'package:bruig/models/newconfig.dart';
import 'package:flutter/material.dart';
import 'package:bruig/components/buttons.dart';

class ConfirmLNWalletSeedPage extends StatefulWidget {
final NewConfigModel newconf;
const ConfirmLNWalletSeedPage(this.newconf, {Key? key}) : super(key: key);

@override
State<ConfirmLNWalletSeedPage> createState() =>
_ConfirmLNWalletSeedPageState();
}

class _ConfirmLNWalletSeedPageState extends State<ConfirmLNWalletSeedPage> {
bool _visible = true;
bool answerWrong = false;
int currentQuestion = 0;

void checkAnswer(bool answer) {
setState(() {
// Only update seed if it hasn't been already st
_visible = false;
Timer(const Duration(milliseconds: 500), () {
setState(() {
if (answer) {
currentQuestion++;
} else {
answerWrong = true;
}
_visible = true;
});
});
});
}

@override
Widget build(BuildContext context) {
void done() {
Navigator.of(context).pushNamed("/newconf/server");
}

void goBack() {
// Go back to copy seed page
Navigator.of(context).pop();
// Generate new seed questions
widget.newconf.confirmSeedWords =
widget.newconf.createConfirmSeedWords(widget.newconf.newWalletSeed);
}

var backgroundColor = const Color(0xFF19172C);
var cardColor = const Color(0xFF05031A);
var textColor = const Color(0xFF8E8D98);
var secondaryTextColor = const Color(0xFFE4E3E6);
//var darkTextColor = const Color(0xFF5A5968);
var confirmSeedWords = widget.newconf.confirmSeedWords;
return Container(
color: backgroundColor,
child: Stack(children: [
Container(
decoration: const BoxDecoration(
image: DecorationImage(
fit: BoxFit.fill,
image: AssetImage("assets/images/loading-bg.png")))),
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.bottomLeft,
end: Alignment.topRight,
colors: [
cardColor,
const Color(0xFF07051C),
backgroundColor.withOpacity(0.34),
],
stops: const [
0,
0.17,
1
])),
padding: const EdgeInsets.all(10),
child: Column(children: [
const SizedBox(height: 89),
Text("Setting up Bison Relay",
style: TextStyle(
color: textColor,
fontSize: 34,
fontWeight: FontWeight.w200)),
const SizedBox(height: 20),
Text("Confirm New Wallet Seed",
style: TextStyle(
color: secondaryTextColor,
fontSize: 21,
fontWeight: FontWeight.w300)),
const SizedBox(height: 34),
AnimatedOpacity(
opacity: _visible ? 1.0 : 0.0,
duration: const Duration(milliseconds: 500),
child: currentQuestion < confirmSeedWords.length
? !answerWrong
? QuestionArea(
confirmSeedWords[currentQuestion], checkAnswer)
: IncorrectArea(goBack)
: Column(children: [
Text("Seed Confirmed",
style: TextStyle(
color: textColor,
fontSize: 20,
fontWeight: FontWeight.w200)),
const SizedBox(height: 20),
Center(
child: LoadingScreenButton(
onPressed: done,
text: "Continue",
))
]),
),
const SizedBox(height: 10),
const SizedBox(height: 34),
]),
)
]));
}
}

class QuestionArea extends StatelessWidget {
final ConfirmSeedWords currentWords;
final Function(bool) checkAnswersCB;
const QuestionArea(this.currentWords, this.checkAnswersCB, {Key? key})
: super(key: key);

@override
Widget build(BuildContext context) {
var textColor = const Color(0xFF8E8D98);
return Column(children: [
Center(
child: Text("Word #${currentWords.position + 1}",
style: TextStyle(
color: textColor,
fontSize: 34,
fontWeight: FontWeight.w200))),
const SizedBox(height: 20),
SizedBox(
width: 600,
child:
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
for (var i in currentWords.seedWordChoices)
Container(
margin: const EdgeInsets.all(5),
child: LoadingScreenButton(
onPressed: () =>
checkAnswersCB(currentWords.correctSeedWord == i),
text: i,
)),
]))
]);
}
}

class IncorrectArea extends StatelessWidget {
final Function() goBackCB;
const IncorrectArea(this.goBackCB, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
var textColor = const Color(0xFF8E8D98);
return Column(children: [
Center(
child: Text("Incorrect, please go back and copy the seed again.",
style: TextStyle(
color: textColor,
fontSize: 20,
fontWeight: FontWeight.w200))),
const SizedBox(height: 20),
Center(
child: LoadingScreenButton(
onPressed: goBackCB,
text: "Go back",
)),
]);
}
}

0 comments on commit 8952def

Please sign in to comment.