diff --git a/ios/Podfile.lock b/ios/Podfile.lock index f25d3cd..557bbc7 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -4,12 +4,12 @@ PODS: - Flutter DEPENDENCIES: - - Flutter (from `.symlinks/flutter/ios-release`) + - Flutter (from `.symlinks/flutter/ios`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) EXTERNAL SOURCES: Flutter: - :path: ".symlinks/flutter/ios-release" + :path: ".symlinks/flutter/ios" flutter_secure_storage: :path: ".symlinks/plugins/flutter_secure_storage/ios" diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 8590272..3b9aebf 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -253,7 +253,7 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", - "${PODS_ROOT}/../.symlinks/flutter/ios-release/Flutter.framework", + "${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( diff --git a/lib/main.dart b/lib/main.dart index 898f434..4c84a88 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,8 +1,8 @@ import 'package:flutter/cupertino.dart'; import 'package:provider/provider.dart'; -import 'repositories/credentials_client.dart'; -import 'repositories/config.dart' as repo; +import 'repositories/grpc_credentials_client.dart'; +import 'repositories/secure_storage_config.dart'; import 'screens/authentication.dart'; import 'screens/credential.dart'; @@ -19,7 +19,7 @@ class Selfpass extends StatelessWidget { @override Widget build(BuildContext context) { return Provider( - builder: (BuildContext context) => repo.Config(), + builder: (BuildContext context) => SecureStorageConfig(), child: CupertinoApp( title: 'Selfpass', onGenerateRoute: (RouteSettings settings) { @@ -36,7 +36,7 @@ class Selfpass extends StatelessWidget { title = 'Hosts'; builder = (BuildContext context) => Provider( builder: (BuildContext context) => - CredentialsClient.cached(config: settings.arguments), + GRPCCredentialsClient.cached(config: settings.arguments), child: Home(), ); break; @@ -45,7 +45,7 @@ class Selfpass extends StatelessWidget { title = 'Credentials'; builder = (BuildContext context) => Provider( builder: (BuildContext context) => - CredentialsClient.cached(), + GRPCCredentialsClient.cached(), child: Credentials(settings.arguments), ); break; @@ -54,7 +54,7 @@ class Selfpass extends StatelessWidget { title = 'Credential'; builder = (BuildContext context) => Provider( builder: (BuildContext context) => - CredentialsClient.cached(), + GRPCCredentialsClient.cached(), child: Credential(settings.arguments), ); break; @@ -63,6 +63,7 @@ class Selfpass extends StatelessWidget { final ConfigScreenArguments arguments = settings.arguments == null ? ConfigScreenArguments() : settings.arguments; + title = 'Configuration'; builder = (BuildContext context) => Config(arguments.connectionConfig, arguments.privateKey); diff --git a/lib/repositories/credentials_client.dart b/lib/repositories/grpc_credentials_client.dart similarity index 87% rename from lib/repositories/credentials_client.dart rename to lib/repositories/grpc_credentials_client.dart index a51de43..df1811f 100644 --- a/lib/repositories/credentials_client.dart +++ b/lib/repositories/grpc_credentials_client.dart @@ -11,11 +11,11 @@ import '../types/abstracts.dart'; import '../types/connection_config.dart'; import '../types/credential.dart'; -class CredentialsClient implements CredentialsRepo { - static CredentialsClient _cached; +class GRPCCredentialsClient implements CredentialsRepo { + static GRPCCredentialsClient _cached; grpc.CredentialServiceClient _client; - CredentialsClient(ConnectionConfig config) { + GRPCCredentialsClient(ConnectionConfig config) { final caCert = utf8.encode(config.caCertificate); final cert = utf8.encode(config.certificate); final privateCert = utf8.encode(config.privateCertificate); @@ -33,8 +33,8 @@ class CredentialsClient implements CredentialsRepo { )); } - factory CredentialsClient.cached({ConnectionConfig config}) => - _cached == null ? _cached = CredentialsClient(config) : _cached; + factory GRPCCredentialsClient.cached({ConnectionConfig config}) => + config == null ? _cached : _cached = GRPCCredentialsClient(config); Stream getAllMetadata(String sourceHost) { final request = grpc.GetAllMetadataRequest(); diff --git a/lib/repositories/config.dart b/lib/repositories/secure_storage_config.dart similarity index 88% rename from lib/repositories/config.dart rename to lib/repositories/secure_storage_config.dart index 3da41df..9d9c4cf 100644 --- a/lib/repositories/config.dart +++ b/lib/repositories/secure_storage_config.dart @@ -7,11 +7,13 @@ import '../types/connection_config.dart'; import '../utils/crypto.dart' as crypto; -class Config implements ConfigRepo { +class SecureStorageConfig implements ConfigRepo { static const _keyPrivateKey = "private_key"; static const _keyConnectionConfig = "connection_config"; static const _keyPassword = "password"; - final FlutterSecureStorage _storage = FlutterSecureStorage(); + + final _storage = FlutterSecureStorage(); + bool _passwordMatched = false; String _password; @@ -32,13 +34,15 @@ class Config implements ConfigRepo { Future setPassword(String password) { _checkIfPasswordMatched(); + _password = password; + return _storage.write( key: _keyPassword, value: crypto.hashPassword(password)); } - Future get passwordSet async { - var passHash = await _storage.read(key: _keyPassword); + Future get passwordIsSet async { + final passHash = await _storage.read(key: _keyPassword); if (passHash != null) { return true; @@ -53,9 +57,7 @@ class Config implements ConfigRepo { _passwordMatched = crypto.matchHashedPassword( await _storage.read(key: _keyPassword), password); - if (_passwordMatched) { - _password = password; - } + if (_passwordMatched) _password = password; return _passwordMatched; } diff --git a/lib/screens/authentication.dart b/lib/screens/authentication.dart index caac43c..f2da82f 100644 --- a/lib/screens/authentication.dart +++ b/lib/screens/authentication.dart @@ -22,7 +22,7 @@ class _AuthenticationState extends State { didChangeDependencies() { super.didChangeDependencies(); _config = Provider.of(context); - _passwordIsSet = _config.passwordSet; + _passwordIsSet = _config.passwordIsSet; } @override diff --git a/lib/screens/home.dart b/lib/screens/home.dart index cdccbc2..ce528c3 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/cupertino.dart'; import 'package:provider/provider.dart'; @@ -8,32 +10,56 @@ import '../types/screen_arguments.dart'; import '../widgets/tappable_text_list.dart'; class Home extends StatefulWidget { + const Home({Key key}) : super(key: key); + @override State createState() => _HomeState(); } -class _HomeState extends State { +class _HomeState extends State with WidgetsBindingObserver { CredentialsRepo _client; ConfigRepo _config; Future> _metadatas; + bool _stateIsPaused = false; + Timer _pausedStateTimer; @override - didChangeDependencies() { + void initState() { + super.initState(); + WidgetsBinding.instance.addObserver(this); + } + + @override + void didChangeDependencies() { super.didChangeDependencies(); _config = Provider.of(context); - _client = Provider.of(context); + _metadatas = _client.getAllMetadata('').toList(); } + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + _stateIsPaused = state == AppLifecycleState.paused; + + if (_stateIsPaused) { + _pausedStateTimer = _newPausedStateTimer(); + return; + } + + if (_pausedStateTimer != null) _pausedStateTimer.cancel(); + } + @override Widget build(BuildContext context) { return CupertinoPageScaffold( child: FutureBuilder>( future: _metadatas, - builder: (BuildContext context, - AsyncSnapshot> snapshot) => + builder: ( + BuildContext context, + AsyncSnapshot> snapshot, + ) => (snapshot.connectionState == ConnectionState.done) ? TappableTextList( tappableText: _buildTappableText(context, snapshot.data)) @@ -55,6 +81,22 @@ class _HomeState extends State { ); } + @override + void dispose() { + WidgetsBinding.instance.removeObserver(this); + if (_pausedStateTimer != null) _pausedStateTimer.cancel(); + super.dispose(); + } + + Timer _newPausedStateTimer() { + const checkPeriod = 30; + + return Timer(Duration(seconds: checkPeriod), () { + Navigator.of(context) + .pushNamedAndRemoveUntil('/', ModalRoute.withName('/home')); + }); + } + Map _buildTappableText( BuildContext context, List metadatas, diff --git a/lib/types/abstracts.dart b/lib/types/abstracts.dart index bae8c75..b399efe 100644 --- a/lib/types/abstracts.dart +++ b/lib/types/abstracts.dart @@ -17,7 +17,7 @@ abstract class ConfigRepo { String get password; Future setPassword(String password); - Future get passwordSet; + Future get passwordIsSet; Future matchesPasswordHash(String password); Future setConnectionConfig(ConnectionConfig config); diff --git a/pubspec.lock b/pubspec.lock index af5081c..f46a501 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,13 +1,6 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: - _discoveryapis_commons: - dependency: transitive - description: - name: _discoveryapis_commons - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.8+1" args: dependency: transitive description: @@ -116,13 +109,6 @@ packages: description: flutter source: sdk version: "0.0.0" - googleapis: - dependency: "direct main" - description: - name: googleapis - url: "https://pub.dartlang.org" - source: hosted - version: "0.53.0" googleapis_auth: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index d3ef76f..b273453 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,7 +11,7 @@ description: The cross-platform Selfpass client. # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.0+1 +version: 0.1.0 environment: sdk: ">=2.1.0 <3.0.0" @@ -24,7 +24,6 @@ dependencies: grpc: ^1.0.3 protobuf: ^0.13.12 - googleapis: ^0.53.0 provider: ^3.0.0