added guardian login with views for their assigned childs
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:marianum_mobile/auth_link/device_binding.dart';
|
||||
import 'package:marianum_mobile/auth_link/guardian_login_link.dart';
|
||||
import 'package:marianum_mobile/auth_link/pending_guardian_request.dart';
|
||||
|
||||
void main() {
|
||||
final live = Uri.parse('https://connect.marianum-fulda.de');
|
||||
|
||||
group('GuardianLoginLink.parse', () {
|
||||
test('accepts a link of the active server', () {
|
||||
final link = GuardianLoginLink.parse(
|
||||
Uri.parse(
|
||||
'https://connect.marianum-fulda.de/app/guardian-login?rid=r1<=t1',
|
||||
),
|
||||
apiBase: live,
|
||||
);
|
||||
expect(link?.requestId, 'r1');
|
||||
expect(link?.linkToken, 't1');
|
||||
});
|
||||
|
||||
test('rejects links of another server', () {
|
||||
expect(
|
||||
GuardianLoginLink.parse(
|
||||
Uri.parse(
|
||||
'https://connect-beta.marianum-fulda.de/app/guardian-login?rid=r<=t',
|
||||
),
|
||||
apiBase: live,
|
||||
),
|
||||
isNull,
|
||||
);
|
||||
});
|
||||
|
||||
test('respects a path prefix of a custom server', () {
|
||||
final custom = Uri.parse('https://dev.example.org/connect/');
|
||||
expect(
|
||||
GuardianLoginLink.parse(
|
||||
Uri.parse(
|
||||
'https://dev.example.org/connect/app/guardian-login?rid=r<=t',
|
||||
),
|
||||
apiBase: custom,
|
||||
),
|
||||
isNotNull,
|
||||
);
|
||||
});
|
||||
|
||||
test('rejects other paths, plain http and missing parameters', () {
|
||||
for (final raw in [
|
||||
'https://connect.marianum-fulda.de/app/other?rid=r<=t',
|
||||
'http://connect.marianum-fulda.de/app/guardian-login?rid=r<=t',
|
||||
'https://connect.marianum-fulda.de/app/guardian-login?rid=r',
|
||||
'https://connect.marianum-fulda.de/app/guardian-login?lt=t',
|
||||
]) {
|
||||
expect(
|
||||
GuardianLoginLink.parse(Uri.parse(raw), apiBase: live),
|
||||
isNull,
|
||||
reason: raw,
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
group('DeviceBinding', () {
|
||||
test('challenge is the base64url SHA-256 of the secret, unpadded', () {
|
||||
// RFC 7636 appendix B test vector.
|
||||
expect(
|
||||
DeviceBinding.challengeFor(
|
||||
'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk',
|
||||
),
|
||||
'E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM',
|
||||
);
|
||||
});
|
||||
|
||||
test('secrets are random and URL-safe', () {
|
||||
final a = DeviceBinding.generateSecret();
|
||||
final b = DeviceBinding.generateSecret();
|
||||
expect(a, isNot(b));
|
||||
expect(a, matches(RegExp(r'^[A-Za-z0-9_-]{43}$')));
|
||||
});
|
||||
});
|
||||
|
||||
group('PendingGuardianRequest', () {
|
||||
final request = PendingGuardianRequest(
|
||||
requestId: 'r1',
|
||||
email: 'e@x.de',
|
||||
deviceSecret: 's',
|
||||
expiresAt: DateTime.utc(2026, 9, 19, 12, 15),
|
||||
resendAvailableAt: DateTime.utc(2026, 9, 19, 12, 1),
|
||||
);
|
||||
|
||||
test('round-trips through JSON', () {
|
||||
final copy = PendingGuardianRequest.fromJson(request.toJson())!;
|
||||
expect(copy.requestId, 'r1');
|
||||
expect(copy.email, 'e@x.de');
|
||||
expect(copy.expiresAt, request.expiresAt);
|
||||
expect(copy.codeLength, 6);
|
||||
});
|
||||
|
||||
test('corrupt JSON reads as absent', () {
|
||||
expect(PendingGuardianRequest.fromJson({'requestId': 1}), isNull);
|
||||
});
|
||||
|
||||
test('expires at expiresAt', () {
|
||||
expect(request.isExpired(DateTime.utc(2026, 9, 19, 12, 14)), isFalse);
|
||||
expect(request.isExpired(DateTime.utc(2026, 9, 19, 12, 15)), isTrue);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user