Files
login-vault-android/lib/auth_service.dart

140 lines
4.6 KiB
Dart

import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:local_auth/local_auth.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:login_vault_app/constants.dart';
/// Handles app-level authentication, session, and local identity.
class AuthService {
final FlutterSecureStorage _storage = const FlutterSecureStorage();
final LocalAuthentication _localAuth = LocalAuthentication();
// ---------- Identity (email + app password) ----------
Future<String?> getEmail() async =>
await _storage.read(key: AppConstants.secureKeyEmail);
Future<String?> getAppPassword() async =>
await _storage.read(key: AppConstants.secureKeyAppPassword);
Future<bool> isRegistered() async => (await getEmail()) != null;
Future<void> registerWithEmail(String email, String appPassword) async {
await _storage.write(key: AppConstants.secureKeyEmail, value: email);
await _storage.write(
key: AppConstants.secureKeyAppPassword, value: appPassword);
}
Future<void> registerWithGoogle(String email) async {
await _storage.write(key: AppConstants.secureKeyEmail, value: email);
final existing = await getAppPassword();
if (existing == null) {
await _storage.write(
key: AppConstants.secureKeyAppPassword, value: '__google__');
}
}
/// Verify the entered app password against the stored one.
Future<bool> verifyPassword(String password) async {
final stored = await getAppPassword();
if (stored == null) return false;
if (stored == '__google__') return true; // google users: any pass ok
return stored == password;
}
Future<void> changePassword(String newPassword) async {
await _storage.write(
key: AppConstants.secureKeyAppPassword, value: newPassword);
}
// ---------- Biometric (fingerprint) ----------
/// Can the device authenticate with biometrics (fingerprint etc.)?
Future<bool> canUseBiometrics() async {
try {
final supported = await _localAuth.isDeviceSupported();
if (!supported) return false;
final available = await _localAuth.getAvailableBiometrics();
return available.isNotEmpty;
} catch (_) {
return false;
}
}
/// Prompt the OS biometric dialog. Returns true on success.
Future<bool> authenticateWithBiometrics() async {
try {
return await _localAuth.authenticate(
localizedReason: 'Gunakan sidik jari untuk membuka Login Vault',
options: const AuthenticationOptions(
biometricOnly: true,
stickyAuth: true,
),
);
} catch (_) {
return false;
}
}
// ---------- Session ----------
/// Persist that a session was just opened (with timestamp).
Future<void> openSession() async {
await _storage.write(
key: AppConstants.secureKeySession, value: DateTime.now().toIso8601String());
}
Future<void> closeSession() async {
await _storage.delete(key: AppConstants.secureKeySession);
}
/// Returns true if a valid, non-expired session exists.
/// [timeoutMinutes] = 0 means "stay logged in until manual logout".
Future<bool> hasValidSession(int timeoutMinutes) async {
if (timeoutMinutes <= 0) {
// never auto-expire; just check a session was opened
final v = await _storage.read(key: AppConstants.secureKeySession);
return v != null;
}
final v = await _storage.read(key: AppConstants.secureKeySession);
if (v == null) return false;
final opened = DateTime.tryParse(v);
if (opened == null) return false;
final diff = DateTime.now().difference(opened).inMinutes;
return diff < timeoutMinutes;
}
// ---------- Timeout setting ----------
/// Get configured session timeout (minutes). Default 3.
Future<int> getTimeoutMinutes() async {
final sp = await _prefs();
return sp.getInt(AppConstants.prefTimeout) ?? 3;
}
Future<void> setTimeoutMinutes(int minutes) async {
final sp = await _prefs();
await sp.setInt(AppConstants.prefTimeout, minutes);
}
// ---------- Biometric toggle setting ----------
Future<bool> isBiometricEnabled() async {
final sp = await _prefs();
return sp.getBool(AppConstants.prefBiometric) ?? false;
}
Future<void> setBiometricEnabled(bool on) async {
final sp = await _prefs();
await sp.setBool(AppConstants.prefBiometric, on);
}
Future<SharedPreferences> _prefs() async =>
await SharedPreferences.getInstance();
Future<void> reset() async {
await _storage.delete(key: AppConstants.secureKeyEmail);
await _storage.delete(key: AppConstants.secureKeyAppPassword);
await _storage.delete(key: AppConstants.secureKeySession);
}
}