فهرست منبع

Add screen to let a returning user enter her existing passphrase

Vishnu Mohandas 4 سال پیش
والد
کامیت
7a34da5588
5فایلهای تغییر یافته به همراه147 افزوده شده و 30 حذف شده
  1. 1 1
      lib/core/configuration.dart
  2. 36 14
      lib/ui/gallery_app_bar_widget.dart
  3. 1 0
      lib/ui/passphrase_entry_page.dart
  4. 94 0
      lib/ui/passphrase_reentry_page.dart
  5. 15 15
      lib/user_authenticator.dart

+ 1 - 1
lib/core/configuration.dart

@@ -134,6 +134,6 @@ class Configuration {
   }
   }
 
 
   bool hasConfiguredAccount() {
   bool hasConfiguredAccount() {
-    return getEndpoint() != null && getToken() != null;
+    return getToken() != null && getKey() != null;
   }
   }
 }
 }

+ 36 - 14
lib/ui/gallery_app_bar_widget.dart

@@ -2,10 +2,14 @@ import 'dart:async';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/material.dart';
 import 'package:photos/core/configuration.dart';
 import 'package:photos/core/configuration.dart';
+import 'package:photos/core/event_bus.dart';
+import 'package:photos/events/user_authenticated_event.dart';
 import 'package:photos/file_repository.dart';
 import 'package:photos/file_repository.dart';
 import 'package:photos/models/selected_files.dart';
 import 'package:photos/models/selected_files.dart';
 import 'package:photos/ui/email_entry_page.dart';
 import 'package:photos/ui/email_entry_page.dart';
 import 'package:photos/ui/ott_verification_page.dart';
 import 'package:photos/ui/ott_verification_page.dart';
+import 'package:photos/ui/passphrase_entry_page.dart';
+import 'package:photos/ui/passphrase_reentry_page.dart';
 import 'package:photos/ui/share_folder_widget.dart';
 import 'package:photos/ui/share_folder_widget.dart';
 import 'package:photos/utils/dialog_util.dart';
 import 'package:photos/utils/dialog_util.dart';
 import 'package:photos/utils/file_util.dart';
 import 'package:photos/utils/file_util.dart';
@@ -40,14 +44,25 @@ class GalleryAppBarWidget extends StatefulWidget
 }
 }
 
 
 class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
 class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
+  StreamSubscription _userAuthEventSubscription;
   @override
   @override
   void initState() {
   void initState() {
     widget.selectedFiles.addListener(() {
     widget.selectedFiles.addListener(() {
       setState(() {});
       setState(() {});
     });
     });
+    _userAuthEventSubscription =
+        Bus.instance.on<UserAuthenticatedEvent>().listen((event) {
+      setState(() {});
+    });
     super.initState();
     super.initState();
   }
   }
 
 
+  @override
+  void dispose() {
+    _userAuthEventSubscription.cancel();
+    super.dispose();
+  }
+
   @override
   @override
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
     if (widget.selectedFiles.files.isEmpty) {
     if (widget.selectedFiles.files.isEmpty) {
@@ -73,11 +88,28 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
     List<Widget> actions = List<Widget>();
     List<Widget> actions = List<Widget>();
     if (!Configuration.instance.hasConfiguredAccount()) {
     if (!Configuration.instance.hasConfiguredAccount()) {
       actions.add(IconButton(
       actions.add(IconButton(
-        icon: Icon(Configuration.instance.hasConfiguredAccount()
-            ? Icons.sync_problem
-            : Icons.sync_disabled),
+        icon: Icon(Icons.sync_disabled),
         onPressed: () {
         onPressed: () {
-          _navigateToSignInPage(context);
+          var page;
+          if (Configuration.instance.getToken() == null) {
+            page = EmailEntryPage();
+          } else {
+            // No key
+            if (Configuration.instance.getEncryptedKey() != null) {
+              // Yet to decrypt the key
+              page = PassphraseReentryPage();
+            } else {
+              // Never had a key
+              page = PassphraseEntryPage();
+            }
+          }
+          Navigator.of(context).push(
+            MaterialPageRoute(
+              builder: (BuildContext context) {
+                return page;
+              },
+            ),
+          );
         },
         },
       ));
       ));
     } else if (widget.type == GalleryAppBarType.local_folder &&
     } else if (widget.type == GalleryAppBarType.local_folder &&
@@ -169,14 +201,4 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
   void _clearSelectedFiles() {
   void _clearSelectedFiles() {
     widget.selectedFiles.clearAll();
     widget.selectedFiles.clearAll();
   }
   }
-
-  void _navigateToSignInPage(BuildContext context) {
-    Navigator.of(context).push(
-      MaterialPageRoute(
-        builder: (BuildContext context) {
-          return EmailEntryPage();
-        },
-      ),
-    );
-  }
 }
 }

+ 1 - 0
lib/ui/passphrase_entry_page.dart

@@ -19,6 +19,7 @@ class _PassphraseEntryPageState extends State<PassphraseEntryPage> {
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
     return Scaffold(
     return Scaffold(
       appBar: AppBar(
       appBar: AppBar(
+        leading: Icon(Icons.lock),
         title: Text("Encryption Passphrase"),
         title: Text("Encryption Passphrase"),
       ),
       ),
       body: _getBody(),
       body: _getBody(),

+ 94 - 0
lib/ui/passphrase_reentry_page.dart

@@ -0,0 +1,94 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:photos/core/configuration.dart';
+import 'package:photos/core/event_bus.dart';
+import 'package:photos/events/user_authenticated_event.dart';
+import 'package:photos/utils/dialog_util.dart';
+
+class PassphraseReentryPage extends StatefulWidget {
+  PassphraseReentryPage({Key key}) : super(key: key);
+
+  @override
+  _PassphraseReentryPageState createState() => _PassphraseReentryPageState();
+}
+
+class _PassphraseReentryPageState extends State<PassphraseReentryPage> {
+  final _passphraseController = TextEditingController();
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: AppBar(
+        leading: Icon(Icons.lock),
+        title: Text(
+          "Encryption Passphrase",
+        ),
+      ),
+      body: _getBody(),
+    );
+  }
+
+  Widget _getBody() {
+    return SingleChildScrollView(
+      child: Container(
+        padding: EdgeInsets.fromLTRB(16, 40, 16, 16),
+        child: Column(
+          children: [
+            SvgPicture.asset(
+              "assets/vault.svg",
+              width: 196,
+              height: 196,
+            ),
+            Padding(padding: EdgeInsets.all(20)),
+            Text(
+              "Please enter your passphrase.",
+              textAlign: TextAlign.center,
+              style: TextStyle(
+                fontSize: 16,
+              ),
+            ),
+            Padding(padding: EdgeInsets.all(12)),
+            TextFormField(
+              decoration: InputDecoration(
+                hintText: "that thing you promised to never forget",
+                contentPadding: EdgeInsets.all(20),
+              ),
+              controller: _passphraseController,
+              autofocus: false,
+              autocorrect: false,
+              keyboardType: TextInputType.visiblePassword,
+              onChanged: (_) {
+                setState(() {});
+              },
+            ),
+            Padding(padding: EdgeInsets.all(12)),
+            SizedBox(
+                width: double.infinity,
+                child: RaisedButton(
+                  onPressed: _passphraseController.text.isNotEmpty
+                      ? () async {
+                          final dialog =
+                              createProgressDialog(context, "Please wait...");
+                          await dialog.show();
+                          await Configuration.instance
+                              .decryptEncryptedKey(_passphraseController.text);
+                          await dialog.hide();
+                          Bus.instance.fire(UserAuthenticatedEvent());
+                          Navigator.of(context)
+                              .popUntil((route) => route.isFirst);
+                        }
+                      : null,
+                  padding: const EdgeInsets.fromLTRB(8, 12, 8, 12),
+                  child: Text("Set Passphrase"),
+                  color: Theme.of(context).buttonColor,
+                  shape: RoundedRectangleBorder(
+                    borderRadius: BorderRadius.circular(18.0),
+                  ),
+                )),
+          ],
+        ),
+      ),
+    );
+  }
+}

+ 15 - 15
lib/user_authenticator.dart

@@ -8,7 +8,9 @@ import 'package:photos/core/event_bus.dart';
 import 'package:photos/events/user_authenticated_event.dart';
 import 'package:photos/events/user_authenticated_event.dart';
 import 'package:photos/ui/ott_verification_page.dart';
 import 'package:photos/ui/ott_verification_page.dart';
 import 'package:photos/ui/passphrase_entry_page.dart';
 import 'package:photos/ui/passphrase_entry_page.dart';
+import 'package:photos/ui/passphrase_reentry_page.dart';
 import 'package:photos/utils/dialog_util.dart';
 import 'package:photos/utils/dialog_util.dart';
+import 'package:photos/utils/toast_util.dart';
 
 
 class UserAuthenticator {
 class UserAuthenticator {
   final _dio = Dio();
   final _dio = Dio();
@@ -29,11 +31,9 @@ class UserAuthenticator {
       },
       },
     ).catchError((e) async {
     ).catchError((e) async {
       _logger.severe(e);
       _logger.severe(e);
-      await dialog.hide();
-      showGenericErrorDialog(context);
     }).then((response) async {
     }).then((response) async {
       await dialog.hide();
       await dialog.hide();
-      if (response.statusCode == 200) {
+      if (response != null && response.statusCode == 200) {
         Navigator.of(context).push(
         Navigator.of(context).push(
           MaterialPageRoute(
           MaterialPageRoute(
             builder: (BuildContext context) {
             builder: (BuildContext context) {
@@ -58,25 +58,25 @@ class UserAuthenticator {
       },
       },
     ).catchError((e) async {
     ).catchError((e) async {
       _logger.severe(e);
       _logger.severe(e);
-      await dialog.hide();
-      showGenericErrorDialog(context);
     }).then((response) async {
     }).then((response) async {
       await dialog.hide();
       await dialog.hide();
       if (response != null && response.statusCode == 200) {
       if (response != null && response.statusCode == 200) {
         _saveConfiguration(response);
         _saveConfiguration(response);
+        showToast("Email verification successful!");
+        var page;
         if (Configuration.instance.getEncryptedKey() != null) {
         if (Configuration.instance.getEncryptedKey() != null) {
-          // TODO: Passphrase re-enter to decrypt
-          Bus.instance.fire(UserAuthenticatedEvent());
-          Navigator.of(context).popUntil((route) => route.isFirst);
+          page = PassphraseReentryPage();
         } else {
         } else {
-          Navigator.of(context).push(
-            MaterialPageRoute(
-              builder: (BuildContext context) {
-                return PassphraseEntryPage();
-              },
-            ),
-          );
+          page = PassphraseEntryPage();
         }
         }
+        Navigator.of(context).pushAndRemoveUntil(
+          MaterialPageRoute(
+            builder: (BuildContext context) {
+              return page;
+            },
+          ),
+          (route) => route.isFirst,
+        );
       } else {
       } else {
         showErrorDialog(
         showErrorDialog(
             context, "Oops.", "Verification failed, please try again.");
             context, "Oops.", "Verification failed, please try again.");