From ac5cfb4d977afb98fc610470ed9a097ca8f6004a Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Mon, 6 Nov 2023 16:38:17 -0500 Subject: [PATCH 01/11] fix: disable public key caching on Windows --- .../src/sshnp/util/sshnpd_channel/sshnpd_default_channel.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 be7ef3dca..ddca8cb75 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,5 +1,6 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:io'; import 'package:at_client/at_client.dart'; import 'package:meta/meta.dart'; @@ -55,7 +56,8 @@ mixin SshnpdDefaultPayloadHandler on SshnpdChannel { params.sshnpdAtSign, logger, envelope, - useFileStorage: useLocalFileStorage, + useFileStorage: useLocalFileStorage && + !Platform.isWindows, // disable publickey cache on windows ); } catch (e) { logger.shout( From d0a80e10d1c8d6ef1437913091a07da1aa2a47f8 Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Mon, 6 Nov 2023 16:42:22 -0500 Subject: [PATCH 02/11] fix: disable chmod call on key files in Windows --- .../lib/src/common/at_ssh_key_util/local_ssh_key_util.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 04562b4ee..3d6a96047 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 @@ -47,8 +47,10 @@ class LocalSshKeyUtil implements AtSshKeyUtil { files[1].writeAsString(keyPair.publicKeyContents), ]).catchError((e) => throw e); - chmod(files[0].path, '600'); - chmod(files[1].path, '644'); + if (!Platform.isWindows) { + chmod(files[0].path, '600'); + chmod(files[1].path, '644'); + } return files; } From 47896ec0530f9c139cb5936a2781f1d74ea48ca3 Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Mon, 6 Nov 2023 16:51:18 -0500 Subject: [PATCH 03/11] fix: disable reverse clients on Windows --- .../lib/src/sshnp/impl/sshnp_unsigned_impl.dart | 6 ++++++ 1 file changed, 6 insertions(+) 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 a47f56839..eee677c53 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,4 +1,5 @@ import 'dart:async'; +import 'dart:io'; import 'package:at_client/at_client.dart'; import 'package:noports_core/sshnp_foundation.dart'; @@ -8,6 +9,11 @@ class SshnpUnsignedImpl extends SshnpCore with SshnpLocalSshKeyHandler { required super.atClient, required super.params, }) { + if (Platform.isWindows) { + throw SshnpError( + 'Windows is not supported by unsigned sshnp clients.', + ); + } _sshnpdChannel = SshnpdUnsignedChannel( atClient: atClient, params: params, From 722b85c08bb19e1f8ddda9fff4f362bee0d25f96 Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Mon, 6 Nov 2023 17:07:11 -0500 Subject: [PATCH 04/11] refactor: rename exec stuff to openssh --- .../lib/src/common/default_args.dart | 4 +- .../noports_core/lib/src/common/types.dart | 4 +- ...mpl.dart => sshnp_openssh_local_impl.dart} | 6 +- .../noports_core/lib/src/sshnp/sshnp.dart | 6 +- .../sshnp_dart_initial_tunnel_handler.dart} | 65 +----------------- .../sshnp_initial_tunnel_handler.dart | 7 ++ .../sshnp_openssh_initial_tunnel_handler.dart | 66 +++++++++++++++++++ .../lib/src/sshnpd/sshnpd_impl.dart | 2 +- .../noports_core/lib/sshnp_foundation.dart | 7 +- packages/sshnoports/lib/sshnp.dart | 4 +- 10 files changed, 92 insertions(+), 79 deletions(-) rename packages/noports_core/lib/src/sshnp/impl/{sshnp_exec_local_impl.dart => sshnp_openssh_local_impl.dart} (95%) rename packages/noports_core/lib/src/sshnp/util/{sshnp_initial_tunnel_handler.dart => sshnp_initial_tunnel_handler/sshnp_dart_initial_tunnel_handler.dart} (71%) create mode 100644 packages/noports_core/lib/src/sshnp/util/sshnp_initial_tunnel_handler/sshnp_initial_tunnel_handler.dart create mode 100644 packages/noports_core/lib/src/sshnp/util/sshnp_initial_tunnel_handler/sshnp_openssh_initial_tunnel_handler.dart diff --git a/packages/noports_core/lib/src/common/default_args.dart b/packages/noports_core/lib/src/common/default_args.dart index cdde95e34..2cb6274f0 100644 --- a/packages/noports_core/lib/src/common/default_args.dart +++ b/packages/noports_core/lib/src/common/default_args.dart @@ -29,9 +29,9 @@ class DefaultSshnpArgs { static const List localSshOptions = []; static const bool legacyDaemon = false; static const bool listDevices = false; - static const SupportedSshClient sshClient = SupportedSshClient.exec; + static const SupportedSshClient sshClient = SupportedSshClient.openssh; } class DefaultSshnpdArgs { - static const SupportedSshClient sshClient = SupportedSshClient.exec; + static const SupportedSshClient sshClient = SupportedSshClient.openssh; } diff --git a/packages/noports_core/lib/src/common/types.dart b/packages/noports_core/lib/src/common/types.dart index 49f770e7c..8137d48b5 100644 --- a/packages/noports_core/lib/src/common/types.dart +++ b/packages/noports_core/lib/src/common/types.dart @@ -3,7 +3,7 @@ import 'package:noports_core/sshrv.dart'; typedef SshrvGenerator = Sshrv Function(String, int, {int localSshdPort}); enum SupportedSshClient { - exec(cliArg: '/usr/bin/ssh'), + openssh(cliArg: 'openssh'), dart(cliArg: 'dart'); final String _cliArg; @@ -11,7 +11,7 @@ enum SupportedSshClient { factory SupportedSshClient.fromString(String cliArg) { return SupportedSshClient.values.firstWhere( - (arg) => arg._cliArg == cliArg, + (arg) => arg._cliArg == cliArg.toLowerCase(), orElse: () => throw ArgumentError('Unsupported SSH client: $cliArg'), ); } diff --git a/packages/noports_core/lib/src/sshnp/impl/sshnp_exec_local_impl.dart b/packages/noports_core/lib/src/sshnp/impl/sshnp_openssh_local_impl.dart similarity index 95% rename from packages/noports_core/lib/src/sshnp/impl/sshnp_exec_local_impl.dart rename to packages/noports_core/lib/src/sshnp/impl/sshnp_openssh_local_impl.dart index 68b96440a..b6b09e1fd 100644 --- a/packages/noports_core/lib/src/sshnp/impl/sshnp_exec_local_impl.dart +++ b/packages/noports_core/lib/src/sshnp/impl/sshnp_openssh_local_impl.dart @@ -4,9 +4,9 @@ import 'dart:io'; import 'package:at_client/at_client.dart'; import 'package:noports_core/sshnp_foundation.dart'; -class SshnpExecLocalImpl extends SshnpCore - with SshnpLocalSshKeyHandler, SshnpExecInitialTunnelHandler { - SshnpExecLocalImpl({ +class SshnpOpensshLocalImpl extends SshnpCore + with SshnpLocalSshKeyHandler, SshnpOpensshInitialTunnelHandler { + SshnpOpensshLocalImpl({ required super.atClient, required super.params, }) { diff --git a/packages/noports_core/lib/src/sshnp/sshnp.dart b/packages/noports_core/lib/src/sshnp/sshnp.dart index 304b80358..b80ce9ef0 100644 --- a/packages/noports_core/lib/src/sshnp/sshnp.dart +++ b/packages/noports_core/lib/src/sshnp/sshnp.dart @@ -12,12 +12,12 @@ abstract interface class Sshnp { return SshnpUnsignedImpl(atClient: atClient, params: params); } - /// Think of this as the "default" client - calls /usr/bin/ssh - factory Sshnp.execLocal({ + /// Think of this as the "default" client - calls openssh + factory Sshnp.openssh({ required AtClient atClient, required SshnpParams params, }) { - return SshnpExecLocalImpl(atClient: atClient, params: params); + return SshnpOpensshLocalImpl(atClient: atClient, params: params); } /// Uses a dartssh2 ssh client - still expects local ssh keys diff --git a/packages/noports_core/lib/src/sshnp/util/sshnp_initial_tunnel_handler.dart b/packages/noports_core/lib/src/sshnp/util/sshnp_initial_tunnel_handler/sshnp_dart_initial_tunnel_handler.dart similarity index 71% rename from packages/noports_core/lib/src/sshnp/util/sshnp_initial_tunnel_handler.dart rename to packages/noports_core/lib/src/sshnp/util/sshnp_initial_tunnel_handler/sshnp_dart_initial_tunnel_handler.dart index a1cd7e4ec..b8f40c9ba 100644 --- a/packages/noports_core/lib/src/sshnp/util/sshnp_initial_tunnel_handler.dart +++ b/packages/noports_core/lib/src/sshnp/util/sshnp_initial_tunnel_handler/sshnp_dart_initial_tunnel_handler.dart @@ -1,72 +1,9 @@ import 'dart:async'; -import 'dart:convert'; import 'dart:io'; import 'package:dartssh2/dartssh2.dart'; import 'package:meta/meta.dart'; -import 'package:noports_core/src/sshnp/sshnp_core.dart'; -import 'package:noports_core/sshnp.dart'; -import 'package:noports_core/utils.dart'; - -mixin SshnpInitialTunnelHandler { - @protected - Future startInitialTunnel({required String identifier}); -} - -mixin SshnpExecInitialTunnelHandler on SshnpCore - implements SshnpInitialTunnelHandler { - @override - Future startInitialTunnel({required String identifier}) async { - Process? process; - // If we are starting an initial tunnel, it should be to sshrvd, - // so it is safe to assume that sshrvdChannel is not null here - String argsString = '$remoteUsername@${sshrvdChannel!.host}' - ' -p ${sshrvdChannel!.sshrvdPort}' - ' -i $identifier' - ' -L $localPort:localhost:${params.remoteSshdPort}' - ' -o LogLevel=VERBOSE' - ' -t -t' - ' -o StrictHostKeyChecking=accept-new' - ' -o IdentitiesOnly=yes' - ' -o BatchMode=yes' - ' -o ExitOnForwardFailure=yes' - ' -n' - ' -f' // fork after authentication - this is important - ; - if (params.addForwardsToTunnel) { - argsString += ' ${params.localSshOptions.join(' ')}'; - } - argsString += ' sleep 15'; - - List args = argsString.split(' '); - - logger.info('$sessionId | Executing /usr/bin/ssh ${args.join(' ')}'); - - // Because of the options we are using, we can wait for this process - // to complete, because it will exit with exitCode 0 once it has connected - // successfully - final soutBuf = StringBuffer(); - final serrBuf = StringBuffer(); - try { - process = await Process.start('/usr/bin/ssh', args); - process.stdout.transform(Utf8Decoder()).listen((String s) { - soutBuf.write(s); - logger.info(' $sessionId | sshStdOut | $s'); - }, onError: (e) {}); - process.stderr.transform(Utf8Decoder()).listen((String s) { - serrBuf.write(s); - logger.info(' $sessionId | sshStdErr | $s'); - }, onError: (e) {}); - await process.exitCode.timeout(Duration(seconds: 10)); - } on TimeoutException catch (e) { - throw SshnpError( - 'ssh process timed out after 10 seconds', - error: e, - ); - } - return process; - } -} +import 'package:noports_core/sshnp_foundation.dart'; mixin SshnpDartInitialTunnelHandler on SshnpCore implements SshnpInitialTunnelHandler { diff --git a/packages/noports_core/lib/src/sshnp/util/sshnp_initial_tunnel_handler/sshnp_initial_tunnel_handler.dart b/packages/noports_core/lib/src/sshnp/util/sshnp_initial_tunnel_handler/sshnp_initial_tunnel_handler.dart new file mode 100644 index 000000000..c100e9632 --- /dev/null +++ b/packages/noports_core/lib/src/sshnp/util/sshnp_initial_tunnel_handler/sshnp_initial_tunnel_handler.dart @@ -0,0 +1,7 @@ +import 'dart:async'; +import 'package:meta/meta.dart'; + +mixin SshnpInitialTunnelHandler { + @protected + Future startInitialTunnel({required String identifier}); +} 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 new file mode 100644 index 000000000..b4193c371 --- /dev/null +++ b/packages/noports_core/lib/src/sshnp/util/sshnp_initial_tunnel_handler/sshnp_openssh_initial_tunnel_handler.dart @@ -0,0 +1,66 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:noports_core/sshnp_foundation.dart'; + +const String _windowsOpensshPath = r'C:\Windows\System32\OpenSSH\ssh.exe'; +const String _unixOpensshPath = '/usr/bin/ssh'; + +mixin SshnpOpensshInitialTunnelHandler on SshnpCore + implements SshnpInitialTunnelHandler { + String get opensshBinaryPath => + Platform.isWindows ? _windowsOpensshPath : _unixOpensshPath; + + @override + Future startInitialTunnel({required String identifier}) async { + Process? process; + // If we are starting an initial tunnel, it should be to sshrvd, + // so it is safe to assume that sshrvdChannel is not null here + String argsString = '$remoteUsername@${sshrvdChannel!.host}' + ' -p ${sshrvdChannel!.sshrvdPort}' + ' -i $identifier' + ' -L $localPort:localhost:${params.remoteSshdPort}' + ' -o LogLevel=VERBOSE' + ' -t -t' + ' -o StrictHostKeyChecking=accept-new' + ' -o IdentitiesOnly=yes' + ' -o BatchMode=yes' + ' -o ExitOnForwardFailure=yes' + ' -n' + ' -f' // fork after authentication - this is important + ; + if (params.addForwardsToTunnel) { + argsString += ' ${params.localSshOptions.join(' ')}'; + } + argsString += ' sleep 15'; + + List args = argsString.split(' '); + + logger.info('$sessionId | Executing $opensshBinaryPath ${args.join(' ')}'); + + // Because of the options we are using, we can wait for this process + // to complete, because it will exit with exitCode 0 once it has connected + // successfully + final soutBuf = StringBuffer(); + final serrBuf = StringBuffer(); + try { + process = await Process.start(opensshBinaryPath, args); + process.stdout.transform(Utf8Decoder()).listen((String s) { + soutBuf.write(s); + logger.info(' $sessionId | sshStdOut | $s'); + }, onError: (e) {}); + process.stderr.transform(Utf8Decoder()).listen((String s) { + serrBuf.write(s); + logger.info(' $sessionId | sshStdErr | $s'); + }, onError: (e) {}); + await process.exitCode.timeout(Duration(seconds: 10)); + } on TimeoutException catch (e) { + throw SshnpError( + 'ssh process timed out after 10 seconds', + error: e, + ); + } + return process; + } +} diff --git a/packages/noports_core/lib/src/sshnpd/sshnpd_impl.dart b/packages/noports_core/lib/src/sshnpd/sshnpd_impl.dart index d2faf3fcc..51e00c728 100644 --- a/packages/noports_core/lib/src/sshnpd/sshnpd_impl.dart +++ b/packages/noports_core/lib/src/sshnpd/sshnpd_impl.dart @@ -561,7 +561,7 @@ class SshnpdImpl implements Sshnpd { String? errorMessage; switch (sshClient) { - case SupportedSshClient.exec: + case SupportedSshClient.openssh: (success, errorMessage) = await reverseSshViaExec( host: host, port: port, diff --git a/packages/noports_core/lib/sshnp_foundation.dart b/packages/noports_core/lib/sshnp_foundation.dart index c76b516ce..d9a321e32 100644 --- a/packages/noports_core/lib/sshnp_foundation.dart +++ b/packages/noports_core/lib/sshnp_foundation.dart @@ -24,13 +24,16 @@ export 'src/sshnp/util/sshrvd_channel/sshrvd_channel.dart'; export 'src/sshnp/util/sshrvd_channel/sshrvd_dart_channel.dart'; export 'src/sshnp/util/sshrvd_channel/sshrvd_exec_channel.dart'; -export 'src/sshnp/util/sshnp_initial_tunnel_handler.dart'; +export 'src/sshnp/util/sshnp_initial_tunnel_handler/sshnp_initial_tunnel_handler.dart'; +export 'src/sshnp/util/sshnp_initial_tunnel_handler/sshnp_dart_initial_tunnel_handler.dart'; +export 'src/sshnp/util/sshnp_initial_tunnel_handler/sshnp_openssh_initial_tunnel_handler.dart'; + export 'src/sshnp/util/sshnp_ssh_key_handler.dart'; // Impl export 'src/sshnp/impl/sshnp_dart_local_impl.dart'; export 'src/sshnp/impl/sshnp_dart_pure_impl.dart'; -export 'src/sshnp/impl/sshnp_exec_local_impl.dart'; +export 'src/sshnp/impl/sshnp_openssh_local_impl.dart'; export 'src/sshnp/impl/sshnp_unsigned_impl.dart'; // Common diff --git a/packages/sshnoports/lib/sshnp.dart b/packages/sshnoports/lib/sshnp.dart index 26be8f276..c8f74c641 100644 --- a/packages/sshnoports/lib/sshnp.dart +++ b/packages/sshnoports/lib/sshnp.dart @@ -23,8 +23,8 @@ Future sshnpFromParamsWithFileBindings( } switch (params.sshClient) { - case SupportedSshClient.exec: - return Sshnp.execLocal( + case SupportedSshClient.openssh: + return Sshnp.openssh( atClient: atClient, params: params, ); From 20aa780c3e43ba66ddf12816c5229385d83b9254 Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Mon, 6 Nov 2023 17:11:12 -0500 Subject: [PATCH 05/11] chore: replace openssh binary path in sshnpd --- .../noports_core/lib/src/common/openssh_binary_path.dart | 7 +++++++ .../sshnp_openssh_initial_tunnel_handler.dart | 7 +------ packages/noports_core/lib/src/sshnpd/sshnpd_impl.dart | 9 +++++---- 3 files changed, 13 insertions(+), 10 deletions(-) create mode 100644 packages/noports_core/lib/src/common/openssh_binary_path.dart diff --git a/packages/noports_core/lib/src/common/openssh_binary_path.dart b/packages/noports_core/lib/src/common/openssh_binary_path.dart new file mode 100644 index 000000000..afbeef643 --- /dev/null +++ b/packages/noports_core/lib/src/common/openssh_binary_path.dart @@ -0,0 +1,7 @@ +import 'dart:io'; + +const String _windowsOpensshPath = r'C:\Windows\System32\OpenSSH\ssh.exe'; +const String _unixOpensshPath = '/usr/bin/ssh'; + +String get opensshBinaryPath => + Platform.isWindows ? _windowsOpensshPath : _unixOpensshPath; 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 b4193c371..e0e25d410 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 @@ -2,16 +2,11 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'package:noports_core/src/common/openssh_binary_path.dart'; import 'package:noports_core/sshnp_foundation.dart'; -const String _windowsOpensshPath = r'C:\Windows\System32\OpenSSH\ssh.exe'; -const String _unixOpensshPath = '/usr/bin/ssh'; - mixin SshnpOpensshInitialTunnelHandler on SshnpCore implements SshnpInitialTunnelHandler { - String get opensshBinaryPath => - Platform.isWindows ? _windowsOpensshPath : _unixOpensshPath; - @override Future startInitialTunnel({required String identifier}) async { Process? process; diff --git a/packages/noports_core/lib/src/sshnpd/sshnpd_impl.dart b/packages/noports_core/lib/src/sshnpd/sshnpd_impl.dart index 51e00c728..42b25057d 100644 --- a/packages/noports_core/lib/src/sshnpd/sshnpd_impl.dart +++ b/packages/noports_core/lib/src/sshnpd/sshnpd_impl.dart @@ -7,6 +7,7 @@ import 'package:at_utils/at_logger.dart'; import 'package:dartssh2/dartssh2.dart'; import 'package:logging/logging.dart'; import 'package:meta/meta.dart'; +import 'package:noports_core/src/common/openssh_binary_path.dart'; import 'package:noports_core/src/sshrv/sshrv.dart'; import 'package:noports_core/sshnpd.dart'; import 'package:noports_core/utils.dart'; @@ -782,7 +783,7 @@ class SshnpdImpl implements Sshnpd { ' -f' // fork after authentication ' sleep 15' .split(' '); - logger.info('$sessionId | Executing /usr/bin/ssh ${args.join(' ')}'); + logger.info('$sessionId | Executing $opensshBinaryPath ${args.join(' ')}'); // Because of the options we are using, we can wait for this process // to complete, because it will exit with exitCode 0 once it has connected @@ -791,7 +792,7 @@ class SshnpdImpl implements Sshnpd { final soutBuf = StringBuffer(); final serrBuf = StringBuffer(); try { - Process process = await Process.start('/usr/bin/ssh', args); + Process process = await Process.start(opensshBinaryPath, args); process.stdout.listen((List l) { var s = utf8.decode(l); soutBuf.write(s); @@ -813,11 +814,11 @@ class SshnpdImpl implements Sshnpd { if (sshExitCode != 0) { if (sshExitCode == 6464) { logger.shout( - '$sessionId | Command timed out: /usr/bin/ssh ${args.join(' ')}'); + '$sessionId | Command timed out: $opensshBinaryPath ${args.join(' ')}'); errorMessage = 'Failed to establish connection - timed out'; } else { logger.shout('$sessionId | Exit code $sshExitCode from' - ' /usr/bin/ssh ${args.join(' ')}'); + ' $opensshBinaryPath ${args.join(' ')}'); errorMessage = 'Failed to establish connection - exit code $sshExitCode'; } From c4e3f9962af1d7654695dea0fa6bbd2a1263a2a9 Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Mon, 6 Nov 2023 17:18:57 -0500 Subject: [PATCH 06/11] fix: background the ssh process via dart / powershell on Windows openssh --- .../sshnp/impl/sshnp_openssh_local_impl.dart | 2 +- .../sshnp_openssh_initial_tunnel_handler.dart | 47 ++++++++++++++----- 2 files changed, 35 insertions(+), 14 deletions(-) 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 b6b09e1fd..6fc9cec05 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 @@ -79,7 +79,7 @@ class SshnpOpensshLocalImpl extends SshnpCore ); /// Start the initial tunnel - Process bean = + Process? bean = await startInitialTunnel(identifier: ephemeralKeyPair.identifier); /// Remove the key pair from the key utility 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 e0e25d410..309b9a09a 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 @@ -6,9 +6,9 @@ import 'package:noports_core/src/common/openssh_binary_path.dart'; import 'package:noports_core/sshnp_foundation.dart'; mixin SshnpOpensshInitialTunnelHandler on SshnpCore - implements SshnpInitialTunnelHandler { + implements SshnpInitialTunnelHandler { @override - Future startInitialTunnel({required String identifier}) async { + Future startInitialTunnel({required String identifier}) async { Process? process; // If we are starting an initial tunnel, it should be to sshrvd, // so it is safe to assume that sshrvdChannel is not null here @@ -40,19 +40,40 @@ mixin SshnpOpensshInitialTunnelHandler on SshnpCore final soutBuf = StringBuffer(); final serrBuf = StringBuffer(); try { - process = await Process.start(opensshBinaryPath, args); - process.stdout.transform(Utf8Decoder()).listen((String s) { - soutBuf.write(s); - logger.info(' $sessionId | sshStdOut | $s'); - }, onError: (e) {}); - process.stderr.transform(Utf8Decoder()).listen((String s) { - serrBuf.write(s); - logger.info(' $sessionId | sshStdErr | $s'); - }, onError: (e) {}); - await process.exitCode.timeout(Duration(seconds: 10)); + if (Platform.isWindows) { + // We have to do special stuff on Windows because -f doesn't fork + // properly in the Windows OpenSSH client: + // This incantation opens the initial tunnel in a separate powershell + // window. It's not necessary (and currently not possible) to capture + // the process since there is a physical window the user can close to + // end the session + unawaited(Process.start( + 'powershell.exe', + [ + '-command', + opensshBinaryPath, + ...args, + ], + runInShell: true, + mode: ProcessStartMode.detachedWithStdio, + )); + // Delay to allow the detached session to pick up the keys + await Future.delayed(Duration(seconds: 1)); + } else { + process = await Process.start(opensshBinaryPath, args); + process.stdout.transform(Utf8Decoder()).listen((String s) { + soutBuf.write(s); + logger.info(' $sessionId | sshStdOut | $s'); + }, onError: (e) {}); + process.stderr.transform(Utf8Decoder()).listen((String s) { + serrBuf.write(s); + logger.info(' $sessionId | sshStdErr | $s'); + }, onError: (e) {}); + await process.exitCode.timeout(Duration(seconds: 10)); + } } on TimeoutException catch (e) { throw SshnpError( - 'ssh process timed out after 10 seconds', + 'SSHNP failed to start the initial tunnel', error: e, ); } From 0608e6d99f1d491c43063f044da5b6d3fb452fbd Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Mon, 6 Nov 2023 22:12:50 -0500 Subject: [PATCH 07/11] ci: add windows x64 to multibuild --- .github/workflows/multibuild.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/multibuild.yaml b/.github/workflows/multibuild.yaml index e2303b7a6..e06a063b2 100644 --- a/.github/workflows/multibuild.yaml +++ b/.github/workflows/multibuild.yaml @@ -20,12 +20,14 @@ jobs: working-directory: ./packages/sshnoports strategy: matrix: - os: [ubuntu-latest, macOS-latest] + os: [ubuntu-latest, macOS-latest, windows-latest] include: - os: ubuntu-latest output-name: sshnp-linux-x64 - os: macOS-latest output-name: sshnp-macos-x64 + - os: windows-latest + output-name: sshnp-windows-x64 steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 From bb87cf3bc544480ca0a44cff5c47e288a5a0f3e9 Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Fri, 10 Nov 2023 18:24:32 -0500 Subject: [PATCH 08/11] deps: upgrade deps --- packages/sshnoports/pubspec.lock | 12 +- packages/sshnp_gui/pubspec.lock | 208 ++----------------------------- 2 files changed, 14 insertions(+), 206 deletions(-) diff --git a/packages/sshnoports/pubspec.lock b/packages/sshnoports/pubspec.lock index afb8fd6f8..92d762c57 100644 --- a/packages/sshnoports/pubspec.lock +++ b/packages/sshnoports/pubspec.lock @@ -77,10 +77,10 @@ packages: dependency: "direct overridden" description: name: at_client - sha256: d96bc7fe7f66419c41281627ff1f221e4fc4296847d4d7f90999c5aa6ecaddfd + sha256: b25f991409efa860a6196399c20bbebb8e763695197996ea4013789b4b96f297 url: "https://pub.dev" source: hosted - version: "3.0.65" + version: "3.0.68" at_commons: dependency: transitive description: @@ -93,10 +93,10 @@ packages: dependency: "direct overridden" description: name: at_lookup - sha256: "9a0db434b98a855b06dc90dcffa96667cd4ede21230449fdd9046c77ec4bb822" + sha256: "75f1e8e0445295c6b649aa04a95275f51d79cd18aa83a9d0c207f10604cc17b1" url: "https://pub.dev" source: hosted - version: "3.0.40" + version: "3.0.41" at_onboarding_cli: dependency: "direct main" description: @@ -109,10 +109,10 @@ packages: dependency: transitive description: name: at_persistence_secondary_server - sha256: "016a98b48d43db19dcb8601c43cdecbcbe0ed60c298d1cfd3d6425f7439e7c30" + sha256: "8dd493beaa10b42f42c47405884b926a01c07c345b53f25fa82383907880e24a" url: "https://pub.dev" source: hosted - version: "3.0.57" + version: "3.0.59" at_persistence_spec: dependency: transitive description: diff --git a/packages/sshnp_gui/pubspec.lock b/packages/sshnp_gui/pubspec.lock index 97f0c2bbd..11cf34782 100644 --- a/packages/sshnp_gui/pubspec.lock +++ b/packages/sshnp_gui/pubspec.lock @@ -1,22 +1,6 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a - url: "https://pub.dev" - source: hosted - version: "61.0.0" - analyzer: - dependency: transitive - description: - name: analyzer - sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 - url: "https://pub.dev" - source: hosted - version: "5.13.0" archive: dependency: transitive description: @@ -77,18 +61,18 @@ packages: dependency: transitive description: name: at_chops - sha256: "9d825e909eb5dcd1bf79554640860193488de7b2db07275692b0167bb80f2ca2" + sha256: "30863a74e38abc88258b8506ec1495ee6dc6bb95c1ab11d2d37fdbe455d93f82" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.5" at_client: dependency: transitive description: name: at_client - sha256: d96bc7fe7f66419c41281627ff1f221e4fc4296847d4d7f90999c5aa6ecaddfd + sha256: b25f991409efa860a6196399c20bbebb8e763695197996ea4013789b4b96f297 url: "https://pub.dev" source: hosted - version: "3.0.65" + version: "3.0.68" at_client_mobile: dependency: "direct main" description: @@ -141,10 +125,10 @@ packages: dependency: transitive description: name: at_lookup - sha256: "9a0db434b98a855b06dc90dcffa96667cd4ede21230449fdd9046c77ec4bb822" + sha256: "75f1e8e0445295c6b649aa04a95275f51d79cd18aa83a9d0c207f10604cc17b1" url: "https://pub.dev" source: hosted - version: "3.0.40" + version: "3.0.41" at_onboarding_flutter: dependency: "direct main" description: @@ -157,10 +141,10 @@ packages: dependency: transitive description: name: at_persistence_secondary_server - sha256: "016a98b48d43db19dcb8601c43cdecbcbe0ed60c298d1cfd3d6425f7439e7c30" + sha256: "8dd493beaa10b42f42c47405884b926a01c07c345b53f25fa82383907880e24a" url: "https://pub.dev" source: hosted - version: "3.0.57" + version: "3.0.59" at_persistence_spec: dependency: transitive description: @@ -265,14 +249,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.1" - coverage: - dependency: transitive - description: - name: coverage - sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097" - url: "https://pub.dev" - source: hosted - version: "1.6.3" cron: dependency: transitive description: @@ -565,22 +541,6 @@ packages: description: flutter source: sdk version: "0.0.0" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" - url: "https://pub.dev" - source: hosted - version: "3.2.0" - glob: - dependency: transitive - description: - name: glob - sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" - url: "https://pub.dev" - source: hosted - version: "2.1.2" go_router: dependency: "direct main" description: @@ -605,14 +565,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.13.6" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" - url: "https://pub.dev" - source: hosted - version: "3.2.1" http_parser: dependency: transitive description: @@ -645,14 +597,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.17.0" - io: - dependency: transitive - description: - name: io - sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" - url: "https://pub.dev" - source: hosted - version: "1.0.4" js: dependency: transitive description: @@ -733,14 +677,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" - mocktail: - dependency: transitive - description: - name: mocktail - sha256: "80a996cd9a69284b3dc521ce185ffe9150cde69767c2d3a0720147d93c0cef53" - url: "https://pub.dev" - source: hosted - version: "0.3.0" mutex: dependency: transitive description: @@ -757,14 +693,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" - node_preamble: - dependency: transitive - description: - name: node_preamble - sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" - url: "https://pub.dev" - source: hosted - version: "2.0.2" noports_core: dependency: "direct main" description: @@ -780,14 +708,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" - package_config: - dependency: transitive - description: - name: package_config - sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" - url: "https://pub.dev" - source: hosted - version: "2.1.0" package_info_plus: dependency: transitive description: @@ -972,14 +892,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.7.3" - pool: - dependency: transitive - description: - name: pool - sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" - url: "https://pub.dev" - source: hosted - version: "1.5.1" posix: dependency: transitive description: @@ -996,14 +908,6 @@ packages: url: "https://pub.dev" source: hosted version: "4.2.4" - pub_semver: - dependency: transitive - description: - name: pub_semver - sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" - url: "https://pub.dev" - source: hosted - version: "2.1.4" qr_code_scanner: dependency: transitive description: @@ -1100,38 +1004,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.1" - shelf: - dependency: transitive - description: - name: shelf - sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 - url: "https://pub.dev" - source: hosted - version: "1.4.1" - shelf_packages_handler: - dependency: transitive - description: - name: shelf_packages_handler - sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - shelf_static: - dependency: transitive - description: - name: shelf_static - sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e - url: "https://pub.dev" - source: hosted - version: "1.1.2" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" - url: "https://pub.dev" - source: hosted - version: "1.0.4" showcaseview: dependency: transitive description: @@ -1154,22 +1026,6 @@ packages: url: "https://github.com/xavierchanth/socket_connector/" source: git version: "1.0.11" - source_map_stack_trace: - dependency: transitive - description: - name: source_map_stack_trace - sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - source_maps: - dependency: transitive - description: - name: source_maps - sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" - url: "https://pub.dev" - source: hosted - version: "0.10.12" source_span: dependency: transitive description: @@ -1218,14 +1074,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.1" - test: - dependency: transitive - description: - name: test - sha256: "13b41f318e2a5751c3169137103b60c584297353d4b1761b66029bae6411fe46" - url: "https://pub.dev" - source: hosted - version: "1.24.3" test_api: dependency: transitive description: @@ -1234,14 +1082,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.0" - test_core: - dependency: transitive - description: - name: test_core - sha256: "99806e9e6d95c7b059b7a0fc08f07fc53fabe54a829497f0d9676299f1e8637e" - url: "https://pub.dev" - source: hosted - version: "0.5.3" tutorial_coach_mark: dependency: transitive description: @@ -1370,22 +1210,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.2" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: c538be99af830f478718b51630ec1b6bee5e74e52c8a802d328d9e71d35d2583 - url: "https://pub.dev" - source: hosted - version: "11.10.0" - watcher: - dependency: transitive - description: - name: watcher - sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" - url: "https://pub.dev" - source: hosted - version: "1.1.0" web: dependency: transitive description: @@ -1394,22 +1218,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.4-beta" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b - url: "https://pub.dev" - source: hosted - version: "2.4.0" - webkit_inspection_protocol: - dependency: transitive - description: - name: webkit_inspection_protocol - sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" - url: "https://pub.dev" - source: hosted - version: "1.2.1" webview_flutter: dependency: transitive description: From 2fc246ba101f1e3de3ffb2c5ef47dc9a33bf8112 Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Mon, 13 Nov 2023 09:38:25 -0500 Subject: [PATCH 09/11] chore: delay 3 seconds on windows --- .../sshnp_openssh_initial_tunnel_handler.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 309b9a09a..c36e6c141 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 @@ -58,7 +58,7 @@ mixin SshnpOpensshInitialTunnelHandler on SshnpCore mode: ProcessStartMode.detachedWithStdio, )); // Delay to allow the detached session to pick up the keys - await Future.delayed(Duration(seconds: 1)); + await Future.delayed(Duration(seconds: 3)); } else { process = await Process.start(opensshBinaryPath, args); process.stdout.transform(Utf8Decoder()).listen((String s) { From ce98a4d718f7df9a42aad62572cc963b9f907eea Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Mon, 13 Nov 2023 09:46:06 -0500 Subject: [PATCH 10/11] Revert "chore: delay 3 seconds on windows" This reverts commit 2fc246ba101f1e3de3ffb2c5ef47dc9a33bf8112. --- .../sshnp_openssh_initial_tunnel_handler.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 c36e6c141..309b9a09a 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 @@ -58,7 +58,7 @@ mixin SshnpOpensshInitialTunnelHandler on SshnpCore mode: ProcessStartMode.detachedWithStdio, )); // Delay to allow the detached session to pick up the keys - await Future.delayed(Duration(seconds: 3)); + await Future.delayed(Duration(seconds: 1)); } else { process = await Process.start(opensshBinaryPath, args); process.stdout.transform(Utf8Decoder()).listen((String s) { From 06a828a5bd5d9eecb17d8a553256f8a91fa58915 Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Mon, 13 Nov 2023 09:52:23 -0500 Subject: [PATCH 11/11] Revert "Revert "chore: delay 3 seconds on windows"" This reverts commit ce98a4d718f7df9a42aad62572cc963b9f907eea. --- .../sshnp_openssh_initial_tunnel_handler.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 309b9a09a..c36e6c141 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 @@ -58,7 +58,7 @@ mixin SshnpOpensshInitialTunnelHandler on SshnpCore mode: ProcessStartMode.detachedWithStdio, )); // Delay to allow the detached session to pick up the keys - await Future.delayed(Duration(seconds: 1)); + await Future.delayed(Duration(seconds: 3)); } else { process = await Process.start(opensshBinaryPath, args); process.stdout.transform(Utf8Decoder()).listen((String s) {