Multiple improvements in authentication functionality
This commit is contained in:
1 parent
bd5c4e002f
commit
fbee31841d
11 files changed
+260
-17
No files matched your search
@@ -1,5 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'chat_list_screen.dart';
|
||||
import 'user_checker.dart';
|
||||
import 'backend.dart';
|
||||
|
||||
class AppMenu extends StatelessWidget {
|
||||
const AppMenu({super.key});
|
||||
@@ -21,6 +24,22 @@ class AppMenu extends StatelessWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('Logout'),
|
||||
onTap: () async {
|
||||
final storage = const FlutterSecureStorage();
|
||||
await storage.delete(key: 'username');
|
||||
await storage.delete(key: 'password');
|
||||
Backend.disconnect();
|
||||
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => UserChecker(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
// Add other settings options here
|
||||
],
|
||||
),
|
||||
|
||||
@@ -6,26 +6,46 @@ import 'dart:async'; // Import for handling Completers
|
||||
class Backend {
|
||||
static WebSocket? _socket;
|
||||
static String? _url;
|
||||
static String? _username;
|
||||
static Map<int, Completer> _pendingActions = {};
|
||||
static Map<int, StreamController<Map<String, dynamic>>> _chatControllers = {};
|
||||
static int _nextNonce = 0; // Tracking nonce for each action
|
||||
static StreamController<Map<String, dynamic>> _packetStreamController = StreamController.broadcast();
|
||||
|
||||
// Authentication
|
||||
static ({String username, String password})? _credentials;
|
||||
static Completer? _loginCompleter;
|
||||
static Completer? _credentialsCompleter;
|
||||
|
||||
static void setup(String url) {
|
||||
_url = url;
|
||||
connect();
|
||||
}
|
||||
|
||||
static void auth(String username, String password) {
|
||||
static Future<void> auth(String username, String password) {
|
||||
_socket!.send(json.encode({'username': username, 'password': password}));
|
||||
_username = username;
|
||||
_credentials = (username: username, password: password);
|
||||
if (_credentialsCompleter != null) {
|
||||
_credentialsCompleter!.complete(_credentials);
|
||||
_credentialsCompleter = null;
|
||||
}
|
||||
_loginCompleter = Completer();
|
||||
return _loginCompleter!.future;
|
||||
}
|
||||
|
||||
static void connect() {
|
||||
_socket = WebSocket(_url!);
|
||||
_socket!.onOpen.listen((event) {
|
||||
print('Connected to the WebSocket server');
|
||||
print('Logging in...');
|
||||
if (_credentials != null) {
|
||||
_socket!.send(json.encode({'username': _credentials!.username, 'password': _credentials!.password}));
|
||||
} else {
|
||||
_credentialsCompleter = Completer();
|
||||
_credentialsCompleter!.future.then((credentials) {
|
||||
_socket!.send(json.encode({'username': credentials.username, 'password': credentials.password}));
|
||||
});
|
||||
}
|
||||
_loginCompleter?.complete();
|
||||
});
|
||||
_socket!.onError.listen((event) {
|
||||
print('Error: $event');
|
||||
@@ -40,6 +60,11 @@ class Backend {
|
||||
});
|
||||
}
|
||||
|
||||
static void disconnect() {
|
||||
_socket?.close();
|
||||
_loginCompleter = null;
|
||||
}
|
||||
|
||||
static void _reconnect() {
|
||||
Future.delayed(Duration(seconds: 5), () {
|
||||
connect();
|
||||
|
||||
@@ -8,6 +8,13 @@ class LoginScreen extends StatelessWidget {
|
||||
final TextEditingController usernameController = TextEditingController();
|
||||
final TextEditingController passwordController = TextEditingController();
|
||||
|
||||
final FocusNode usernameFocusNode = FocusNode();
|
||||
final FocusNode passwordFocusNode = FocusNode();
|
||||
|
||||
void _handleLogin() {
|
||||
onLogin(usernameController.text, passwordController.text);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@@ -18,18 +25,29 @@ class LoginScreen extends StatelessWidget {
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
TextField(controller: usernameController, decoration: InputDecoration(labelText: 'Username')),
|
||||
TextField(
|
||||
controller: usernameController,
|
||||
focusNode: usernameFocusNode,
|
||||
decoration: InputDecoration(labelText: 'Username'),
|
||||
textInputAction: TextInputAction.next,
|
||||
onSubmitted: (_) {
|
||||
FocusScope.of(context).requestFocus(passwordFocusNode);
|
||||
},
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
TextField(
|
||||
controller: passwordController,
|
||||
focusNode: passwordFocusNode,
|
||||
decoration: InputDecoration(labelText: 'Password'),
|
||||
obscureText: true, // Hide password characters
|
||||
obscureText: true,
|
||||
textInputAction: TextInputAction.done,
|
||||
onSubmitted: (_) {
|
||||
_handleLogin();
|
||||
},
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
onLogin(usernameController.text, passwordController.text);
|
||||
},
|
||||
onPressed: _handleLogin,
|
||||
child: Text('Login'),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'backend.dart';
|
||||
import 'login_screen.dart';
|
||||
import 'chat_screen.dart';
|
||||
@@ -11,12 +12,26 @@ class UserChecker extends StatefulWidget {
|
||||
|
||||
class _UserCheckerState extends State<UserChecker> {
|
||||
String? username;
|
||||
bool isLoading = false;
|
||||
bool isLoading = true;
|
||||
final _storage = const FlutterSecureStorage();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
username = null;
|
||||
_checkSavedCredentials();
|
||||
}
|
||||
|
||||
Future<void> _checkSavedCredentials() async {
|
||||
final savedUsername = await _storage.read(key: 'username');
|
||||
final savedPassword = await _storage.read(key: 'password');
|
||||
|
||||
if (savedUsername != null && savedPassword != null) {
|
||||
_handleLogin(savedUsername, savedPassword);
|
||||
} else {
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static void fetchChats(Function(List<int>) onSuccess) {
|
||||
@@ -28,13 +43,15 @@ class _UserCheckerState extends State<UserChecker> {
|
||||
});
|
||||
}
|
||||
|
||||
void _handleLogin(String user, String password) {
|
||||
Backend.auth(user, password);
|
||||
|
||||
void _handleLogin(String user, String password) async {
|
||||
setState(() {
|
||||
username = user;
|
||||
isLoading = true; // Show loading spinner
|
||||
isLoading = true;
|
||||
});
|
||||
|
||||
await Backend.auth(user, password);
|
||||
await _storage.write(key: 'username', value: user);
|
||||
await _storage.write(key: 'password', value: password);
|
||||
|
||||
fetchChats((chatIds) {
|
||||
if (chatIds.isEmpty) {
|
||||
@@ -49,14 +66,13 @@ class _UserCheckerState extends State<UserChecker> {
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
print("Build UserChecker: $username $isLoading");
|
||||
if (isLoading) {
|
||||
return Center(child: CircularProgressIndicator()); // Loading state UI
|
||||
return Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
return LoginScreen(onLogin: _handleLogin);
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
|
||||
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
flutter_secure_storage_linux
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import flutter_secure_storage_macos
|
||||
import path_provider_foundation
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
}
|
||||
+150
-1
@@ -57,6 +57,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.2"
|
||||
ffi:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: ffi
|
||||
sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@@ -70,11 +78,72 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
flutter_secure_storage:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_secure_storage
|
||||
sha256: "9cad52d75ebc511adfae3d447d5d13da15a55a92c9410e50f67335b6d21d16ea"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.2.4"
|
||||
flutter_secure_storage_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_linux
|
||||
sha256: be76c1d24a97d0b98f8b54bce6b481a380a6590df992d0098f868ad54dc8f688
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.3"
|
||||
flutter_secure_storage_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_macos
|
||||
sha256: "6c0a2795a2d1de26ae202a0d78527d163f4acbb11cde4c75c670f3a0fc064247"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.3"
|
||||
flutter_secure_storage_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_platform_interface
|
||||
sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
flutter_secure_storage_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_web
|
||||
sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
flutter_secure_storage_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_windows
|
||||
sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_web_plugins:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.7"
|
||||
leak_tracker:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -139,6 +208,70 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.1"
|
||||
path_provider:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider
|
||||
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.5"
|
||||
path_provider_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.17"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_foundation
|
||||
sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_linux
|
||||
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
path_provider_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_platform_interface
|
||||
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
path_provider_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_windows
|
||||
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: platform
|
||||
sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.6"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.8"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
@@ -208,6 +341,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.3.1"
|
||||
win32:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
sha256: "329edf97fdd893e0f1e3b9e88d6a0e627128cc17cc316a8d67fda8f1451178ba"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.13.0"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xdg_directories
|
||||
sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
sdks:
|
||||
dart: ">=3.7.2 <4.0.0"
|
||||
flutter: ">=3.18.0-18.0.pre.54"
|
||||
flutter: ">=3.27.0"
|
||||
@@ -35,6 +35,9 @@ dependencies:
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
cupertino_icons: ^1.0.8
|
||||
|
||||
# For user credentials and sensitive data
|
||||
flutter_secure_storage: ^9.2.4
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
flutter_secure_storage_windows
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
||||
Reference in new issue
Block a user