From a6566ae383a7502884046dddfeb145b71ea8510e Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Tue, 14 Nov 2023 19:27:07 -0500 Subject: [PATCH] refactor: wrap all dart:io calls --- .../at_ssh_key_util/local_ssh_key_util.dart | 31 +++++++----- .../lib/src/common/default_args.dart | 3 +- .../lib/src/common/file_system_utils.dart | 2 +- .../noports_core/lib/src/common/io_types.dart | 23 +++++++++ .../lib/src/common/openssh_binary_path.dart | 2 +- .../lib/src/common/validation_utils.dart | 48 ++++++++++++------- .../sshnp/impl/sshnp_openssh_local_impl.dart | 23 ++++++++- .../src/sshnp/impl/sshnp_unsigned_impl.dart | 2 +- .../sshnp/models/config_file_repository.dart | 44 +++++++++++------ .../lib/src/sshnp/models/sshnp_result.dart | 3 +- .../lib/src/sshnp/sshnp_core.dart | 26 ---------- .../sshnp_dart_initial_tunnel_handler.dart | 5 +- .../sshnp_openssh_initial_tunnel_handler.dart | 2 +- .../src/sshnp/util/sshnp_ssh_key_handler.dart | 2 +- .../sshnpd_default_channel.dart | 11 ++--- packages/noports_core/pubspec.yaml | 1 + .../test/sshnp/sshnp_core_mocks.dart | 14 ------ .../test/sshnp/sshnp_core_test.dart | 10 ---- 18 files changed, 143 insertions(+), 109 deletions(-) create mode 100644 packages/noports_core/lib/src/common/io_types.dart diff --git a/packages/noports_core/lib/src/common/at_ssh_key_util/local_ssh_key_util.dart b/packages/noports_core/lib/src/common/at_ssh_key_util/local_ssh_key_util.dart index 3d6a96047..e17ba59aa 100644 --- a/packages/noports_core/lib/src/common/at_ssh_key_util/local_ssh_key_util.dart +++ b/packages/noports_core/lib/src/common/at_ssh_key_util/local_ssh_key_util.dart @@ -1,6 +1,7 @@ import 'dart:async'; -import 'dart:io'; +import 'package:meta/meta.dart'; +import 'package:noports_core/src/common/io_types.dart'; import 'package:noports_core/sshnp.dart'; import 'package:noports_core/utils.dart'; import 'package:path/path.dart' as path; @@ -14,10 +15,17 @@ class LocalSshKeyUtil implements AtSshKeyUtil { static final Map _keyPairCache = {}; + @visibleForTesting + final FileSystem fs; + final String homeDirectory; bool cacheKeys; - LocalSshKeyUtil({String? homeDirectory, this.cacheKeys = true}) - : homeDirectory = homeDirectory ?? getHomeDirectory(throwIfNull: true)!; + + LocalSshKeyUtil({ + String? homeDirectory, + this.cacheKeys = true, + @visibleForTesting this.fs = const LocalFileSystem(), + }) : homeDirectory = homeDirectory ?? getHomeDirectory(throwIfNull: true)!; bool get isValidPlatform => Platform.isLinux || Platform.isMacOS || Platform.isWindows; @@ -31,8 +39,8 @@ class LocalSshKeyUtil implements AtSshKeyUtil { List _filesFromIdentifier({required String identifier}) { return [ - File(path.normalize(identifier)), - File(path.normalize('$identifier.pub')), + fs.file(path.normalize(identifier)), + fs.file(path.normalize('$identifier.pub')), ]; } @@ -90,17 +98,18 @@ class LocalSshKeyUtil implements AtSshKeyUtil { SupportedSshAlgorithm algorithm = DefaultArgs.sshAlgorithm, String? directory, String? passphrase, + @visibleForTesting ProcessRunner processRunner = Process.run, }) async { String workingDirectory = directory ?? _defaultDirectory; - await Process.run( + await processRunner( 'ssh-keygen', [..._sshKeygenArgMap[algorithm]!, '-f', identifier, '-q', '-N', ''], workingDirectory: workingDirectory, ); String pemText = - await File(path.join(workingDirectory, identifier)).readAsString(); + await fs.file(path.join(workingDirectory, identifier)).readAsString(); return AtSshKeyPair.fromPem( pemText, @@ -122,13 +131,13 @@ class LocalSshKeyUtil implements AtSshKeyUtil { throw ('$sshPublicKey does not look like a public key'); } - if (!Directory(sshHomeDirectory).existsSync()) { - Directory(sshHomeDirectory).createSync(); + if (!fs.directory(sshHomeDirectory).existsSync()) { + fs.directory(sshHomeDirectory).createSync(); } // Check to see if the ssh Publickey is already in the authorized_keys file. // If not, then append it. - var authKeys = File(path.normalize('$sshHomeDirectory/authorized_keys')); + var authKeys = fs.file(path.normalize('$sshHomeDirectory/authorized_keys')); var authKeysContent = await authKeys.readAsString(); if (!authKeysContent.endsWith('\n')) { @@ -157,7 +166,7 @@ class LocalSshKeyUtil implements AtSshKeyUtil { Future deauthorizePublicKey(String sessionId) async { try { final File file = - File(path.normalize('$sshHomeDirectory/authorized_keys')); + fs.file(path.normalize('$sshHomeDirectory/authorized_keys')); // read into List of strings final List lines = await file.readAsLines(); // find the line we want to remove diff --git a/packages/noports_core/lib/src/common/default_args.dart b/packages/noports_core/lib/src/common/default_args.dart index 2cb6274f0..638097e10 100644 --- a/packages/noports_core/lib/src/common/default_args.dart +++ b/packages/noports_core/lib/src/common/default_args.dart @@ -1,5 +1,4 @@ -import 'dart:io'; - +import 'package:noports_core/src/common/io_types.dart'; import 'package:noports_core/src/common/types.dart'; import 'package:noports_core/sshrv.dart'; diff --git a/packages/noports_core/lib/src/common/file_system_utils.dart b/packages/noports_core/lib/src/common/file_system_utils.dart index ef069c889..bae31eb46 100644 --- a/packages/noports_core/lib/src/common/file_system_utils.dart +++ b/packages/noports_core/lib/src/common/file_system_utils.dart @@ -1,4 +1,4 @@ -import 'dart:io'; +import 'package:noports_core/src/common/io_types.dart'; import 'package:path/path.dart' as path; /// Get the home directory or null if unknown. diff --git a/packages/noports_core/lib/src/common/io_types.dart b/packages/noports_core/lib/src/common/io_types.dart new file mode 100644 index 000000000..79c9832d5 --- /dev/null +++ b/packages/noports_core/lib/src/common/io_types.dart @@ -0,0 +1,23 @@ +/// This file contains all of the dart:io calls in noports_core +/// All io used should be wrapped for the sake of testing and compatibilty +import 'dart:io' show Process, ProcessResult, ProcessStartMode; +import 'package:meta/meta.dart'; + +export 'dart:io' show Platform, Process, ProcessStartMode, ServerSocket, InternetAddress; +export 'package:file/file.dart'; +export 'package:file/local.dart' show LocalFileSystem; + +@internal +typedef ProcessRunner = Future Function( + String executable, + List arguments, { + String? workingDirectory, +}); + +@internal +typedef ProcessStarter = Future Function( + String executable, + List arguments, { + bool runInShell, + ProcessStartMode mode, +}); diff --git a/packages/noports_core/lib/src/common/openssh_binary_path.dart b/packages/noports_core/lib/src/common/openssh_binary_path.dart index afbeef643..0b6e40cf5 100644 --- a/packages/noports_core/lib/src/common/openssh_binary_path.dart +++ b/packages/noports_core/lib/src/common/openssh_binary_path.dart @@ -1,4 +1,4 @@ -import 'dart:io'; +import 'package:noports_core/src/common/io_types.dart'; const String _windowsOpensshPath = r'C:\Windows\System32\OpenSSH\ssh.exe'; const String _unixOpensshPath = '/usr/bin/ssh'; diff --git a/packages/noports_core/lib/src/common/validation_utils.dart b/packages/noports_core/lib/src/common/validation_utils.dart index 3d158d70b..3f1778ad9 100644 --- a/packages/noports_core/lib/src/common/validation_utils.dart +++ b/packages/noports_core/lib/src/common/validation_utils.dart @@ -1,9 +1,11 @@ import 'dart:convert'; -import 'dart:io'; + import 'package:at_chops/at_chops.dart'; import 'package:at_client/at_client.dart'; import 'package:at_utils/at_utils.dart'; + import 'package:noports_core/src/common/file_system_utils.dart'; +import 'package:noports_core/src/common/io_types.dart'; import 'package:path/path.dart' as path; const String sshnpDeviceNameRegex = r'[a-zA-Z0-9_]{0,15}'; @@ -66,15 +68,18 @@ String signAndWrapAndJsonEncode(AtClient atClient, Map payload) { return jsonEncode(envelope); } -Future verifyEnvelopeSignature(AtClient atClient, String requestingAtsign, - AtSignLogger logger, Map envelope, - {bool useFileStorage = true}) async { +Future verifyEnvelopeSignature( + AtClient atClient, + String requestingAtsign, + AtSignLogger logger, + Map envelope, { + FileSystem? fs, +}) async { final String signature = envelope['signature']; Map payload = envelope['payload']; final hashingAlgo = HashingAlgoType.values.byName(envelope['hashingAlgo']); final signingAlgo = SigningAlgoType.values.byName(envelope['signingAlgo']); - final pk = await getLocallyCachedPK(atClient, requestingAtsign, - useFileStorage: useFileStorage); + final pk = await getLocallyCachedPK(atClient, requestingAtsign, fs: fs); AtSigningVerificationInput input = AtSigningVerificationInput( jsonEncode(payload), base64Decode(signature), pk) ..signingMode = AtSigningMode.data @@ -101,12 +106,14 @@ Future verifyEnvelopeSignature(AtClient atClient, String requestingAtsign, /// `~/.atsign/sshnp/cached_pks/alice` /// /// Note that for storage, the leading `@` in the atSign is stripped off. -Future getLocallyCachedPK(AtClient atClient, String atSign, - {bool useFileStorage = true}) async { +Future getLocallyCachedPK( + AtClient atClient, + String atSign, { + FileSystem? fs, +}) async { atSign = AtUtils.fixAtSign(atSign); - String? cachedPK = - await _fetchFromLocalPKCache(atClient, atSign, useFileStorage); + String? cachedPK = await _fetchFromLocalPKCache(atClient, atSign, fs: fs); if (cachedPK != null) { return cachedPK; } @@ -117,18 +124,21 @@ Future getLocallyCachedPK(AtClient atClient, String atSign, throw AtPublicKeyNotFoundException('Failed to retrieve $s'); } - await _storeToLocalPKCache(av.value, atClient, atSign, useFileStorage); + await _storeToLocalPKCache(av.value, atClient, atSign, fs: fs); return av.value; } Future _fetchFromLocalPKCache( - AtClient atClient, String atSign, bool useFileStorage) async { + AtClient atClient, + String atSign, { + FileSystem? fs, +}) async { String dontAtMe = atSign.substring(1); - if (useFileStorage) { + if (fs != null) { String fn = path .normalize('${getHomeDirectory()}/.atsign/sshnp/cached_pks/$dontAtMe'); - File f = File(fn); + File f = fs.file(fn); if (await f.exists()) { return (await f.readAsString()).trim(); } else { @@ -147,14 +157,18 @@ Future _fetchFromLocalPKCache( } Future _storeToLocalPKCache( - String pk, AtClient atClient, String atSign, bool useFileStorage) async { + String pk, + AtClient atClient, + String atSign, { + FileSystem? fs, +}) async { String dontAtMe = atSign.substring(1); - if (useFileStorage) { + if (fs != null) { String dirName = path.normalize('${getHomeDirectory()}/.atsign/sshnp/cached_pks'); String fileName = path.normalize('$dirName/$dontAtMe'); - File f = File(fileName); + File f = fs.file(fileName); if (!await f.exists()) { await f.create(recursive: true); await Process.run('chmod', ['-R', 'go-rwx', dirName]); diff --git a/packages/noports_core/lib/src/sshnp/impl/sshnp_openssh_local_impl.dart b/packages/noports_core/lib/src/sshnp/impl/sshnp_openssh_local_impl.dart index 6fc9cec05..408fe3c14 100644 --- a/packages/noports_core/lib/src/sshnp/impl/sshnp_openssh_local_impl.dart +++ b/packages/noports_core/lib/src/sshnp/impl/sshnp_openssh_local_impl.dart @@ -1,7 +1,8 @@ import 'dart:async'; -import 'dart:io'; import 'package:at_client/at_client.dart'; +import 'package:meta/meta.dart'; +import 'package:noports_core/src/common/io_types.dart'; import 'package:noports_core/sshnp_foundation.dart'; class SshnpOpensshLocalImpl extends SshnpCore @@ -34,10 +35,30 @@ class SshnpOpensshLocalImpl extends SshnpCore @override Future initialize() async { if (!isSafeToInitialize) return; + await findLocalPortIfRequired(); await super.initialize(); completeInitialization(); } + @visibleForTesting + Future findLocalPortIfRequired() async { + // find a spare local port + if (localPort == 0) { + logger.info('Finding a spare local port'); + try { + ServerSocket serverSocket = + await ServerSocket.bind(InternetAddress.loopbackIPv4, 0) + .catchError((e) => throw e); + localPort = serverSocket.port; + await serverSocket.close().catchError((e) => throw e); + } catch (e, s) { + logger.info('Unable to find a spare local port'); + throw SshnpError('Unable to find a spare local port', + error: e, stackTrace: s); + } + } + } + @override Future run() async { /// Ensure that sshnp is initialized diff --git a/packages/noports_core/lib/src/sshnp/impl/sshnp_unsigned_impl.dart b/packages/noports_core/lib/src/sshnp/impl/sshnp_unsigned_impl.dart index eee677c53..8fa0ae53b 100644 --- a/packages/noports_core/lib/src/sshnp/impl/sshnp_unsigned_impl.dart +++ b/packages/noports_core/lib/src/sshnp/impl/sshnp_unsigned_impl.dart @@ -1,7 +1,7 @@ import 'dart:async'; -import 'dart:io'; import 'package:at_client/at_client.dart'; +import 'package:noports_core/src/common/io_types.dart'; import 'package:noports_core/sshnp_foundation.dart'; class SshnpUnsignedImpl extends SshnpCore with SshnpLocalSshKeyHandler { diff --git a/packages/noports_core/lib/src/sshnp/models/config_file_repository.dart b/packages/noports_core/lib/src/sshnp/models/config_file_repository.dart index 09b3fda41..6bcf1de56 100644 --- a/packages/noports_core/lib/src/sshnp/models/config_file_repository.dart +++ b/packages/noports_core/lib/src/sshnp/models/config_file_repository.dart @@ -1,6 +1,6 @@ -import 'dart:io'; - +import 'package:meta/meta.dart'; import 'package:noports_core/src/common/file_system_utils.dart'; +import 'package:noports_core/src/common/io_types.dart'; import 'package:noports_core/src/sshnp/models/sshnp_params.dart'; import 'package:noports_core/src/sshnp/models/sshnp_arg.dart'; import 'package:path/path.dart' as path; @@ -30,19 +30,25 @@ class ConfigFileRepository { ); } - static Future createConfigDirectory({String? directory}) async { + static Future createConfigDirectory({ + String? directory, + @visibleForTesting FileSystem fs = const LocalFileSystem(), + }) async { directory ??= getDefaultSshnpConfigDirectory(getHomeDirectory()!); - var dir = Directory(directory); + var dir = fs.directory(directory); if (!await dir.exists()) { await dir.create(recursive: true); } return dir; } - static Future> listProfiles({String? directory}) async { + static Future> listProfiles({ + String? directory, + @visibleForTesting FileSystem fs = const LocalFileSystem(), + }) async { var profileNames = {}; directory ??= getDefaultSshnpConfigDirectory(getHomeDirectory()!); - var files = Directory(directory).list(); + var files = fs.directory(directory).list(); await files.forEach((file) { if (file is! File) return; @@ -62,15 +68,19 @@ class ConfigFileRepository { return SshnpParams.fromFile(fileName); } - static Future putParams(SshnpParams params, - {String? directory, bool overwrite = false}) async { + static Future putParams( + SshnpParams params, { + String? directory, + bool overwrite = false, + @visibleForTesting FileSystem fs = const LocalFileSystem(), + }) async { if (params.profileName == null || params.profileName!.isEmpty) { throw Exception('profileName is null or empty'); } var fileName = await fromProfileName(params.profileName!, directory: directory); - var file = File(fileName); + var file = fs.file(fileName); var exists = await file.exists(); @@ -87,15 +97,18 @@ class ConfigFileRepository { ); } - static Future deleteParams(SshnpParams params, - {String? directory}) async { + static Future deleteParams( + SshnpParams params, { + String? directory, + @visibleForTesting FileSystem fs = const LocalFileSystem(), + }) async { if (params.profileName == null || params.profileName!.isEmpty) { throw Exception('profileName is null or empty'); } var fileName = await fromProfileName(params.profileName!, directory: directory); - var file = File(fileName); + var file = fs.file(fileName); var exists = await file.exists(); @@ -106,8 +119,11 @@ class ConfigFileRepository { return file.delete(); } - static Map parseConfigFile(String fileName) { - File file = File(fileName); + static Map parseConfigFile( + String fileName, { + @visibleForTesting FileSystem fs = const LocalFileSystem(), + }) { + File file = fs.file(fileName); if (!file.existsSync()) { throw Exception('Config file does not exist: $fileName'); diff --git a/packages/noports_core/lib/src/sshnp/models/sshnp_result.dart b/packages/noports_core/lib/src/sshnp/models/sshnp_result.dart index c07a6d87f..6a4147631 100644 --- a/packages/noports_core/lib/src/sshnp/models/sshnp_result.dart +++ b/packages/noports_core/lib/src/sshnp/models/sshnp_result.dart @@ -1,6 +1,5 @@ -import 'dart:io'; - import 'package:meta/meta.dart'; +import 'package:noports_core/src/common/io_types.dart'; import 'package:socket_connector/socket_connector.dart'; abstract class SshnpResult {} diff --git a/packages/noports_core/lib/src/sshnp/sshnp_core.dart b/packages/noports_core/lib/src/sshnp/sshnp_core.dart index 3ece92d13..9aa18be62 100644 --- a/packages/noports_core/lib/src/sshnp/sshnp_core.dart +++ b/packages/noports_core/lib/src/sshnp/sshnp_core.dart @@ -1,9 +1,6 @@ import 'dart:async'; -import 'dart:io'; - import 'package:at_client/at_client.dart' hide StringBuffer; - import 'package:at_utils/at_logger.dart'; import 'package:meta/meta.dart'; import 'package:noports_core/src/common/mixins/async_completion.dart'; @@ -86,9 +83,6 @@ abstract class SshnpCore /// Set the remote username to use for the ssh session remoteUsername = await sshnpdChannel.resolveRemoteUsername(); - /// Find a spare local port if required - await findLocalPortIfRequired(); - /// Shares the public key if required await sshnpdChannel.sharePublicKeyIfRequired(identityKeyPair); @@ -101,26 +95,6 @@ abstract class SshnpCore completeDisposal(); } - @visibleForTesting - Future findLocalPortIfRequired() async { - // TODO investigate if this is a problem on mobile - // find a spare local port - if (localPort == 0) { - logger.info('Finding a spare local port'); - try { - ServerSocket serverSocket = - await ServerSocket.bind(InternetAddress.loopbackIPv4, 0) - .catchError((e) => throw e); - localPort = serverSocket.port; - await serverSocket.close().catchError((e) => throw e); - } catch (e, s) { - logger.info('Unable to find a spare local port'); - throw SshnpError('Unable to find a spare local port', - error: e, stackTrace: s); - } - } - } - @override Future listDevices() => sshnpdChannel.listDevices(); } diff --git a/packages/noports_core/lib/src/sshnp/util/sshnp_initial_tunnel_handler/sshnp_dart_initial_tunnel_handler.dart b/packages/noports_core/lib/src/sshnp/util/sshnp_initial_tunnel_handler/sshnp_dart_initial_tunnel_handler.dart index f163bffbc..efb6c59f2 100644 --- a/packages/noports_core/lib/src/sshnp/util/sshnp_initial_tunnel_handler/sshnp_dart_initial_tunnel_handler.dart +++ b/packages/noports_core/lib/src/sshnp/util/sshnp_initial_tunnel_handler/sshnp_dart_initial_tunnel_handler.dart @@ -1,5 +1,7 @@ import 'dart:async'; -import 'dart:io'; +// Current implementation uses ServerSocket, which will be replaced with an +// internal Dart stream at a later time +import 'dart:io' show ServerSocket; import 'package:dartssh2/dartssh2.dart'; import 'package:meta/meta.dart'; @@ -73,6 +75,7 @@ mixin SshnpDartInitialTunnelHandler on SshnpCore ' from localhost:$fLocalPort on local side' ' to $fRemoteHost:$fRemotePort on remote side'); + // TODO remove local dependency on ServerSockets /// Do the port forwarding for sshd final serverSocket = await ServerSocket.bind('localhost', fLocalPort); diff --git a/packages/noports_core/lib/src/sshnp/util/sshnp_initial_tunnel_handler/sshnp_openssh_initial_tunnel_handler.dart b/packages/noports_core/lib/src/sshnp/util/sshnp_initial_tunnel_handler/sshnp_openssh_initial_tunnel_handler.dart index f165efa52..f2db21d15 100644 --- a/packages/noports_core/lib/src/sshnp/util/sshnp_initial_tunnel_handler/sshnp_openssh_initial_tunnel_handler.dart +++ b/packages/noports_core/lib/src/sshnp/util/sshnp_initial_tunnel_handler/sshnp_openssh_initial_tunnel_handler.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:io'; +import 'package:noports_core/src/common/io_types.dart'; import 'package:noports_core/src/common/openssh_binary_path.dart'; import 'package:noports_core/sshnp_foundation.dart'; diff --git a/packages/noports_core/lib/src/sshnp/util/sshnp_ssh_key_handler.dart b/packages/noports_core/lib/src/sshnp/util/sshnp_ssh_key_handler.dart index 8c91f3679..6f0e2c1b2 100644 --- a/packages/noports_core/lib/src/sshnp/util/sshnp_ssh_key_handler.dart +++ b/packages/noports_core/lib/src/sshnp/util/sshnp_ssh_key_handler.dart @@ -1,7 +1,7 @@ import 'dart:async'; -import 'dart:io'; import 'package:meta/meta.dart'; +import 'package:noports_core/src/common/io_types.dart'; import 'package:noports_core/src/sshnp/sshnp_core.dart'; import 'package:noports_core/src/sshnp/models/sshnp_result.dart'; import 'package:noports_core/utils.dart'; diff --git a/packages/noports_core/lib/src/sshnp/util/sshnpd_channel/sshnpd_default_channel.dart b/packages/noports_core/lib/src/sshnp/util/sshnpd_channel/sshnpd_default_channel.dart index ddca8cb75..19f6ef8ac 100644 --- a/packages/noports_core/lib/src/sshnp/util/sshnpd_channel/sshnpd_default_channel.dart +++ b/packages/noports_core/lib/src/sshnp/util/sshnpd_channel/sshnpd_default_channel.dart @@ -1,10 +1,9 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:io'; import 'package:at_client/at_client.dart'; import 'package:meta/meta.dart'; -import 'package:noports_core/src/sshnp/util/sshnp_ssh_key_handler.dart'; +import 'package:noports_core/src/common/io_types.dart'; import 'package:noports_core/src/sshnp/util/sshnpd_channel/sshnpd_channel.dart'; import 'package:noports_core/utils.dart'; @@ -21,8 +20,9 @@ class SshnpdDefaultChannel extends SshnpdChannel mixin SshnpdDefaultPayloadHandler on SshnpdChannel { late final String ephemeralPrivateKey; - @protected - bool get useLocalFileStorage => (this is SshnpLocalSshKeyHandler); + @visibleForTesting + // disable publickey cache on windows + FileSystem? fs = Platform.isWindows ? null : LocalFileSystem(); @override Future initialize() async { @@ -56,8 +56,7 @@ mixin SshnpdDefaultPayloadHandler on SshnpdChannel { params.sshnpdAtSign, logger, envelope, - useFileStorage: useLocalFileStorage && - !Platform.isWindows, // disable publickey cache on windows + fs: fs, ); } catch (e) { logger.shout( diff --git a/packages/noports_core/pubspec.yaml b/packages/noports_core/pubspec.yaml index 690703155..013069753 100644 --- a/packages/noports_core/pubspec.yaml +++ b/packages/noports_core/pubspec.yaml @@ -15,6 +15,7 @@ dependencies: at_utils: ^3.0.15 cryptography: ^2.7.0 dartssh2: ^2.8.2 + file: ^6.0.0 logging: ^1.2.0 meta: ^1.9.1 openssh_ed25519: ^1.1.0 diff --git a/packages/noports_core/test/sshnp/sshnp_core_mocks.dart b/packages/noports_core/test/sshnp/sshnp_core_mocks.dart index 75377aaae..c9b9a211c 100644 --- a/packages/noports_core/test/sshnp/sshnp_core_mocks.dart +++ b/packages/noports_core/test/sshnp/sshnp_core_mocks.dart @@ -22,14 +22,6 @@ class MockSshrvdChannel extends Mock implements SshrvdChannel {} /// Stubbed [SshnpCore] (minimum viable implementation of [SshnpCore]) class StubbedSshnpCore extends SshnpCore with StubbedAsyncInitializationMixin { - FunctionStub? _stubbedFindLocalPortIfRequired; - - void stubFindLocalPortIfRequired( - FunctionStub stubbedFindLocalPortIfRequired, - ) { - _stubbedFindLocalPortIfRequired = stubbedFindLocalPortIfRequired; - } - StubbedSshnpCore({ required super.atClient, required super.params, @@ -64,12 +56,6 @@ class StubbedSshnpCore extends SshnpCore with StubbedAsyncInitializationMixin { SshrvdChannel get sshrvdChannel => _sshrvdChannel ?? (throw UnimplementedError()); final SshrvdChannel? _sshrvdChannel; - - @override - Future findLocalPortIfRequired() { - _stubbedFindLocalPortIfRequired?.call(); - return super.findLocalPortIfRequired(); - } } /// Stubbed mixin wrapper diff --git a/packages/noports_core/test/sshnp/sshnp_core_test.dart b/packages/noports_core/test/sshnp/sshnp_core_test.dart index 40cc4ef3f..744528414 100644 --- a/packages/noports_core/test/sshnp/sshnp_core_test.dart +++ b/packages/noports_core/test/sshnp/sshnp_core_test.dart @@ -19,7 +19,6 @@ void main() { late FunctionStub stubbedCallInitialization; late FunctionStub stubbedInitialize; late FunctionStub stubbedCompleteInitialization; - late FunctionStub stubbedFindLocalPortIfRequired; setUp(() { /// Creation @@ -33,7 +32,6 @@ void main() { stubbedCallInitialization = FunctionStub(); stubbedInitialize = FunctionStub(); stubbedCompleteInitialization = FunctionStub(); - stubbedFindLocalPortIfRequired = FunctionStub(); }); /// When declaration setup for the constructor of [StubbedSshnpCore] @@ -50,7 +48,6 @@ void main() { when(() => stubbedCallInitialization.call()).thenAnswer((_) async {}); when(() => stubbedInitialize.call()).thenAnswer((_) async {}); when(() => stubbedCompleteInitialization.call()).thenReturn(null); - when(() => stubbedFindLocalPortIfRequired.call()).thenReturn(null); when(() => mockSshnpdChannel.callInitialization()) .thenAnswer((_) async {}); @@ -115,15 +112,11 @@ void main() { mockInitialize: stubbedInitialize, ); - /// Setup stub for [SshnpCore.findLocalPortIfRequired()] - sshnpCore.stubFindLocalPortIfRequired(stubbedFindLocalPortIfRequired); - whenInitialization(identityKeyPair: sshnpCore.identityKeyPair); verifyNever(() => stubbedCallInitialization.call()); verifyNever(() => stubbedInitialize.call()); verifyNever(() => stubbedCompleteInitialization.call()); - verifyNever(() => stubbedFindLocalPortIfRequired.call()); await expectLater(sshnpCore.callInitialization(), completes); @@ -135,7 +128,6 @@ void main() { () => stubbedInitialize.call(), () => mockSshnpdChannel.callInitialization(), () => mockSshnpdChannel.resolveRemoteUsername(), - () => stubbedFindLocalPortIfRequired.call(), () => mockSshnpdChannel .sharePublicKeyIfRequired(sshnpCore.identityKeyPair), () => mockSshrvdChannel.callInitialization(), @@ -147,7 +139,6 @@ void main() { verifyNever(() => stubbedInitialize.call()); verifyNever(() => mockSshnpdChannel.callInitialization()); verifyNever(() => mockSshnpdChannel.resolveRemoteUsername()); - verifyNever(() => stubbedFindLocalPortIfRequired.call()); verifyNever(() => mockSshnpdChannel .sharePublicKeyIfRequired(sshnpCore.identityKeyPair)); verifyNever(() => mockSshrvdChannel.callInitialization()); @@ -159,7 +150,6 @@ void main() { verify(() => stubbedCallInitialization.call()).called(1); verifyNever(() => stubbedInitialize.call()); verifyNever(() => stubbedCompleteInitialization.call()); - verifyNever(() => stubbedFindLocalPortIfRequired.call()); verifyNever(() => mockSshrvdChannel.callInitialization()); }); }); // group Initialization