Add reusable two-factor verification for login and money operations (#32)
This commit is contained in:
1 parent
b7a58b1a87
commit
fb40f860d2
41 files changed
+2439
-43
No files matched your search
@@ -7,6 +7,7 @@ import 'package:provider/provider.dart';
|
||||
import 'package:sxchnge_wallet/sxchnge_wallet.dart';
|
||||
|
||||
import '../providers/locale.dart';
|
||||
import '../security/settings.dart';
|
||||
|
||||
import '../generated/i18n/app_localizations.dart';
|
||||
|
||||
@@ -105,19 +106,7 @@ class SettingsPage extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(l.wSecurity, style: t.textTheme.titleLarge),
|
||||
const SizedBox(height: 12),
|
||||
Text(l.wSecurityBody),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SecuritySettings(),
|
||||
const SizedBox(height: 20),
|
||||
TextButton(
|
||||
onPressed: () => context.go('/'),
|
||||
|
||||
@@ -6,8 +6,12 @@ import 'package:go_router/go_router.dart';
|
||||
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:sxchnge_auth/sxchnge_auth.dart';
|
||||
|
||||
import 'package:sxchnge_wallet/sxchnge_wallet.dart';
|
||||
|
||||
import '../security/challenge.dart';
|
||||
|
||||
import 'copy.dart';
|
||||
import 'summary.dart';
|
||||
|
||||
@@ -64,6 +68,25 @@ class TransferPageState extends State<TransferPage> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _confirm() async {
|
||||
final p = _provider;
|
||||
final challenge = await p.challenge();
|
||||
if (!mounted || p.factorError != null || p.error != null) return;
|
||||
FactorGrant? grant;
|
||||
if (challenge != null) {
|
||||
grant = await verifyFactor(
|
||||
context,
|
||||
challenge: challenge,
|
||||
service: p.wallet.factors!,
|
||||
recorder: p.recorder,
|
||||
journey: p.journey,
|
||||
summary: TransferSummary(quote: p.quote!),
|
||||
);
|
||||
if (!mounted || grant == null) return;
|
||||
}
|
||||
await p.submit(approval: grant);
|
||||
}
|
||||
|
||||
Future<bool> allowExit() async {
|
||||
if (_provider.result != null) return true;
|
||||
if (_provider.busy || _provider.uncertain) return false;
|
||||
@@ -163,6 +186,17 @@ class TransferPageState extends State<TransferPage> {
|
||||
),
|
||||
),
|
||||
),
|
||||
if (p.factorError != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
child: Semantics(
|
||||
liveRegion: true,
|
||||
child: Text(
|
||||
factorErrorText(l, p.factorError!),
|
||||
style: TextStyle(color: t.colorScheme.error),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (p.noSubmission) Text(l.wNoSubmission),
|
||||
if (p.uncertain) ...[
|
||||
Text(l.wUncertain),
|
||||
@@ -183,7 +217,7 @@ class TransferPageState extends State<TransferPage> {
|
||||
else
|
||||
FilledButton(
|
||||
key: const ValueKey('transfer-confirm'),
|
||||
onPressed: p.busy ? null : p.submit,
|
||||
onPressed: p.busy ? null : _confirm,
|
||||
child: Text(l.wConfirm),
|
||||
),
|
||||
TextButton(
|
||||
|
||||
Reference in new issue
Block a user