Browse Source

Add support to show mnemonic recovery key

Neeraj Gupta 3 năm trước cách đây
mục cha
commit
fbc5e7329e

+ 11 - 0
lib/core/configuration.dart

@@ -2,6 +2,7 @@ import 'dart:convert';
 import 'dart:io' as io;
 import 'dart:typed_data';
 
+import 'package:bip39/bip39.dart' as bip39;
 import 'package:flutter_secure_storage/flutter_secure_storage.dart';
 import 'package:flutter_sodium/flutter_sodium.dart';
 import 'package:logging/logging.dart';
@@ -28,6 +29,8 @@ import 'package:shared_preferences/shared_preferences.dart';
 import 'package:super_logging/super_logging.dart';
 import 'package:uuid/uuid.dart';
 
+import 'constants.dart';
+
 class Configuration {
   Configuration._privateConstructor();
 
@@ -265,6 +268,14 @@ class Configuration {
   }
 
   Future<void> recover(String recoveryKey) async {
+    // check if user has entered mnemonic code
+    if (recoveryKey.contains(' ')) {
+      if (recoveryKey.split(' ').length != kMnemonicKeyWordCount) {
+        throw AssertionError(
+            'recovery code should have $kMnemonicKeyWordCount words');
+      }
+      recoveryKey = bip39.mnemonicToEntropy(recoveryKey);
+    }
     final attributes = getKeyAttributes();
     Uint8List masterKey;
     try {

+ 4 - 0
lib/core/constants.dart

@@ -20,3 +20,7 @@ const String kLivePhotoToastCounterKey = "show_live_photo_toast";
 
 const kThumbnailDiskLoadDeferDuration = Duration(milliseconds: 40);
 const kThumbnailServerLoadDeferDuration = Duration(milliseconds: 80);
+
+// 256 bit key maps to 24 words
+// https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki#Generating_the_mnemonic
+const kMnemonicKeyWordCount = 24;

+ 24 - 1
lib/ui/recovery_key_dialog.dart

@@ -1,10 +1,12 @@
 import 'dart:io' as io;
 import 'dart:ui';
 
+import 'package:bip39/bip39.dart' as bip39;
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter/widgets.dart';
 import 'package:photos/core/configuration.dart';
+import 'package:photos/core/constants.dart';
 import 'package:photos/utils/toast_util.dart';
 import 'package:share_plus/share_plus.dart';
 
@@ -34,12 +36,21 @@ class RecoveryKeyDialog extends StatefulWidget {
 
 class _RecoveryKeyDialogState extends State<RecoveryKeyDialog> {
   bool _hasTriedToSave = false;
+  bool _showMnenomicCode = true;
   final _recoveryKeyFile = io.File(
       Configuration.instance.getTempDirectory() + "ente-recovery-key.txt");
 
   @override
   Widget build(BuildContext context) {
-    final recoveryKey = widget.recoveryKey;
+    String recoveryKey = widget.recoveryKey;
+    if (_showMnenomicCode) {
+      recoveryKey = bip39.entropyToMnemonic(recoveryKey);
+      if (recoveryKey.split(' ').length != kMnemonicKeyWordCount) {
+        throw AssertionError(
+            'recovery code should have $kMnemonicKeyWordCount words');
+      }
+    }
+
     List<Widget> actions = [];
     if (!_hasTriedToSave) {
       actions.add(TextButton(
@@ -128,6 +139,17 @@ class _RecoveryKeyDialogState extends State<RecoveryKeyDialog> {
               Text(
                 "please save this in a safe place",
               ),
+              Padding(padding: EdgeInsets.all(8)),
+              CheckboxListTile(
+                  contentPadding: EdgeInsets.zero,
+                  controlAffinity: ListTileControlAffinity.trailing,
+                  title: Text('show human readable key'),
+                  value: _showMnenomicCode,
+                  onChanged: (value) {
+                    setState(() {
+                      _showMnenomicCode = value;
+                    });
+                  }),
             ],
           ),
         ),
@@ -136,6 +158,7 @@ class _RecoveryKeyDialogState extends State<RecoveryKeyDialog> {
     );
   }
 
+  // author civil bicycle drop gown ship file shallow chicken hub isolate among report piece cram crumble leopard guard spike segment update fall defy achieve
   Future _shareRecoveryKey(String recoveryKey) async {
     if (_recoveryKeyFile.existsSync()) {
       await _recoveryKeyFile.delete();

+ 7 - 2
lib/ui/recovery_page.dart

@@ -86,8 +86,13 @@ class _RecoveryPageState extends State<RecoveryPage> {
                         );
                       } catch (e) {
                         await dialog.hide();
-                        showErrorDialog(context, "incorrect recovery key",
-                            "the recovery key you entered is incorrect");
+                        String errMessage =
+                            'the recovery key you entered is incorrect';
+                        if (e is AssertionError) {
+                          errMessage = '$errMessage : ${e.message}';
+                        }
+                        showErrorDialog(
+                            context, "incorrect recovery key", errMessage);
                       }
                     }
                   : null,

+ 21 - 0
pubspec.lock

@@ -50,6 +50,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "0.0.73"
+  bip39:
+    dependency: "direct main"
+    description:
+      name: bip39
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.0.6"
   boolean_selector:
     dependency: transitive
     description:
@@ -492,6 +499,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "5.0.5"
+  hex:
+    dependency: transitive
+    description:
+      name: hex
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.2.0"
   html:
     dependency: transitive
     description:
@@ -827,6 +841,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "2.0.0"
+  pointycastle:
+    dependency: transitive
+    description:
+      name: pointycastle
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "3.4.0"
   process:
     dependency: transitive
     description:

+ 1 - 0
pubspec.yaml

@@ -21,6 +21,7 @@ dependencies:
   animate_do: ^2.0.0
   archive: ^3.1.2
   background_fetch: ^1.0.1
+  bip39: ^1.0.6
   cached_network_image: ^3.0.0
   chewie:
     path: thirdparty/chewie