import 'package:flutter_secure_storage/flutter_secure_storage.dart'; /// Keychain access group shared between the Runner and the (Phase 3) iOS /// Notification Service Extension so the NSE can read the RSA private key, /// the server public key and the Nextcloud app password to decrypt pushes /// while the app is not running. /// /// A team-prefixed keychain access group (`$(AppIdentifierPrefix)eu.mhsl…push`) /// listed under `keychain-access-groups` in both the Runner and the NSE /// entitlements. The literal `MY55VF3KPG.` prefix is the team's stable /// AppIdentifierPrefix; Runner and NSE share the group because they sign with /// the same team. (App-group ids like `group.*` can't be used here because the /// Xcode-managed profiles only grant `.*` keychain groups.) /// On Android `groupId` is ignored, so this is a no-op there. const String kPushKeychainGroup = 'MY55VF3KPG.eu.mhsl.marianum.mobile.client.push'; /// [IOSOptions] used for every push-related secure-storage entry. Uses /// `first_unlock` accessibility so the NSE can read the key material after the /// first device unlock following a reboot (the NSE may run while locked). const IOSOptions kPushIosOptions = IOSOptions( groupId: kPushKeychainGroup, accessibility: KeychainAccessibility.first_unlock, ); /// Shared secure storage instance for all push key material and registration /// bookkeeping. Kept separate from [AccountData]'s default storage because the /// entries here are group-scoped for NSE access. const FlutterSecureStorage pushSecureStorage = FlutterSecureStorage( iOptions: kPushIosOptions, ); /// Minimal storage contract so tests can inject an in-memory fake instead of /// touching the platform keystore. abstract class FlutterSecureStorageLike { Future read({required String key}); Future write({required String key, required String? value}); Future delete({required String key}); } /// Default [FlutterSecureStorageLike] backed by [pushSecureStorage]. class PushSecureStorage implements FlutterSecureStorageLike { const PushSecureStorage(); @override Future read({required String key}) => pushSecureStorage.read(key: key); @override Future write({required String key, required String? value}) => pushSecureStorage.write(key: key, value: value); @override Future delete({required String key}) => pushSecureStorage.delete(key: key); }