inventory_mobile/lib/services/auth_service.dart
2025-12-15 16:04:14 +08:00

198 lines
7.3 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'package:html/parser.dart' as html_parser;
import 'package:inventory_system/services/api_service.dart';
import 'package:inventory_system/services/session_manager.dart';
class AuthService {
Future<Map<String, dynamic>> signIn({
required String usernameOrEmail,
required String password,
}) async {
if (usernameOrEmail.toLowerCase() == 'admin@pstw.com.my') {
return _performAdminWebLogin(usernameOrEmail, password);
} else {
return _performLdapApiLogin(usernameOrEmail, password);
}
}
Future<Map<String, dynamic>> _performLdapApiLogin(
String username, String password) async {
final Uri loginUri = Uri.parse('${ApiService.baseUrl}/IdentityAPI/LdapLogin');
final loginHeaders = {'Content-Type': 'application/json; charset=UTF-8'};
final loginBody = jsonEncode({'UserName': username, 'Password': password});
try {
final response = await http.post(loginUri, headers: loginHeaders, body: loginBody);
if (response.statusCode != 200) {
return _handleLdapError(response);
}
final String? sessionCookie = response.headers['set-cookie'];
if (sessionCookie == null) {
return {'success': false, 'message': 'Login succeeded, but failed to start a session.'};
}
SessionManager.instance.setCookie(sessionCookie);
return await _fetchLdapUserDetails(sessionCookie, username);
} on TimeoutException {
return {'success': false, 'message': 'The connection timed out. Please try again.'};
} on SocketException {
return {'success': false, 'message': 'Could not connect to the server. Please check your network.'};
} catch (e) {
debugPrint('An unexpected error occurred during LDAP login: $e');
return {'success': false, 'message': 'An unexpected error occurred.'};
}
}
Future<Map<String, dynamic>> fetchUserProfile() async {
final String? sessionCookie = SessionManager.instance.getCookie();
if (sessionCookie == null) {
return {'success': false, 'message': 'No active session found.'};
}
final Uri userInfoUri = Uri.parse('${ApiService.baseUrl}/IdentityAPI/GetUserInformation');
final headers = {'Cookie': sessionCookie};
try {
final response = await http.post(userInfoUri, headers: headers);
if (response.statusCode == 200) {
final userInfoResponse = jsonDecode(response.body);
final Map<String, dynamic>? userData = userInfoResponse['userInfo'];
if (userData == null) {
return {'success': false, 'message': 'User profile data is missing from the API response.'};
}
return {
'success': true,
'data': userData // Return raw user data as requested for display
};
} else {
return {'success': false, 'message': 'Failed to retrieve user profile. Status: ${response.statusCode}'};
}
} catch (e) {
debugPrint('Error fetching user profile: $e');
return {'success': false, 'message': 'Error fetching user details.'};
}
}
Future<Map<String, dynamic>> _fetchLdapUserDetails(String sessionCookie, String username) async {
final Uri userInfoUri = Uri.parse('${ApiService.baseUrl}/IdentityAPI/GetUserInformation');
final headers = {'Cookie': sessionCookie};
try {
final response = await http.post(userInfoUri, headers: headers);
if (response.statusCode == 200) {
final userInfoResponse = jsonDecode(response.body);
final Map<String, dynamic>? userData = userInfoResponse['userInfo'];
if (userData == null) {
return {'success': false, 'message': 'User profile data is missing from the API response.'};
}
final List<dynamic> roles = userData['role'] ?? [];
final bool isInventoryMaster = roles.contains('Inventory Master');
final bool isSuperAdmin = roles.contains('Super Admin');
final Map<String, dynamic> sessionData = Map<String, dynamic>.from(userData);
sessionData['fullName'] = username;
sessionData['isAdmin'] = isInventoryMaster || isSuperAdmin;
sessionData['isInventoryMaster'] = isInventoryMaster;
sessionData['isSuperAdmin'] = isSuperAdmin;
sessionData['role'] = roles;
return {
'success': true,
'data': sessionData
};
} else {
return {'success': false, 'message': 'Logged in, but failed to retrieve user profile.'};
}
} catch (e) {
return {'success': false, 'message': 'Error fetching user details after login.'};
}
}
Map<String, dynamic> _handleLdapError(http.Response response) {
try {
final errorData = jsonDecode(response.body);
String errorMessage = errorData['message'] ?? 'An unknown error occurred';
if (errorMessage.toLowerCase().contains('was not found')) {
return {'success': false, 'message': 'Wrong username or email.'};
} else if (errorMessage.toLowerCase().contains('incorrect password.')) {
return {'success': false, 'message': 'Wrong password.'};
} else {
return {'success': false, 'message': errorMessage};
}
} catch (e) {
return {'success': false, 'message': 'Login failed with status: ${response.statusCode}'};
}
}
Future<Map<String, dynamic>> _performAdminWebLogin(
String email, String password) async {
final Uri loginUri = Uri.parse('${ApiService.baseUrl}/Identity/Account/Login');
try {
final getResponse = await http.get(loginUri);
final String? sessionCookie = getResponse.headers['set-cookie'];
final document = html_parser.parse(getResponse.body);
final token = document.querySelector('input[name="__RequestVerificationToken"]')?.attributes['value'];
if (sessionCookie == null || token == null) {
return {'success': false, 'message': 'Failed to prepare a secure login session.'};
}
SessionManager.instance.setCookie(sessionCookie);
final postResponse = await http.post(
loginUri,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Cookie': sessionCookie,
},
body: {
'Email': email,
'Password': password,
'RememberMe': 'false',
'__RequestVerificationToken': token,
},
);
if (postResponse.statusCode == 302) {
// After a successful login, the server issues a new, authenticated cookie.
// We must capture and save this new cookie from the POST response.
final String? newSessionCookie = postResponse.headers['set-cookie'];
if (newSessionCookie != null) {
SessionManager.instance.setCookie(newSessionCookie);
}
return {
'success': true,
'data': {
'fullName': 'Super Admin',
'isAdmin': true,
'isInventoryMaster': false,
'isSuperAdmin': true,
'role': ['Super Admin'],
}
};
} else {
return {'success': false, 'message': 'Admin login failed. Please check credentials.'};
}
} catch (e) {
debugPrint('An unexpected error occurred during Admin login: $e');
return {'success': false, 'message': 'An unexpected error occurred.'};
}
}
}