Add Baron Safe app features through session block skeleton
ci / flutter-check (push) Successful in 4s

This commit is contained in:
2026-06-30 17:17:14 +09:00
parent d2f6af7657
commit 7c8e95e0a3
23 changed files with 1531 additions and 5 deletions
@@ -0,0 +1,89 @@
import 'package:baron_safe_app/src/features/bridge/baron_safe_bridge_models.dart';
import 'package:baron_safe_app/src/features/bridge/baron_safe_bridge_service.dart';
import 'package:baron_safe_app/src/features/session/baron_safe_session_block_service.dart';
import 'package:baron_safe_app/src/features/session/baron_safe_session_client.dart';
import 'package:baron_safe_app/src/features/session/baron_safe_session_models.dart';
import 'package:baron_safe_app/src/features/session/baron_safe_session_repository.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('BiometricBaronSafeSessionBlockService', () {
test('blocks a session after biometric verification succeeds', () async {
final repository = ClientBaronSafeSessionRepository(
MockBaronSafeSessionClient(),
);
final service = BiometricBaronSafeSessionBlockService(
repository: repository,
biometricPrompt: const _FakeBiometricPrompt(verified: true),
);
final result = await service.blockSession(
sessionId: 'session-1',
reason: 'Suspicious login',
);
expect(result.sessionId, 'session-1');
expect(result.biometricVerified, isTrue);
expect(result.blocked, isTrue);
expect(result.message, 'Session blocked');
});
test('does not call block API when biometric verification fails', () async {
final repository = _RecordingSessionRepository();
final service = BiometricBaronSafeSessionBlockService(
repository: repository,
biometricPrompt: const _FakeBiometricPrompt(
verified: false,
reason: 'User canceled biometric prompt',
),
);
final result = await service.blockSession(
sessionId: 'session-1',
reason: 'Suspicious login',
);
expect(result.biometricVerified, isFalse);
expect(result.blocked, isFalse);
expect(result.message, 'User canceled biometric prompt');
expect(repository.blockCallCount, 0);
});
});
}
class _FakeBiometricPrompt implements BaronSafeBiometricPrompt {
const _FakeBiometricPrompt({required this.verified, this.reason = 'OK'});
final bool verified;
final String reason;
@override
Future<BaronSafeBiometricResult> verify({required String reason}) async {
return BaronSafeBiometricResult(verified: verified, reason: this.reason);
}
}
class _RecordingSessionRepository implements BaronSafeSessionRepository {
int blockCallCount = 0;
@override
Future<BaronSafeSessionBlockResponse> blockSession(
BaronSafeSessionBlockRequest request,
) async {
blockCallCount += 1;
return BaronSafeSessionBlockResponse(
sessionId: request.sessionId,
blocked: true,
);
}
@override
Future<BaronSafeSessionDetail> getSessionDetail(String sessionId) {
throw UnimplementedError();
}
@override
Future<List<BaronSafeSessionSummary>> listRecentSessions() {
throw UnimplementedError();
}
}
@@ -0,0 +1,80 @@
import 'package:baron_safe_app/src/features/session/baron_safe_session_client.dart';
import 'package:baron_safe_app/src/features/session/baron_safe_session_models.dart';
import 'package:baron_safe_app/src/features/session/baron_safe_session_repository.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('ClientBaronSafeSessionRepository', () {
test('lists recent sessions from the client', () async {
final repository = ClientBaronSafeSessionRepository(
MockBaronSafeSessionClient(),
);
final sessions = await repository.listRecentSessions();
expect(sessions, hasLength(2));
expect(sessions.first.id, 'session-1');
expect(sessions.last.riskLevel, BaronSafeSessionRiskLevel.high);
});
test('loads a session detail by id', () async {
final repository = ClientBaronSafeSessionRepository(
MockBaronSafeSessionClient(),
);
final session = await repository.getSessionDetail('session-2');
expect(session.serviceName, 'Admin Console');
expect(session.locationLabel, 'Unknown');
expect(session.status, BaronSafeSessionStatus.active);
});
test('throws when a session id is unknown', () async {
final repository = ClientBaronSafeSessionRepository(
MockBaronSafeSessionClient(),
);
expect(
() => repository.getSessionDetail('missing-session'),
throwsA(isA<BaronSafeSessionNotFoundException>()),
);
});
test('blocks a known session through the client', () async {
final repository = ClientBaronSafeSessionRepository(
MockBaronSafeSessionClient(),
);
final result = await repository.blockSession(
const BaronSafeSessionBlockRequest(
sessionId: 'session-1',
reason: 'Suspicious login',
),
);
expect(result.sessionId, 'session-1');
expect(result.blocked, isTrue);
});
});
group('BaronSafeSessionDetail', () {
test('round trips from JSON to model', () {
final session = BaronSafeSessionDetail.fromJson({
'id': 'session-json',
'serviceName': 'JSON Service',
'status': 'blocked',
'riskLevel': 'medium',
'createdAt': '2026-06-30T10:00:00.000Z',
'ipAddress': '203.0.113.11',
'deviceLabel': 'Safari on iOS',
'locationLabel': 'Busan',
'userAgent': 'Safari',
'authMethod': 'phone',
});
expect(session.status, BaronSafeSessionStatus.blocked);
expect(session.riskLevel, BaronSafeSessionRiskLevel.medium);
expect(session.toJson()['locationLabel'], 'Busan');
});
});
}