flet-local-auth 1.0.0.dev2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
@@ -0,0 +1,18 @@
1
+ Metadata-Version: 2.4
2
+ Name: flet-local-auth
3
+ Version: 1.0.0.dev2
4
+ Summary: Local authentication service for Flet
5
+ Author-email: "Appveyor Systems Inc." <hello@flet.dev>
6
+ Project-URL: Homepage, https://flet.dev
7
+ Project-URL: Documentation, https://flet.dev/docs/services/localauthentication
8
+ Project-URL: Repository, https://github.com/flet-dev/flet/tree/main/sdk/python/packages/flet-local-auth
9
+ Project-URL: Issues, https://github.com/flet-dev/flet/issues
10
+ Requires-Python: >=3.10
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: flet==1.0.0.dev2
14
+ Dynamic: license-file
15
+
16
+ # Flet Local Authentication
17
+
18
+ `LocalAuthentication` service for Flet apps. Authenticate users with biometrics, PIN, passcode, or pattern via the [`local_auth`](https://pub.dev/packages/local_auth) Flutter plugin.
@@ -0,0 +1,3 @@
1
+ # Flet Local Authentication
2
+
3
+ `LocalAuthentication` service for Flet apps. Authenticate users with biometrics, PIN, passcode, or pattern via the [`local_auth`](https://pub.dev/packages/local_auth) Flutter plugin.
@@ -0,0 +1,26 @@
1
+ [project]
2
+ name = "flet-local-auth"
3
+ version = "1.0.0.dev2"
4
+ description = "Local authentication service for Flet"
5
+ authors = [{name = "Appveyor Systems Inc.", email = "hello@flet.dev"}]
6
+ readme = "README.md"
7
+ requires-python = ">=3.10"
8
+ dependencies = [
9
+ "flet==1.0.0.dev2",
10
+ ]
11
+
12
+ [project.urls]
13
+ Homepage = "https://flet.dev"
14
+ Documentation = "https://flet.dev/docs/services/localauthentication"
15
+ Repository = "https://github.com/flet-dev/flet/tree/main/sdk/python/packages/flet-local-auth"
16
+ Issues = "https://github.com/flet-dev/flet/issues"
17
+
18
+ [tool.setuptools.package-data]
19
+ "flutter.flet_local_auth" = [
20
+ "pubspec.yaml",
21
+ "lib/**",
22
+ ]
23
+
24
+ [build-system]
25
+ requires = ["setuptools"]
26
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,19 @@
1
+ from flet_local_auth.local_auth import LocalAuthentication
2
+ from flet_local_auth.types import (
3
+ AndroidAuthMessages,
4
+ BiometricType,
5
+ IOSAuthMessages,
6
+ LocalAuthErrorCode,
7
+ LocalAuthException,
8
+ WindowsAuthMessages,
9
+ )
10
+
11
+ __all__ = [
12
+ "AndroidAuthMessages",
13
+ "BiometricType",
14
+ "IOSAuthMessages",
15
+ "LocalAuthErrorCode",
16
+ "LocalAuthentication",
17
+ "LocalAuthException",
18
+ "WindowsAuthMessages",
19
+ ]
@@ -0,0 +1,134 @@
1
+ from typing import Optional
2
+
3
+ import flet as ft
4
+ from flet.controls.base_control import control
5
+ from flet.controls.services.service import Service
6
+ from flet_local_auth.types import (
7
+ AndroidAuthMessages,
8
+ BiometricType,
9
+ IOSAuthMessages,
10
+ LocalAuthErrorCode,
11
+ LocalAuthException,
12
+ WindowsAuthMessages,
13
+ )
14
+
15
+ __all__ = [
16
+ "AndroidAuthMessages",
17
+ "BiometricType",
18
+ "IOSAuthMessages",
19
+ "LocalAuthErrorCode",
20
+ "LocalAuthentication",
21
+ "LocalAuthException",
22
+ "WindowsAuthMessages",
23
+ ]
24
+
25
+
26
+ @control("LocalAuthentication")
27
+ class LocalAuthentication(Service):
28
+ """
29
+ Authenticates the user with on-device biometrics or device credentials.
30
+
31
+ Danger: Platform support
32
+ Supported on Android, iOS, macOS, and Windows. Not supported on Linux or Web.
33
+
34
+ Raises:
35
+ FletUnsupportedPlatformException: If the platform is not supported.
36
+ LocalAuthException: If authentication fails.
37
+ """
38
+
39
+ def before_update(self):
40
+ super().before_update()
41
+
42
+ if self.page.web or self.page.platform == ft.PagePlatform.LINUX:
43
+ raise ft.FletUnsupportedPlatformException(
44
+ "LocalAuthentication is not supported on Linux or Web platforms."
45
+ )
46
+
47
+ async def is_device_supported(self) -> bool:
48
+ """
49
+ Returns whether the device can authenticate with biometrics or credentials.
50
+ """
51
+ return await self._invoke_method("is_device_supported")
52
+
53
+ async def can_check_biometrics(self) -> bool:
54
+ """
55
+ Returns whether the device has biometric hardware available.
56
+ """
57
+ return await self._invoke_method("can_check_biometrics")
58
+
59
+ async def get_available_biometrics(self) -> list[BiometricType]:
60
+ """
61
+ Returns the biometrics currently enrolled on the device.
62
+ """
63
+ result = await self._invoke_method("get_available_biometrics")
64
+ return [BiometricType(value) for value in result or []]
65
+
66
+ async def authenticate(
67
+ self,
68
+ reason: str,
69
+ *,
70
+ biometric_only: bool = False,
71
+ sensitive_transaction: bool = True,
72
+ persist_across_backgrounding: bool = False,
73
+ android_messages: Optional[AndroidAuthMessages] = None,
74
+ ios_messages: Optional[IOSAuthMessages] = None,
75
+ windows_messages: Optional[WindowsAuthMessages] = None,
76
+ ) -> bool:
77
+ """
78
+ Prompts the user to authenticate locally.
79
+
80
+ Args:
81
+ reason: The message shown in the system authentication dialog.
82
+ biometric_only: Whether to allow only biometric authentication.
83
+ sensitive_transaction: Whether to treat the transaction as sensitive.
84
+ persist_across_backgrounding: Whether to retry after the app is
85
+ foregrounded again if authentication was interrupted.
86
+ android_messages: Optional Android dialog customization.
87
+ ios_messages: Optional iOS dialog customization.
88
+ windows_messages: Optional Windows dialog customization.
89
+
90
+ Returns:
91
+ `True` when authentication succeeds.
92
+
93
+ Raises:
94
+ LocalAuthException: If authentication fails or is canceled.
95
+ """
96
+ result = await self._invoke_method(
97
+ method_name="authenticate",
98
+ arguments={
99
+ "reason": reason,
100
+ "biometric_only": biometric_only,
101
+ "sensitive_transaction": sensitive_transaction,
102
+ "persist_across_backgrounding": persist_across_backgrounding,
103
+ "android_messages": android_messages,
104
+ "ios_messages": ios_messages,
105
+ "windows_messages": windows_messages,
106
+ },
107
+ )
108
+ self._raise_for_error(result)
109
+ return bool(result)
110
+
111
+ async def stop_authentication(self) -> bool:
112
+ """
113
+ Cancels any in-progress authentication prompt.
114
+
115
+ Returns:
116
+ `True` if authentication was canceled successfully.
117
+ """
118
+ return await self._invoke_method("stop_authentication")
119
+
120
+ @staticmethod
121
+ def _raise_for_error(result: object) -> None:
122
+ if not isinstance(result, dict) or "error_code" not in result:
123
+ return
124
+
125
+ code_value = result.get("error_code")
126
+ try:
127
+ code = LocalAuthErrorCode(code_value)
128
+ except ValueError:
129
+ code = LocalAuthErrorCode.UNKNOWN_ERROR
130
+
131
+ raise LocalAuthException(
132
+ code=code,
133
+ description=result.get("error_description"),
134
+ )
@@ -0,0 +1,85 @@
1
+ from enum import Enum
2
+ from typing import Optional
3
+
4
+ import flet as ft
5
+
6
+
7
+ class BiometricType(Enum):
8
+ """
9
+ Biometric types reported by the device.
10
+ """
11
+
12
+ FACE = "face"
13
+ FINGERPRINT = "fingerprint"
14
+ IRIS = "iris"
15
+ WEAK = "weak"
16
+ STRONG = "strong"
17
+
18
+
19
+ class LocalAuthErrorCode(Enum):
20
+ """
21
+ Error codes reported by local authentication failures.
22
+ """
23
+
24
+ AUTH_IN_PROGRESS = "authInProgress"
25
+ UI_UNAVAILABLE = "uiUnavailable"
26
+ USER_CANCELED = "userCanceled"
27
+ TIMEOUT = "timeout"
28
+ SYSTEM_CANCELED = "systemCanceled"
29
+ NO_CREDENTIALS_SET = "noCredentialsSet"
30
+ NO_BIOMETRICS_ENROLLED = "noBiometricsEnrolled"
31
+ NO_BIOMETRIC_HARDWARE = "noBiometricHardware"
32
+ BIOMETRIC_HARDWARE_TEMPORARILY_UNAVAILABLE = (
33
+ "biometricHardwareTemporarilyUnavailable"
34
+ )
35
+ TEMPORARY_LOCKOUT = "temporaryLockout"
36
+ BIOMETRIC_LOCKOUT = "biometricLockout"
37
+ USER_REQUESTED_FALLBACK = "userRequestedFallback"
38
+ DEVICE_ERROR = "deviceError"
39
+ UNKNOWN_ERROR = "unknownError"
40
+
41
+
42
+ @ft.value
43
+ class AndroidAuthMessages:
44
+ """
45
+ Customizable Android authentication dialog strings.
46
+ """
47
+
48
+ sign_in_hint: Optional[str] = None
49
+ cancel_button: Optional[str] = None
50
+ sign_in_title: Optional[str] = None
51
+
52
+
53
+ @ft.value
54
+ class IOSAuthMessages:
55
+ """
56
+ Customizable iOS authentication dialog strings.
57
+ """
58
+
59
+ cancel_button: Optional[str] = None
60
+ localized_fallback_title: Optional[str] = None
61
+
62
+
63
+ @ft.value
64
+ class WindowsAuthMessages:
65
+ """
66
+ Placeholder for Windows authentication messages.
67
+
68
+ `local_auth` 3.x does not currently expose customizable Windows dialog strings.
69
+ """
70
+
71
+
72
+ class LocalAuthException(ft.FletException):
73
+ """
74
+ Raised when local authentication fails.
75
+ """
76
+
77
+ def __init__(
78
+ self,
79
+ code: LocalAuthErrorCode,
80
+ description: Optional[str] = None,
81
+ ):
82
+ self.code = code
83
+ self.description = description
84
+ message = description or code.value
85
+ super().__init__(message)
@@ -0,0 +1,18 @@
1
+ Metadata-Version: 2.4
2
+ Name: flet-local-auth
3
+ Version: 1.0.0.dev2
4
+ Summary: Local authentication service for Flet
5
+ Author-email: "Appveyor Systems Inc." <hello@flet.dev>
6
+ Project-URL: Homepage, https://flet.dev
7
+ Project-URL: Documentation, https://flet.dev/docs/services/localauthentication
8
+ Project-URL: Repository, https://github.com/flet-dev/flet/tree/main/sdk/python/packages/flet-local-auth
9
+ Project-URL: Issues, https://github.com/flet-dev/flet/issues
10
+ Requires-Python: >=3.10
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: flet==1.0.0.dev2
14
+ Dynamic: license-file
15
+
16
+ # Flet Local Authentication
17
+
18
+ `LocalAuthentication` service for Flet apps. Authenticate users with biometrics, PIN, passcode, or pattern via the [`local_auth`](https://pub.dev/packages/local_auth) Flutter plugin.
@@ -0,0 +1,16 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/flet_local_auth/__init__.py
5
+ src/flet_local_auth/local_auth.py
6
+ src/flet_local_auth/types.py
7
+ src/flet_local_auth.egg-info/PKG-INFO
8
+ src/flet_local_auth.egg-info/SOURCES.txt
9
+ src/flet_local_auth.egg-info/dependency_links.txt
10
+ src/flet_local_auth.egg-info/requires.txt
11
+ src/flet_local_auth.egg-info/top_level.txt
12
+ src/flutter/flet_local_auth/pubspec.yaml
13
+ src/flutter/flet_local_auth/lib/flet_local_auth.dart
14
+ src/flutter/flet_local_auth/lib/src/extension.dart
15
+ src/flutter/flet_local_auth/lib/src/local_auth.dart
16
+ src/flutter/flet_local_auth/lib/src/utils/local_auth.dart
@@ -0,0 +1,2 @@
1
+ flet_local_auth
2
+ flutter
@@ -0,0 +1,3 @@
1
+ library flet_local_auth;
2
+
3
+ export "src/extension.dart" show Extension;
@@ -0,0 +1,15 @@
1
+ import 'package:flet/flet.dart';
2
+
3
+ import 'local_auth.dart';
4
+
5
+ class Extension extends FletExtension {
6
+ @override
7
+ FletService? createService(Control control) {
8
+ switch (control.type) {
9
+ case "LocalAuthentication":
10
+ return LocalAuthenticationService(control: control);
11
+ default:
12
+ return null;
13
+ }
14
+ }
15
+ }
@@ -0,0 +1,59 @@
1
+ import 'package:flet/flet.dart';
2
+ import 'package:flutter/material.dart';
3
+ import 'package:local_auth/local_auth.dart';
4
+
5
+ import 'utils/local_auth.dart';
6
+
7
+ class LocalAuthenticationService extends FletService {
8
+ LocalAuthenticationService({required super.control});
9
+
10
+ final LocalAuthentication _auth = LocalAuthentication();
11
+
12
+ @override
13
+ void init() {
14
+ super.init();
15
+ debugPrint(
16
+ "LocalAuthenticationService(${control.id}).init: ${control.properties}",
17
+ );
18
+ control.addInvokeMethodListener(_invokeMethod);
19
+ }
20
+
21
+ Future<dynamic> _invokeMethod(String name, dynamic args) async {
22
+ debugPrint("LocalAuthentication.$name($args)");
23
+ switch (name) {
24
+ case "is_device_supported":
25
+ return await _auth.isDeviceSupported();
26
+ case "can_check_biometrics":
27
+ return await _auth.canCheckBiometrics;
28
+ case "get_available_biometrics":
29
+ return (await _auth.getAvailableBiometrics())
30
+ .map(parseBiometricTypeName)
31
+ .toList();
32
+ case "authenticate":
33
+ try {
34
+ return await _auth.authenticate(
35
+ localizedReason: args["reason"]!,
36
+ authMessages: parseAuthMessages(args),
37
+ biometricOnly: args["biometric_only"] as bool? ?? false,
38
+ sensitiveTransaction:
39
+ args["sensitive_transaction"] as bool? ?? true,
40
+ persistAcrossBackgrounding:
41
+ args["persist_across_backgrounding"] as bool? ?? false,
42
+ );
43
+ } on LocalAuthException catch (e) {
44
+ return localAuthErrorMap(e);
45
+ }
46
+ case "stop_authentication":
47
+ return await _auth.stopAuthentication();
48
+ default:
49
+ throw Exception("Unknown LocalAuthentication method: $name");
50
+ }
51
+ }
52
+
53
+ @override
54
+ void dispose() {
55
+ debugPrint("LocalAuthenticationService(${control.id}).dispose()");
56
+ control.removeInvokeMethodListener(_invokeMethod);
57
+ super.dispose();
58
+ }
59
+ }
@@ -0,0 +1,81 @@
1
+ import 'package:local_auth/local_auth.dart';
2
+ import 'package:local_auth_android/local_auth_android.dart';
3
+ import 'package:local_auth_darwin/local_auth_darwin.dart';
4
+ import 'package:local_auth_windows/local_auth_windows.dart';
5
+
6
+ AndroidAuthMessages? parseAndroidAuthMessages(Map? value) {
7
+ if (value == null) {
8
+ return null;
9
+ }
10
+ return AndroidAuthMessages(
11
+ signInHint: value["sign_in_hint"],
12
+ cancelButton: value["cancel_button"],
13
+ signInTitle: value["sign_in_title"],
14
+ );
15
+ }
16
+
17
+ IOSAuthMessages? parseIosAuthMessages(Map? value) {
18
+ if (value == null) {
19
+ return null;
20
+ }
21
+ return IOSAuthMessages(
22
+ cancelButton: value["cancel_button"],
23
+ localizedFallbackTitle: value["localized_fallback_title"],
24
+ );
25
+ }
26
+
27
+ WindowsAuthMessages? parseWindowsAuthMessages(Map? value) {
28
+ if (value == null) {
29
+ return null;
30
+ }
31
+ return const WindowsAuthMessages();
32
+ }
33
+
34
+ List<AuthMessages> parseAuthMessages(
35
+ Map? args, {
36
+ List<AuthMessages> defaults = const [
37
+ IOSAuthMessages(),
38
+ AndroidAuthMessages(),
39
+ WindowsAuthMessages(),
40
+ ],
41
+ }) {
42
+ final android = parseAndroidAuthMessages(args?["android_messages"]);
43
+ final ios = parseIosAuthMessages(args?["ios_messages"]);
44
+ final windows = parseWindowsAuthMessages(args?["windows_messages"]);
45
+
46
+ if (android == null && ios == null && windows == null) {
47
+ return defaults;
48
+ }
49
+
50
+ final messages = <AuthMessages>[];
51
+ for (final message in defaults) {
52
+ if (message is AndroidAuthMessages) {
53
+ messages.add(android ?? message);
54
+ } else if (message is IOSAuthMessages) {
55
+ messages.add(ios ?? message);
56
+ } else if (message is WindowsAuthMessages) {
57
+ messages.add(windows ?? message);
58
+ } else {
59
+ messages.add(message);
60
+ }
61
+ }
62
+ return messages;
63
+ }
64
+
65
+ String? parseBiometricTypeName(BiometricType type) {
66
+ return type.name;
67
+ }
68
+
69
+ LocalAuthExceptionCode parseLocalAuthExceptionCode(String? value) {
70
+ return LocalAuthExceptionCode.values.firstWhere(
71
+ (code) => code.name == value,
72
+ orElse: () => LocalAuthExceptionCode.unknownError,
73
+ );
74
+ }
75
+
76
+ Map<String, Object?> localAuthErrorMap(LocalAuthException exception) {
77
+ return {
78
+ "error_code": exception.code.name,
79
+ "error_description": exception.description,
80
+ };
81
+ }
@@ -0,0 +1,25 @@
1
+ name: flet_local_auth
2
+ description: Flet Local Authentication service
3
+ version: 0.1.0
4
+ publish_to: none
5
+
6
+ environment:
7
+ sdk: '>=3.3.0 <4.0.0'
8
+ flutter: ">=1.17.0"
9
+
10
+ dependencies:
11
+ flutter:
12
+ sdk: flutter
13
+
14
+ local_auth: 3.0.2
15
+ local_auth_android: 2.0.9
16
+ local_auth_darwin: 2.0.3
17
+ local_auth_windows: 2.0.1
18
+
19
+ flet:
20
+ path: ../../../../../../../packages/flet
21
+
22
+ dev_dependencies:
23
+ flutter_test:
24
+ sdk: flutter
25
+ flutter_lints: ^3.0.0