mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-10 12:07:58 -06:00
feat: Add debug output, run app in guarded zone
This commit is contained in:
@@ -3,6 +3,7 @@ import 'package:flutter/widgets.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:hive_flutter/adapters.dart';
|
||||
import 'package:hydrated_bloc/hydrated_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
|
||||
import 'package:paperless_mobile/core/config/hive/hive_extensions.dart';
|
||||
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
|
||||
@@ -37,7 +38,10 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
}) async {
|
||||
assert(credentials.username != null && credentials.password != null);
|
||||
final localUserId = "${credentials.username}@$serverUrl";
|
||||
|
||||
_debugPrintMessage(
|
||||
"login",
|
||||
"Trying to login $localUserId...",
|
||||
);
|
||||
await _addUser(
|
||||
localUserId,
|
||||
serverUrl,
|
||||
@@ -60,6 +64,10 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
localUserId: localUserId,
|
||||
),
|
||||
);
|
||||
_debugPrintMessage(
|
||||
"login",
|
||||
"User successfully logged in.",
|
||||
);
|
||||
}
|
||||
|
||||
/// Switches to another account if it exists.
|
||||
@@ -161,26 +169,57 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
/// Performs a conditional hydration based on the local authentication success.
|
||||
///
|
||||
Future<void> restoreSessionState() async {
|
||||
_debugPrintMessage(
|
||||
"restoreSessionState",
|
||||
"Trying to restore previous session...",
|
||||
);
|
||||
final globalSettings =
|
||||
Hive.box<GlobalSettings>(HiveBoxes.globalSettings).getValue()!;
|
||||
final localUserId = globalSettings.currentLoggedInUser;
|
||||
if (localUserId == null) {
|
||||
_debugPrintMessage(
|
||||
"restoreSessionState",
|
||||
"There is nothing to restore.",
|
||||
);
|
||||
// If there is nothing to restore, we can quit here.
|
||||
return;
|
||||
}
|
||||
final localUserAccountBox =
|
||||
Hive.box<LocalUserAccount>(HiveBoxes.localUserAccount);
|
||||
final localUserAccount = localUserAccountBox.get(localUserId)!;
|
||||
|
||||
_debugPrintMessage(
|
||||
"restoreSessionState",
|
||||
"Checking if biometric authentication is required...",
|
||||
);
|
||||
if (localUserAccount.settings.isBiometricAuthenticationEnabled) {
|
||||
_debugPrintMessage(
|
||||
"restoreSessionState",
|
||||
"Biometric authentication required, waiting for user to authenticate...",
|
||||
);
|
||||
final localAuthSuccess = await _localAuthService
|
||||
.authenticateLocalUser("Authenticate to log back in"); //TODO: INTL
|
||||
if (!localAuthSuccess) {
|
||||
emit(const AuthenticationState.requriresLocalAuthentication());
|
||||
_debugPrintMessage(
|
||||
"restoreSessionState",
|
||||
"User could not be authenticated.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
_debugPrintMessage(
|
||||
"restoreSessionState",
|
||||
"User successfully autheticated.",
|
||||
);
|
||||
} else {
|
||||
_debugPrintMessage(
|
||||
"restoreSessionState",
|
||||
"Biometric authentication not configured, skipping.",
|
||||
);
|
||||
}
|
||||
|
||||
_debugPrintMessage(
|
||||
"restoreSessionState",
|
||||
"Trying to retrieve authentication credentials...",
|
||||
);
|
||||
final authentication =
|
||||
await withEncryptedBox<UserCredentials, UserCredentials>(
|
||||
HiveBoxes.localUserCredentials, (box) {
|
||||
@@ -188,14 +227,32 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
});
|
||||
|
||||
if (authentication == null) {
|
||||
_debugPrintMessage(
|
||||
"restoreSessionState",
|
||||
"Could not retrieve existing authentication credentials.",
|
||||
);
|
||||
throw Exception(
|
||||
"User should be authenticated but no authentication information was found."); //TODO: INTL
|
||||
"User should be authenticated but no authentication information was found.",
|
||||
); //TODO: INTL
|
||||
}
|
||||
_debugPrintMessage(
|
||||
"restoreSessionState",
|
||||
"Authentication credentials successfully retrieved.",
|
||||
);
|
||||
_debugPrintMessage(
|
||||
"restoreSessionState",
|
||||
"Updating current session state...",
|
||||
);
|
||||
_sessionManager.updateSettings(
|
||||
clientCertificate: authentication.clientCertificate,
|
||||
authToken: authentication.token,
|
||||
baseUrl: localUserAccount.serverUrl,
|
||||
);
|
||||
_debugPrintMessage(
|
||||
"restoreSessionState",
|
||||
"Current session state successfully updated.",
|
||||
);
|
||||
|
||||
final apiVersion = await _getApiVersion(_sessionManager.client);
|
||||
await _updateRemoteUser(
|
||||
_sessionManager,
|
||||
@@ -208,20 +265,41 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
localUserId: localUserId,
|
||||
),
|
||||
);
|
||||
_debugPrintMessage(
|
||||
"restoreSessionState",
|
||||
"Session was successfully restored.",
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> logout() async {
|
||||
_debugPrintMessage(
|
||||
"logout",
|
||||
"Trying to log out current user...",
|
||||
);
|
||||
await _resetExternalState();
|
||||
final globalSettings =
|
||||
Hive.box<GlobalSettings>(HiveBoxes.globalSettings).getValue()!;
|
||||
globalSettings.currentLoggedInUser = null;
|
||||
await globalSettings.save();
|
||||
|
||||
emit(const AuthenticationState.unauthenticated());
|
||||
_debugPrintMessage(
|
||||
"logout",
|
||||
"User successfully logged out.",
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _resetExternalState() async {
|
||||
_debugPrintMessage(
|
||||
"_resetExternalState",
|
||||
"Resetting session manager and clearing storage...",
|
||||
);
|
||||
_sessionManager.resetSettings();
|
||||
await HydratedBloc.storage.clear();
|
||||
_debugPrintMessage(
|
||||
"_resetExternalState",
|
||||
"Session manager successfully reset and storage cleared.",
|
||||
);
|
||||
}
|
||||
|
||||
Future<int> _addUser(
|
||||
@@ -232,6 +310,7 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
SessionManager sessionManager,
|
||||
) async {
|
||||
assert(credentials.username != null && credentials.password != null);
|
||||
_debugPrintMessage("_addUser", "Adding new user $localUserId...");
|
||||
|
||||
sessionManager.updateSettings(
|
||||
baseUrl: serverUrl,
|
||||
@@ -240,11 +319,21 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
|
||||
final authApi = _apiFactory.createAuthenticationApi(sessionManager.client);
|
||||
|
||||
_debugPrintMessage(
|
||||
"_addUser",
|
||||
"Trying to login user ${credentials.username} on $serverUrl...",
|
||||
);
|
||||
|
||||
final token = await authApi.login(
|
||||
username: credentials.username!,
|
||||
password: credentials.password!,
|
||||
);
|
||||
|
||||
_debugPrintMessage(
|
||||
"_addUser",
|
||||
"Successfully acquired token.",
|
||||
);
|
||||
|
||||
sessionManager.updateSettings(
|
||||
baseUrl: serverUrl,
|
||||
clientCertificate: clientCert,
|
||||
@@ -257,17 +346,41 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
Hive.box<LocalUserAppState>(HiveBoxes.localUserAppState);
|
||||
|
||||
if (userAccountBox.containsKey(localUserId)) {
|
||||
_debugPrintMessage(
|
||||
"_addUser",
|
||||
"An error occurred! The user $localUserId already exists.",
|
||||
);
|
||||
throw Exception("User already exists!");
|
||||
}
|
||||
final apiVersion = await _getApiVersion(sessionManager.client);
|
||||
|
||||
final serverUser = await _apiFactory
|
||||
.createUserApi(
|
||||
sessionManager.client,
|
||||
apiVersion: apiVersion,
|
||||
)
|
||||
.findCurrentUser();
|
||||
|
||||
_debugPrintMessage(
|
||||
"_addUser",
|
||||
"Trying to fetch user object for $localUserId...",
|
||||
);
|
||||
late UserModel serverUser;
|
||||
try {
|
||||
serverUser = await _apiFactory
|
||||
.createUserApi(
|
||||
sessionManager.client,
|
||||
apiVersion: apiVersion,
|
||||
)
|
||||
.findCurrentUser();
|
||||
} on DioError catch (error, stackTrace) {
|
||||
_debugPrintMessage(
|
||||
"_addUser",
|
||||
"An error occurred: ${error.message}",
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
_debugPrintMessage(
|
||||
"_addUser",
|
||||
"User object successfully fetched.",
|
||||
);
|
||||
_debugPrintMessage(
|
||||
"_addUser",
|
||||
"Persisting local user account...",
|
||||
);
|
||||
// Create user account
|
||||
await userAccountBox.put(
|
||||
localUserId,
|
||||
@@ -278,15 +391,29 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
paperlessUser: serverUser,
|
||||
),
|
||||
);
|
||||
|
||||
_debugPrintMessage(
|
||||
"_addUser",
|
||||
"Local user account successfully persisted.",
|
||||
);
|
||||
_debugPrintMessage(
|
||||
"_addUser",
|
||||
"Persisting user state...",
|
||||
);
|
||||
// Create user state
|
||||
await userStateBox.put(
|
||||
localUserId,
|
||||
LocalUserAppState(userId: localUserId),
|
||||
);
|
||||
|
||||
_debugPrintMessage(
|
||||
"_addUser",
|
||||
"User state successfully persisted.",
|
||||
);
|
||||
// Save credentials in encrypted box
|
||||
await withEncryptedBox(HiveBoxes.localUserCredentials, (box) async {
|
||||
_debugPrintMessage(
|
||||
"_addUser",
|
||||
"Saving user credentials inside encrypted storage...",
|
||||
);
|
||||
await box.put(
|
||||
localUserId,
|
||||
UserCredentials(
|
||||
@@ -294,17 +421,32 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
clientCertificate: clientCert,
|
||||
),
|
||||
);
|
||||
_debugPrintMessage(
|
||||
"_addUser",
|
||||
"User credentials successfully saved.",
|
||||
);
|
||||
});
|
||||
final hostsBox = Hive.box<String>(HiveBoxes.hosts);
|
||||
if (!hostsBox.values.contains(serverUrl)) {
|
||||
await hostsBox.add(serverUrl);
|
||||
}
|
||||
|
||||
return serverUser.id;
|
||||
}
|
||||
|
||||
Future<int> _getApiVersion(Dio dio) async {
|
||||
_debugPrintMessage(
|
||||
"_getApiVersion",
|
||||
"Trying to fetch API version...",
|
||||
);
|
||||
final response = await dio.get("/api/");
|
||||
return int.parse(response.headers.value('x-api-version') ?? "3");
|
||||
final apiVersion =
|
||||
int.parse(response.headers.value('x-api-version') ?? "3");
|
||||
_debugPrintMessage(
|
||||
"_getApiVersion",
|
||||
"API version ($apiVersion) successfully retrieved.",
|
||||
);
|
||||
return apiVersion;
|
||||
}
|
||||
|
||||
/// Fetches possibly updated (permissions, name, updated server version and thus new user model, ...) remote user data.
|
||||
@@ -313,13 +455,37 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
LocalUserAccount localUserAccount,
|
||||
int apiVersion,
|
||||
) async {
|
||||
_debugPrintMessage(
|
||||
"_updateRemoteUser",
|
||||
"Updating paperless user object...",
|
||||
);
|
||||
final updatedPaperlessUser = await _apiFactory
|
||||
.createUserApi(
|
||||
sessionManager.client,
|
||||
apiVersion: apiVersion,
|
||||
)
|
||||
.findCurrentUser();
|
||||
|
||||
localUserAccount.paperlessUser = updatedPaperlessUser;
|
||||
await localUserAccount.save();
|
||||
_debugPrintMessage(
|
||||
"_updateRemoteUser",
|
||||
"Paperless user object successfully updated.",
|
||||
);
|
||||
}
|
||||
|
||||
void _debugPrintMessage(
|
||||
String methodName,
|
||||
String message, {
|
||||
Object? error,
|
||||
StackTrace? stackTrace,
|
||||
}) {
|
||||
debugPrint("AuthenticationCubit#$methodName: $message");
|
||||
if (error != null) {
|
||||
debugPrint(error.toString());
|
||||
}
|
||||
if (stackTrace != null) {
|
||||
debugPrintStack(stackTrace: stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,10 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||
import 'package:hive_flutter/adapters.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
|
||||
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||
import 'package:paperless_mobile/core/exception/server_message_exception.dart';
|
||||
import 'package:paperless_mobile/features/login/cubit/authentication_cubit.dart';
|
||||
import 'package:paperless_mobile/features/login/model/client_certificate.dart';
|
||||
import 'package:paperless_mobile/features/login/model/client_certificate_form_model.dart';
|
||||
@@ -147,7 +149,11 @@ class _LoginPageState extends State<LoginPage> {
|
||||
form[ServerAddressFormField.fkServerAddress],
|
||||
clientCert,
|
||||
);
|
||||
} on Exception catch (error) {
|
||||
} on PaperlessServerException catch (error) {
|
||||
showErrorMessage(context, error);
|
||||
} on ServerMessageException catch (error) {
|
||||
showLocalizedError(context, error.message);
|
||||
} catch (error) {
|
||||
showGenericError(context, error);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user