138 lines
4.0 KiB
Dart
138 lines
4.0 KiB
Dart
import 'package:flutter/widgets.dart';
|
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:ikar/core/security/app_lock.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
void main() {
|
|
TestWidgetsFlutterBinding.ensureInitialized();
|
|
final lock = AppLock.instance;
|
|
|
|
setUp(() async {
|
|
SharedPreferences.setMockInitialValues({});
|
|
FlutterSecureStorage.setMockInitialValues({});
|
|
await lock.load();
|
|
});
|
|
|
|
tearDown(() async {
|
|
await lock.disable();
|
|
});
|
|
|
|
test('a fresh install is not locked', () {
|
|
expect(lock.enabled.value, isFalse);
|
|
expect(lock.locked.value, isFalse);
|
|
lock.lock();
|
|
expect(lock.locked.value, isFalse);
|
|
});
|
|
|
|
test(
|
|
'a missing secure key never silently disables a configured lock',
|
|
() async {
|
|
SharedPreferences.setMockInitialValues({'app_lock_enabled': true});
|
|
await lock.load();
|
|
expect(lock.enabled.value, isTrue);
|
|
expect(lock.locked.value, isTrue);
|
|
expect(await lock.unlockWithPin('1234'), isFalse);
|
|
},
|
|
);
|
|
|
|
test('overlapping PIN attempts cannot race a successful unlock', () async {
|
|
await lock.setPin('2468');
|
|
lock.lock();
|
|
final wrong = lock.unlockWithPin('0000');
|
|
expect(await lock.unlockWithPin('2468'), isFalse);
|
|
expect(await wrong, isFalse);
|
|
expect(lock.locked.value, isTrue);
|
|
expect(await lock.unlockWithPin('2468'), isTrue);
|
|
});
|
|
|
|
test('a malformed secure key fails closed', () async {
|
|
SharedPreferences.setMockInitialValues({'app_lock_enabled': true});
|
|
FlutterSecureStorage.setMockInitialValues({'app_lock_pin': 'v1:!:!'});
|
|
await lock.load();
|
|
expect(await lock.unlockWithPin('2468'), isFalse);
|
|
expect(lock.locked.value, isTrue);
|
|
});
|
|
|
|
test('the right passcode unlocks and a wrong one does not', () async {
|
|
await lock.setPin('2468');
|
|
lock.lock();
|
|
expect(lock.locked.value, isTrue);
|
|
|
|
expect(await lock.unlockWithPin('1111'), isFalse);
|
|
expect(lock.locked.value, isTrue);
|
|
expect(lock.attemptsLeft, AppLock.maxAttempts - 1);
|
|
|
|
expect(await lock.unlockWithPin('2468'), isTrue);
|
|
expect(lock.locked.value, isFalse);
|
|
expect(lock.attemptsLeft, AppLock.maxAttempts);
|
|
});
|
|
|
|
test('five wrong attempts block input even for the right code', () async {
|
|
await lock.setPin('2468');
|
|
lock.lock();
|
|
for (var i = 0; i < AppLock.maxAttempts; i++) {
|
|
expect(await lock.unlockWithPin('0000'), isFalse);
|
|
}
|
|
|
|
expect(lock.blockedUntil.value, isNotNull);
|
|
expect(
|
|
lock.blockedUntil.value!.difference(DateTime.now()),
|
|
greaterThan(AppLock.lockout - const Duration(seconds: 5)),
|
|
);
|
|
expect(await lock.unlockWithPin('2468'), isFalse);
|
|
expect(lock.locked.value, isTrue);
|
|
});
|
|
|
|
test('the lockout survives a restart', () async {
|
|
await lock.setPin('2468');
|
|
for (var i = 0; i < AppLock.maxAttempts; i++) {
|
|
await lock.unlockWithPin('0000');
|
|
}
|
|
|
|
await lock.load();
|
|
|
|
expect(lock.locked.value, isTrue);
|
|
expect(lock.blockedUntil.value, isNotNull);
|
|
});
|
|
|
|
test('a restart with a passcode starts locked', () async {
|
|
await lock.setPin('2468');
|
|
lock.unlock();
|
|
|
|
await lock.load();
|
|
|
|
expect(lock.enabled.value, isTrue);
|
|
expect(lock.locked.value, isTrue);
|
|
});
|
|
|
|
test(
|
|
'going to the background locks, an app-launched picker does not',
|
|
() async {
|
|
await lock.setPin('2468');
|
|
lock.unlock();
|
|
|
|
await lock.external(() async {
|
|
lock.onLifecycle(AppLifecycleState.paused);
|
|
});
|
|
expect(lock.locked.value, isFalse);
|
|
|
|
lock.onLifecycle(AppLifecycleState.inactive);
|
|
expect(lock.locked.value, isFalse);
|
|
|
|
lock.onLifecycle(AppLifecycleState.paused);
|
|
expect(lock.locked.value, isTrue);
|
|
},
|
|
);
|
|
|
|
test('turning the passcode off forgets it', () async {
|
|
await lock.setPin('2468');
|
|
await lock.disable();
|
|
|
|
expect(lock.enabled.value, isFalse);
|
|
expect(await lock.checkPin('2468'), isFalse);
|
|
await lock.load();
|
|
expect(lock.locked.value, isFalse);
|
|
});
|
|
}
|