all lists on lists.proxmox.com
 help / color / mirror / Atom feed
* [pve-devel] [PATCH pve_flutter_frontend] add changes to support local biometric authentication
@ 2020-09-30 10:32 Tim Marx
  2020-09-30 10:32 ` [pve-devel] [PATCH proxmox_login_manager] add option for " Tim Marx
  2020-11-12 15:39 ` [pve-devel] [PATCH pve_flutter_frontend] add changes to support " Aaron Lauterer
  0 siblings, 2 replies; 3+ messages in thread
From: Tim Marx @ 2020-09-30 10:32 UTC (permalink / raw)
  To: pve-devel

Signed-off-by: Tim Marx <t.marx@proxmox.com>
---
 android/app/src/debug/AndroidManifest.xml     |  2 +
 android/app/src/main/AndroidManifest.xml      |  1 +
 .../app/pve_flutter_frontend/MainActivity.kt  |  4 +-
 pubspec.lock                                  | 52 ++++++++++++-------
 4 files changed, 38 insertions(+), 21 deletions(-)

diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml
index 617ada1..dd99f60 100644
--- a/android/app/src/debug/AndroidManifest.xml
+++ b/android/app/src/debug/AndroidManifest.xml
@@ -4,4 +4,6 @@
          to allow setting breakpoints, to provide hot reload, etc.
     -->
     <uses-permission android:name="android.permission.INTERNET"/>
+    <uses-permission android:name="android.permission.USE_FINGERPRINT"/>
+
 </manifest>
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 529671e..22e4a71 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -2,6 +2,7 @@
     package="com.proxmox.app.pve_flutter_frontend">
 
     <uses-permission android:name="android.permission.INTERNET"/>
+    <uses-permission android:name="android.permission.USE_FINGERPRINT"/>
 
     <application
         android:label="Proxmox Virtual Environment"
diff --git a/android/app/src/main/kotlin/com/proxmox/app/pve_flutter_frontend/MainActivity.kt b/android/app/src/main/kotlin/com/proxmox/app/pve_flutter_frontend/MainActivity.kt
index 8b1e324..1458fa0 100644
--- a/android/app/src/main/kotlin/com/proxmox/app/pve_flutter_frontend/MainActivity.kt
+++ b/android/app/src/main/kotlin/com/proxmox/app/pve_flutter_frontend/MainActivity.kt
@@ -3,7 +3,7 @@ package com.proxmox.app.pve_flutter_frontend
 import android.content.ActivityNotFoundException
 import android.content.Intent
 import androidx.annotation.NonNull
-import io.flutter.embedding.android.FlutterActivity
+import io.flutter.embedding.android.FlutterFragmentActivity
 import io.flutter.embedding.engine.FlutterEngine
 import io.flutter.plugin.common.MethodChannel
 import androidx.core.content.FileProvider
@@ -16,7 +16,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 
-class MainActivity: FlutterActivity() {
+class MainActivity: FlutterFragmentActivity() {
 
     private val CHANNEL = "com.proxmox.app.pve_flutter_frontend/filesharing"
 
diff --git a/pubspec.lock b/pubspec.lock
index 831fd91..94886b3 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -28,14 +28,14 @@ packages:
       name: async
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.5.0-nullsafety"
+    version: "2.5.0-nullsafety.1"
   boolean_selector:
     dependency: transitive
     description:
       name: boolean_selector
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.1.0-nullsafety"
+    version: "2.1.0-nullsafety.1"
   build:
     dependency: transitive
     description:
@@ -105,14 +105,14 @@ packages:
       name: characters
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.1.0-nullsafety.2"
+    version: "1.1.0-nullsafety.3"
   charcode:
     dependency: transitive
     description:
       name: charcode
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.2.0-nullsafety"
+    version: "1.2.0-nullsafety.1"
   checked_yaml:
     dependency: transitive
     description:
@@ -133,7 +133,7 @@ packages:
       name: clock
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.1.0-nullsafety"
+    version: "1.1.0-nullsafety.1"
   code_builder:
     dependency: transitive
     description:
@@ -147,7 +147,7 @@ packages:
       name: collection
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.15.0-nullsafety.2"
+    version: "1.15.0-nullsafety.3"
   convert:
     dependency: transitive
     description:
@@ -189,7 +189,7 @@ packages:
       name: fake_async
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.1.0-nullsafety"
+    version: "1.2.0-nullsafety.1"
   ffi:
     dependency: transitive
     description:
@@ -216,6 +216,13 @@ packages:
     description: flutter
     source: sdk
     version: "0.0.0"
+  flutter_plugin_android_lifecycle:
+    dependency: transitive
+    description:
+      name: flutter_plugin_android_lifecycle
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.0.11"
   flutter_test:
     dependency: "direct dev"
     description: flutter
@@ -303,6 +310,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "3.1.0"
+  local_auth:
+    dependency: transitive
+    description:
+      name: local_auth
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.6.3+2"
   logging:
     dependency: transitive
     description:
@@ -316,14 +330,14 @@ packages:
       name: matcher
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.12.10-nullsafety"
+    version: "0.12.10-nullsafety.1"
   meta:
     dependency: "direct main"
     description:
       name: meta
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.3.0-nullsafety.2"
+    version: "1.3.0-nullsafety.3"
   mime:
     dependency: transitive
     description:
@@ -365,7 +379,7 @@ packages:
       name: path
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.8.0-nullsafety"
+    version: "1.8.0-nullsafety.1"
   path_provider:
     dependency: "direct main"
     description:
@@ -573,21 +587,21 @@ packages:
       name: source_span
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.8.0-nullsafety"
+    version: "1.8.0-nullsafety.2"
   stack_trace:
     dependency: transitive
     description:
       name: stack_trace
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.10.0-nullsafety"
+    version: "1.10.0-nullsafety.1"
   stream_channel:
     dependency: transitive
     description:
       name: stream_channel
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.1.0-nullsafety"
+    version: "2.1.0-nullsafety.1"
   stream_transform:
     dependency: transitive
     description:
@@ -601,21 +615,21 @@ packages:
       name: string_scanner
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.1.0-nullsafety"
+    version: "1.1.0-nullsafety.1"
   term_glyph:
     dependency: transitive
     description:
       name: term_glyph
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.2.0-nullsafety"
+    version: "1.2.0-nullsafety.1"
   test_api:
     dependency: transitive
     description:
       name: test_api
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.2.19-nullsafety"
+    version: "0.2.19-nullsafety.2"
   timing:
     dependency: transitive
     description:
@@ -629,7 +643,7 @@ packages:
       name: typed_data
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.3.0-nullsafety.2"
+    version: "1.3.0-nullsafety.3"
   url_launcher:
     dependency: "direct main"
     description:
@@ -678,7 +692,7 @@ packages:
       name: vector_math
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.1.0-nullsafety.2"
+    version: "2.1.0-nullsafety.3"
   watcher:
     dependency: transitive
     description:
@@ -715,5 +729,5 @@ packages:
     source: hosted
     version: "2.2.1"
 sdks:
-  dart: ">=2.10.0-0.0.dev <2.10.0"
+  dart: ">=2.10.0-110 <=2.11.0-176.0.dev"
   flutter: ">=1.12.13+hotfix.5 <2.0.0"
-- 
2.20.1




^ permalink raw reply	[flat|nested] 3+ messages in thread

* [pve-devel] [PATCH proxmox_login_manager] add option for local biometric authentication
  2020-09-30 10:32 [pve-devel] [PATCH pve_flutter_frontend] add changes to support local biometric authentication Tim Marx
@ 2020-09-30 10:32 ` Tim Marx
  2020-11-12 15:39 ` [pve-devel] [PATCH pve_flutter_frontend] add changes to support " Aaron Lauterer
  1 sibling, 0 replies; 3+ messages in thread
From: Tim Marx @ 2020-09-30 10:32 UTC (permalink / raw)
  To: pve-devel

Signed-off-by: Tim Marx <t.marx@proxmox.com>
---
 lib/proxmox_general_settings_form.dart  |  39 +++-
 lib/proxmox_general_settings_model.dart |  12 +-
 lib/proxmox_login_form.dart             |   9 +-
 lib/proxmox_login_model.dart            |   4 +-
 lib/proxmox_login_selector.dart         | 234 +++++++++++++++---------
 pubspec.lock                            |  14 ++
 pubspec.yaml                            |   1 +
 7 files changed, 216 insertions(+), 97 deletions(-)

diff --git a/lib/proxmox_general_settings_form.dart b/lib/proxmox_general_settings_form.dart
index f3fdd44..61a7d76 100644
--- a/lib/proxmox_general_settings_form.dart
+++ b/lib/proxmox_general_settings_form.dart
@@ -1,5 +1,9 @@
+import 'dart:io';
+
 import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
 import 'package:proxmox_login_manager/proxmox_general_settings_model.dart';
+import 'package:local_auth/local_auth.dart';
 
 class ProxmoxGeneralSettingsForm extends StatefulWidget {
   @override
@@ -43,7 +47,40 @@ class _ProxmoxGeneralSettingsFormState
                               ProxmoxGeneralSettingsModel.fromLocalStorage();
                         });
                       },
-                    )
+                    ),
+                    if (Platform.isAndroid)
+                      SwitchListTile(
+                        title: Text('Biometric lock'),
+                        subtitle: Text('Lock app with fingerprint'),
+                        value: settings.useBiometrics,
+                        onChanged: (value) async {
+                          try {
+                            bool didAuthenticate = await LocalAuthentication()
+                                .authenticateWithBiometrics(
+                                    localizedReason:
+                                        'Please authenticate to enable app lock');
+                            if (didAuthenticate) {
+                              await settings
+                                  .rebuild((b) => b.useBiometrics = value)
+                                  .toLocalStorage();
+                              setState(() {
+                                _settings = ProxmoxGeneralSettingsModel
+                                    .fromLocalStorage();
+                              });
+                            }
+                          } on PlatformException catch (e) {
+                            print(e);
+                            showDialog(
+                              context: context,
+                              builder: (context) => AlertDialog(
+                                title: Text('Sensor Error'),
+                                content:
+                                    Text('Accessing biometric sensor failed'),
+                              ),
+                            );
+                          }
+                        },
+                      )
                   ],
                 ),
               );
diff --git a/lib/proxmox_general_settings_model.dart b/lib/proxmox_general_settings_model.dart
index 72fc0f7..3f3b9a3 100644
--- a/lib/proxmox_general_settings_model.dart
+++ b/lib/proxmox_general_settings_model.dart
@@ -11,6 +11,7 @@ abstract class ProxmoxGeneralSettingsModel
     implements
         Built<ProxmoxGeneralSettingsModel, ProxmoxGeneralSettingsModelBuilder> {
   bool get sslValidation;
+  bool get useBiometrics;
 
   ProxmoxGeneralSettingsModel._();
   factory ProxmoxGeneralSettingsModel(
@@ -18,8 +19,15 @@ abstract class ProxmoxGeneralSettingsModel
       _$ProxmoxGeneralSettingsModel;
 
   factory ProxmoxGeneralSettingsModel.defaultValues() =>
-      ProxmoxGeneralSettingsModel((b) => b..sslValidation = true);
-
+      ProxmoxGeneralSettingsModel(
+        (b) => b
+          ..sslValidation = true
+          ..useBiometrics = false,
+      );
+  static void _initializeBuilder(ProxmoxGeneralSettingsModelBuilder builder) =>
+      builder
+        ..sslValidation = true
+        ..useBiometrics = false;
   Object toJson() {
     return serializers.serializeWith(
         ProxmoxGeneralSettingsModel.serializer, this);
diff --git a/lib/proxmox_login_form.dart b/lib/proxmox_login_form.dart
index 3115ffd..50afb3a 100644
--- a/lib/proxmox_login_form.dart
+++ b/lib/proxmox_login_form.dart
@@ -556,8 +556,10 @@ class _ProxmoxLoginPageState extends State<ProxmoxLoginPage> {
 }
 
 class ProxmoxProgressOverlay extends StatelessWidget {
+  final Color foregroundColor;
   const ProxmoxProgressOverlay({
     Key key,
+    Color this.foregroundColor,
     @required this.message,
   }) : super(key: key);
 
@@ -574,13 +576,16 @@ class ProxmoxProgressOverlay extends StatelessWidget {
             Text(
               message,
               style: TextStyle(
-                color: Theme.of(context).accentColor,
+                color: foregroundColor ?? Theme.of(context).accentColor,
                 fontSize: 20,
               ),
             ),
             Padding(
               padding: const EdgeInsets.only(top: 20.0),
-              child: CircularProgressIndicator(),
+              child: CircularProgressIndicator(
+                valueColor: AlwaysStoppedAnimation<Color>(
+                    foregroundColor ?? Theme.of(context).accentColor),
+              ),
             )
           ],
         ),
diff --git a/lib/proxmox_login_model.dart b/lib/proxmox_login_model.dart
index af7c4fd..067e92f 100644
--- a/lib/proxmox_login_model.dart
+++ b/lib/proxmox_login_model.dart
@@ -44,8 +44,10 @@ abstract class ProxmoxLoginStorage
   }
 
   Future<proxclient.ProxmoxApiClient> recoverLatestSession() async {
-    final latestSession = logins.singleWhere((e) => e.ticket.isNotEmpty);
     final settings = await ProxmoxGeneralSettingsModel.fromLocalStorage();
+    if (settings.useBiometrics)
+      throw Exception('Biometric authentication required');
+    final latestSession = logins.singleWhere((e) => e.ticket.isNotEmpty);
     final apiClient = await proxclient.authenticate(latestSession.fullUsername,
         latestSession.ticket, latestSession.origin, settings.sslValidation);
     return apiClient;
diff --git a/lib/proxmox_login_selector.dart b/lib/proxmox_login_selector.dart
index f6ca2fa..fc8dda9 100644
--- a/lib/proxmox_login_selector.dart
+++ b/lib/proxmox_login_selector.dart
@@ -1,5 +1,8 @@
 import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:local_auth/local_auth.dart';
 import 'package:proxmox_login_manager/proxmox_general_settings_form.dart';
+import 'package:proxmox_login_manager/proxmox_general_settings_model.dart';
 import 'package:proxmox_login_manager/proxmox_login_form.dart';
 import 'package:proxmox_login_manager/proxmox_login_model.dart';
 import 'package:proxmox_dart_api_client/proxmox_dart_api_client.dart'
@@ -19,12 +22,44 @@ class ProxmoxLoginSelector extends StatefulWidget {
 
 class _ProxmoxLoginSelectorState extends State<ProxmoxLoginSelector> {
   Future<ProxmoxLoginStorage> loginStorage;
+  Future<bool> authenticated;
+  final LocalAuthentication auth = LocalAuthentication();
+  bool _isAuthenticating = false;
+
   @override
   void initState() {
     super.initState();
+    authenticated = _authenticate();
     loginStorage = ProxmoxLoginStorage.fromLocalStorage();
   }
 
+  Future<bool> _authenticate() async {
+    final settings = await ProxmoxGeneralSettingsModel.fromLocalStorage();
+
+    if (!settings.useBiometrics) return true;
+
+    var authenticated = false;
+
+    try {
+      setState(() {
+        _isAuthenticating = true;
+      });
+      while (!authenticated) {
+        authenticated = await auth.authenticateWithBiometrics(
+            localizedReason: 'Scan your fingerprint to authenticate',
+            useErrorDialogs: true,
+            stickyAuth: true);
+      }
+      setState(() {
+        _isAuthenticating = false;
+      });
+    } on PlatformException catch (e) {
+      print(e);
+    }
+    if (!mounted) return authenticated;
+    return authenticated;
+  }
+
   @override
   Widget build(BuildContext context) {
     return SafeArea(
@@ -57,103 +92,120 @@ class _ProxmoxLoginSelectorState extends State<ProxmoxLoginSelector> {
                 })
           ],
         ),
-        body: FutureBuilder<ProxmoxLoginStorage>(
-            future: loginStorage,
+        body: FutureBuilder(
+            future: authenticated,
             builder: (context, snapshot) {
-              if (!snapshot.hasData) {
-                return Center(
-                  child: CircularProgressIndicator(),
-                );
-              }
-              if (snapshot.hasData && (snapshot.data.logins?.isEmpty ?? true)) {
-                return Center(
-                  child: Text('Add an account'),
+              if (_isAuthenticating || !snapshot.hasData || !snapshot.data) {
+                return ProxmoxProgressOverlay(
+                  message: 'Waiting for authentication',
+                  foregroundColor: Colors.white,
                 );
               }
-              var items = <Widget>[];
-              final logins = snapshot.data?.logins;
+              return FutureBuilder<ProxmoxLoginStorage>(
+                  future: loginStorage,
+                  builder: (context, snapshot) {
+                    if (!snapshot.hasData) {
+                      return Center(
+                        child: CircularProgressIndicator(),
+                      );
+                    }
+                    if (snapshot.hasData &&
+                        (snapshot.data.logins?.isEmpty ?? true)) {
+                      return Center(
+                        child: Text('Add an account'),
+                      );
+                    }
+                    var items = <Widget>[];
+                    final logins = snapshot.data?.logins;
 
-              final activeSessions =
-                  logins.rebuild((b) => b.where((b) => b.activeSession));
+                    final activeSessions =
+                        logins.rebuild((b) => b.where((b) => b.activeSession));
 
-              if (activeSessions.isNotEmpty) {
-                items.addAll([
-                  Padding(
-                    padding: const EdgeInsets.all(12.0),
-                    child: Text(
-                      'Active Sessions',
-                      style: TextStyle(
-                        fontSize: 18,
-                        fontWeight: FontWeight.bold,
+                    if (activeSessions.isNotEmpty) {
+                      items.addAll([
+                        Padding(
+                          padding: const EdgeInsets.all(12.0),
+                          child: Text(
+                            'Active Sessions',
+                            style: TextStyle(
+                              fontSize: 18,
+                              fontWeight: FontWeight.bold,
+                            ),
+                          ),
+                        ),
+                        ...activeSessions.map((s) => ListTile(
+                              title: Text(s.fullHostname),
+                              subtitle: Text(s.fullUsername),
+                              trailing: Icon(Icons.navigate_next),
+                              leading: PopupMenuButton(
+                                  icon: Icon(Icons.more_vert,
+                                      color: Colors.green),
+                                  itemBuilder: (context) => [
+                                        PopupMenuItem(
+                                          child: ListTile(
+                                            dense: true,
+                                            leading: Icon(Icons.logout),
+                                            title: Text('Logout'),
+                                            onTap: () async {
+                                              await snapshot.data
+                                                  .rebuild((b) => b.logins
+                                                      .rebuildWhere(
+                                                          (m) => s == m,
+                                                          (b) =>
+                                                              b..ticket = ''))
+                                                  .saveToDisk();
+                                              refreshFromStorage();
+                                              Navigator.of(context).pop();
+                                            },
+                                          ),
+                                        ),
+                                      ]),
+                              onTap: () => _login(user: s),
+                            )),
+                      ]);
+                    }
+                    items.addAll([
+                      Padding(
+                        padding: const EdgeInsets.all(12.0),
+                        child: Text(
+                          'Available Sites',
+                          style: TextStyle(
+                            fontSize: 18,
+                            fontWeight: FontWeight.bold,
+                          ),
+                        ),
                       ),
-                    ),
-                  ),
-                  ...activeSessions.map((s) => ListTile(
-                        title: Text(s.fullHostname),
-                        subtitle: Text(s.fullUsername),
-                        trailing: Icon(Icons.navigate_next),
-                        leading: PopupMenuButton(
-                            icon: Icon(Icons.more_vert, color: Colors.green),
-                            itemBuilder: (context) => [
-                                  PopupMenuItem(
-                                    child: ListTile(
-                                      dense: true,
-                                      leading: Icon(Icons.logout),
-                                      title: Text('Logout'),
-                                      onTap: () async {
-                                        await snapshot.data
-                                            .rebuild((b) => b.logins
-                                                .rebuildWhere((m) => s == m,
-                                                    (b) => b..ticket = ''))
-                                            .saveToDisk();
-                                        refreshFromStorage();
-                                        Navigator.of(context).pop();
-                                      },
-                                    ),
-                                  ),
-                                ]),
-                        onTap: () => _login(user: s),
-                      )),
-                ]);
-              }
-              items.addAll([
-                Padding(
-                  padding: const EdgeInsets.all(12.0),
-                  child: Text(
-                    'Available Sites',
-                    style: TextStyle(
-                      fontSize: 18,
-                      fontWeight: FontWeight.bold,
-                    ),
-                  ),
-                ),
-                ...logins.where((b) => !b.activeSession)?.map((l) => ListTile(
-                      title: Text(l.fullHostname),
-                      subtitle: Text(l.fullUsername),
-                      trailing: Icon(Icons.navigate_next),
-                      leading: PopupMenuButton(
-                          itemBuilder: (context) => [
-                                PopupMenuItem(
-                                  child: ListTile(
-                                    dense: true,
-                                    leading: Icon(Icons.delete),
-                                    title: Text('Delete'),
-                                    onTap: () async {
-                                      await snapshot.data
-                                          .rebuild((b) => b.logins.remove(l))
-                                          .saveToDisk();
-                                      refreshFromStorage();
-                                      Navigator.of(context).pop();
-                                    },
-                                  ),
-                                ),
-                              ]),
-                      onTap: () => _login(user: l),
-                    ))
-              ]);
-              return ListView(
-                children: items,
-              );
+                      ...logins
+                          .where((b) => !b.activeSession)
+                          ?.map((l) => ListTile(
+                                title: Text(l.fullHostname),
+                                subtitle: Text(l.fullUsername),
+                                trailing: Icon(Icons.navigate_next),
+                                leading: PopupMenuButton(
+                                    itemBuilder: (context) => [
+                                          PopupMenuItem(
+                                            child: ListTile(
+                                              dense: true,
+                                              leading: Icon(Icons.delete),
+                                              title: Text('Delete'),
+                                              onTap: () async {
+                                                await snapshot.data
+                                                    .rebuild((b) =>
+                                                        b.logins.remove(l))
+                                                    .saveToDisk();
+                                                refreshFromStorage();
+                                                Navigator.of(context).pop();
+                                              },
+                                            ),
+                                          ),
+                                        ]),
+                                onTap: () => _login(user: l),
+                              ))
+                    ]);
+                    return ListView(
+                      children: items,
+                    );
+                  });
             }),
         floatingActionButton: FloatingActionButton.extended(
           onPressed: () => _login(isCreate: true),
diff --git a/pubspec.lock b/pubspec.lock
index b0bf674..58794ad 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -209,6 +209,13 @@ packages:
     description: flutter
     source: sdk
     version: "0.0.0"
+  flutter_plugin_android_lifecycle:
+    dependency: transitive
+    description:
+      name: flutter_plugin_android_lifecycle
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.0.11"
   flutter_test:
     dependency: "direct dev"
     description: flutter
@@ -289,6 +296,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "3.1.0"
+  local_auth:
+    dependency: "direct main"
+    description:
+      name: local_auth
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.6.3+2"
   logging:
     dependency: transitive
     description:
diff --git a/pubspec.yaml b/pubspec.yaml
index dc11ec8..2b5f5a5 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -12,6 +12,7 @@ dependencies:
   shared_preferences: '>=0.5.10 <2.0.0'
   built_value: ^7.1.0
   built_collection: ^4.3.2
+  local_auth: ^0.6.3+2
   proxmox_dart_api_client:
     path: ../proxmox_dart_api_client
 
-- 
2.20.1




^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [pve-devel] [PATCH pve_flutter_frontend] add changes to support local biometric authentication
  2020-09-30 10:32 [pve-devel] [PATCH pve_flutter_frontend] add changes to support local biometric authentication Tim Marx
  2020-09-30 10:32 ` [pve-devel] [PATCH proxmox_login_manager] add option for " Tim Marx
@ 2020-11-12 15:39 ` Aaron Lauterer
  1 sibling, 0 replies; 3+ messages in thread
From: Aaron Lauterer @ 2020-11-12 15:39 UTC (permalink / raw)
  To: pve-devel

Maybe a bit more explanation is needed for what this patch actually does.

Once enabled, a fingerprint scan is needed in the following situations:
* open the app
* navigate to the "Sites" panel


for the series:
Tested-By: Aaron Lauterer <a.lauterer@proxmox.com>

On 9/30/20 12:32 PM, Tim Marx wrote:
> Signed-off-by: Tim Marx <t.marx@proxmox.com>
> ---
>   android/app/src/debug/AndroidManifest.xml     |  2 +
>   android/app/src/main/AndroidManifest.xml      |  1 +
>   .../app/pve_flutter_frontend/MainActivity.kt  |  4 +-
>   pubspec.lock                                  | 52 ++++++++++++-------
>   4 files changed, 38 insertions(+), 21 deletions(-)
> 
> diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml
> index 617ada1..dd99f60 100644
> --- a/android/app/src/debug/AndroidManifest.xml
> +++ b/android/app/src/debug/AndroidManifest.xml
> @@ -4,4 +4,6 @@
>            to allow setting breakpoints, to provide hot reload, etc.
>       -->
>       <uses-permission android:name="android.permission.INTERNET"/>
> +    <uses-permission android:name="android.permission.USE_FINGERPRINT"/>
> +
>   </manifest>
> diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
> index 529671e..22e4a71 100644
> --- a/android/app/src/main/AndroidManifest.xml
> +++ b/android/app/src/main/AndroidManifest.xml
> @@ -2,6 +2,7 @@
>       package="com.proxmox.app.pve_flutter_frontend">
>   
>       <uses-permission android:name="android.permission.INTERNET"/>
> +    <uses-permission android:name="android.permission.USE_FINGERPRINT"/>
>   
>       <application
>           android:label="Proxmox Virtual Environment"
> diff --git a/android/app/src/main/kotlin/com/proxmox/app/pve_flutter_frontend/MainActivity.kt b/android/app/src/main/kotlin/com/proxmox/app/pve_flutter_frontend/MainActivity.kt
> index 8b1e324..1458fa0 100644
> --- a/android/app/src/main/kotlin/com/proxmox/app/pve_flutter_frontend/MainActivity.kt
> +++ b/android/app/src/main/kotlin/com/proxmox/app/pve_flutter_frontend/MainActivity.kt
> @@ -3,7 +3,7 @@ package com.proxmox.app.pve_flutter_frontend
>   import android.content.ActivityNotFoundException
>   import android.content.Intent
>   import androidx.annotation.NonNull
> -import io.flutter.embedding.android.FlutterActivity
> +import io.flutter.embedding.android.FlutterFragmentActivity
>   import io.flutter.embedding.engine.FlutterEngine
>   import io.flutter.plugin.common.MethodChannel
>   import androidx.core.content.FileProvider
> @@ -16,7 +16,7 @@ import java.io.IOException;
>   import java.io.InputStream;
>   import java.io.OutputStream;
>   
> -class MainActivity: FlutterActivity() {
> +class MainActivity: FlutterFragmentActivity() {
>   
>       private val CHANNEL = "com.proxmox.app.pve_flutter_frontend/filesharing"
>   
> diff --git a/pubspec.lock b/pubspec.lock
> index 831fd91..94886b3 100644
> --- a/pubspec.lock
> +++ b/pubspec.lock
> @@ -28,14 +28,14 @@ packages:
>         name: async
>         url: "https://pub.dartlang.org"
>       source: hosted
> -    version: "2.5.0-nullsafety"
> +    version: "2.5.0-nullsafety.1"
>     boolean_selector:
>       dependency: transitive
>       description:
>         name: boolean_selector
>         url: "https://pub.dartlang.org"
>       source: hosted
> -    version: "2.1.0-nullsafety"
> +    version: "2.1.0-nullsafety.1"
>     build:
>       dependency: transitive
>       description:
> @@ -105,14 +105,14 @@ packages:
>         name: characters
>         url: "https://pub.dartlang.org"
>       source: hosted
> -    version: "1.1.0-nullsafety.2"
> +    version: "1.1.0-nullsafety.3"
>     charcode:
>       dependency: transitive
>       description:
>         name: charcode
>         url: "https://pub.dartlang.org"
>       source: hosted
> -    version: "1.2.0-nullsafety"
> +    version: "1.2.0-nullsafety.1"
>     checked_yaml:
>       dependency: transitive
>       description:
> @@ -133,7 +133,7 @@ packages:
>         name: clock
>         url: "https://pub.dartlang.org"
>       source: hosted
> -    version: "1.1.0-nullsafety"
> +    version: "1.1.0-nullsafety.1"
>     code_builder:
>       dependency: transitive
>       description:
> @@ -147,7 +147,7 @@ packages:
>         name: collection
>         url: "https://pub.dartlang.org"
>       source: hosted
> -    version: "1.15.0-nullsafety.2"
> +    version: "1.15.0-nullsafety.3"
>     convert:
>       dependency: transitive
>       description:
> @@ -189,7 +189,7 @@ packages:
>         name: fake_async
>         url: "https://pub.dartlang.org"
>       source: hosted
> -    version: "1.1.0-nullsafety"
> +    version: "1.2.0-nullsafety.1"
>     ffi:
>       dependency: transitive
>       description:
> @@ -216,6 +216,13 @@ packages:
>       description: flutter
>       source: sdk
>       version: "0.0.0"
> +  flutter_plugin_android_lifecycle:
> +    dependency: transitive
> +    description:
> +      name: flutter_plugin_android_lifecycle
> +      url: "https://pub.dartlang.org"
> +    source: hosted
> +    version: "1.0.11"
>     flutter_test:
>       dependency: "direct dev"
>       description: flutter
> @@ -303,6 +310,13 @@ packages:
>         url: "https://pub.dartlang.org"
>       source: hosted
>       version: "3.1.0"
> +  local_auth:
> +    dependency: transitive
> +    description:
> +      name: local_auth
> +      url: "https://pub.dartlang.org"
> +    source: hosted
> +    version: "0.6.3+2"
>     logging:
>       dependency: transitive
>       description:
> @@ -316,14 +330,14 @@ packages:
>         name: matcher
>         url: "https://pub.dartlang.org"
>       source: hosted
> -    version: "0.12.10-nullsafety"
> +    version: "0.12.10-nullsafety.1"
>     meta:
>       dependency: "direct main"
>       description:
>         name: meta
>         url: "https://pub.dartlang.org"
>       source: hosted
> -    version: "1.3.0-nullsafety.2"
> +    version: "1.3.0-nullsafety.3"
>     mime:
>       dependency: transitive
>       description:
> @@ -365,7 +379,7 @@ packages:
>         name: path
>         url: "https://pub.dartlang.org"
>       source: hosted
> -    version: "1.8.0-nullsafety"
> +    version: "1.8.0-nullsafety.1"
>     path_provider:
>       dependency: "direct main"
>       description:
> @@ -573,21 +587,21 @@ packages:
>         name: source_span
>         url: "https://pub.dartlang.org"
>       source: hosted
> -    version: "1.8.0-nullsafety"
> +    version: "1.8.0-nullsafety.2"
>     stack_trace:
>       dependency: transitive
>       description:
>         name: stack_trace
>         url: "https://pub.dartlang.org"
>       source: hosted
> -    version: "1.10.0-nullsafety"
> +    version: "1.10.0-nullsafety.1"
>     stream_channel:
>       dependency: transitive
>       description:
>         name: stream_channel
>         url: "https://pub.dartlang.org"
>       source: hosted
> -    version: "2.1.0-nullsafety"
> +    version: "2.1.0-nullsafety.1"
>     stream_transform:
>       dependency: transitive
>       description:
> @@ -601,21 +615,21 @@ packages:
>         name: string_scanner
>         url: "https://pub.dartlang.org"
>       source: hosted
> -    version: "1.1.0-nullsafety"
> +    version: "1.1.0-nullsafety.1"
>     term_glyph:
>       dependency: transitive
>       description:
>         name: term_glyph
>         url: "https://pub.dartlang.org"
>       source: hosted
> -    version: "1.2.0-nullsafety"
> +    version: "1.2.0-nullsafety.1"
>     test_api:
>       dependency: transitive
>       description:
>         name: test_api
>         url: "https://pub.dartlang.org"
>       source: hosted
> -    version: "0.2.19-nullsafety"
> +    version: "0.2.19-nullsafety.2"
>     timing:
>       dependency: transitive
>       description:
> @@ -629,7 +643,7 @@ packages:
>         name: typed_data
>         url: "https://pub.dartlang.org"
>       source: hosted
> -    version: "1.3.0-nullsafety.2"
> +    version: "1.3.0-nullsafety.3"
>     url_launcher:
>       dependency: "direct main"
>       description:
> @@ -678,7 +692,7 @@ packages:
>         name: vector_math
>         url: "https://pub.dartlang.org"
>       source: hosted
> -    version: "2.1.0-nullsafety.2"
> +    version: "2.1.0-nullsafety.3"
>     watcher:
>       dependency: transitive
>       description:
> @@ -715,5 +729,5 @@ packages:
>       source: hosted
>       version: "2.2.1"
>   sdks:
> -  dart: ">=2.10.0-0.0.dev <2.10.0"
> +  dart: ">=2.10.0-110 <=2.11.0-176.0.dev"
>     flutter: ">=1.12.13+hotfix.5 <2.0.0"
> 




^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2020-11-12 15:39 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-30 10:32 [pve-devel] [PATCH pve_flutter_frontend] add changes to support local biometric authentication Tim Marx
2020-09-30 10:32 ` [pve-devel] [PATCH proxmox_login_manager] add option for " Tim Marx
2020-11-12 15:39 ` [pve-devel] [PATCH pve_flutter_frontend] add changes to support " Aaron Lauterer

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal