From b5e67b68a826a9a7e32e107c782ad0fdda60ab48 Mon Sep 17 00:00:00 2001 From: gkc Date: Wed, 22 Nov 2023 14:24:52 +0000 Subject: [PATCH] feat: Add -U option to provide a `tunnelUsername` to use for the initial ssh tunnel. When not supplied, the username for the initial tunnel is the `remoteUsername` --- .../lib/src/sshnp/models/sshnp_arg.dart | 6 +++ .../lib/src/sshnp/models/sshnp_params.dart | 29 ++++++++----- .../lib/src/sshnp/sshnp_core.dart | 6 +++ .../sshnp_dart_initial_tunnel_handler.dart | 7 ++-- .../sshnp_openssh_initial_tunnel_handler.dart | 2 +- .../util/sshnpd_channel/sshnpd_channel.dart | 11 +++++ .../test/sshnp/models/sshnp_params_test.dart | 42 +++++++++++++++++++ .../test/sshnp/sshnp_core_test.dart | 2 + .../sshnp_local_ssh_key_handler_test.dart | 2 + packages/sshnp_gui/lib/l10n/app_en.arb | 1 + 10 files changed, 94 insertions(+), 14 deletions(-) diff --git a/packages/noports_core/lib/src/sshnp/models/sshnp_arg.dart b/packages/noports_core/lib/src/sshnp/models/sshnp_arg.dart index 84c62cbfe..4226b7257 100644 --- a/packages/noports_core/lib/src/sshnp/models/sshnp_arg.dart +++ b/packages/noports_core/lib/src/sshnp/models/sshnp_arg.dart @@ -115,6 +115,7 @@ class SshnpArg { localSshOptionsArg, verboseArg, remoteUserNameArg, + tunnelUserNameArg, rootDomainArg, localSshdPortArg, legacyDaemonArg, @@ -278,6 +279,11 @@ class SshnpArg { abbr: 'u', help: 'username to use in the ssh session on the remote host', ); + static const tunnelUserNameArg = SshnpArg( + name: 'tunnel-user-name', + abbr: 'U', + help: 'username to use for the initial ssh tunnel', + ); static const rootDomainArg = SshnpArg( name: 'root-domain', help: 'atDirectory domain', diff --git a/packages/noports_core/lib/src/sshnp/models/sshnp_params.dart b/packages/noports_core/lib/src/sshnp/models/sshnp_params.dart index 43006dc67..be37b9945 100644 --- a/packages/noports_core/lib/src/sshnp/models/sshnp_params.dart +++ b/packages/noports_core/lib/src/sshnp/models/sshnp_params.dart @@ -25,6 +25,7 @@ class SshnpParams { final bool sendSshPublicKey; final List localSshOptions; final String? remoteUsername; + final String? tunnelUsername; final bool verbose; final String rootDomain; final int localSshdPort; @@ -38,7 +39,7 @@ class SshnpParams { /// Special Arguments final String? - profileName; // automatically populated with the filename if from a configFile + profileName; // automatically populated with the filename if from a configFile /// Operation flags final bool listDevices; @@ -57,6 +58,7 @@ class SshnpParams { this.localSshOptions = DefaultSshnpArgs.localSshOptions, this.verbose = DefaultArgs.verbose, this.remoteUsername, + this.tunnelUsername, this.atKeysFilePath, this.rootDomain = DefaultArgs.rootDomain, this.localSshdPort = DefaultArgs.localSshdPort, @@ -94,10 +96,11 @@ class SshnpParams { atKeysFilePath: params2.atKeysFilePath ?? params1.atKeysFilePath, identityFile: params2.identityFile ?? params1.identityFile, identityPassphrase: - params2.identityPassphrase ?? params1.identityPassphrase, + params2.identityPassphrase ?? params1.identityPassphrase, sendSshPublicKey: params2.sendSshPublicKey ?? params1.sendSshPublicKey, localSshOptions: params2.localSshOptions ?? params1.localSshOptions, remoteUsername: params2.remoteUsername ?? params1.remoteUsername, + tunnelUsername: params2.tunnelUsername ?? params1.tunnelUsername, verbose: params2.verbose ?? params1.verbose, rootDomain: params2.rootDomain ?? params1.rootDomain, localSshdPort: params2.localSshdPort ?? params1.localSshdPort, @@ -106,7 +109,7 @@ class SshnpParams { remoteSshdPort: params2.remoteSshdPort ?? params1.remoteSshdPort, idleTimeout: params2.idleTimeout ?? params1.idleTimeout, addForwardsToTunnel: - params2.addForwardsToTunnel ?? params1.addForwardsToTunnel, + params2.addForwardsToTunnel ?? params1.addForwardsToTunnel, sshClient: params2.sshClient ?? params1.sshClient, sshAlgorithm: params2.sshAlgorithm ?? params1.sshAlgorithm, ); @@ -134,11 +137,12 @@ class SshnpParams { identityFile: partial.identityFile, identityPassphrase: partial.identityPassphrase, sendSshPublicKey: - partial.sendSshPublicKey ?? DefaultSshnpArgs.sendSshPublicKey, + partial.sendSshPublicKey ?? DefaultSshnpArgs.sendSshPublicKey, localSshOptions: - partial.localSshOptions ?? DefaultSshnpArgs.localSshOptions, + partial.localSshOptions ?? DefaultSshnpArgs.localSshOptions, verbose: partial.verbose ?? DefaultArgs.verbose, remoteUsername: partial.remoteUsername, + tunnelUsername: partial.tunnelUsername, atKeysFilePath: partial.atKeysFilePath, rootDomain: partial.rootDomain ?? DefaultArgs.rootDomain, localSshdPort: partial.localSshdPort ?? DefaultArgs.localSshdPort, @@ -147,7 +151,7 @@ class SshnpParams { remoteSshdPort: partial.remoteSshdPort ?? DefaultArgs.remoteSshdPort, idleTimeout: partial.idleTimeout ?? DefaultArgs.idleTimeout, addForwardsToTunnel: - partial.addForwardsToTunnel ?? DefaultArgs.addForwardsToTunnel, + partial.addForwardsToTunnel ?? DefaultArgs.addForwardsToTunnel, sshClient: partial.sshClient ?? DefaultSshnpArgs.sshClient, sshAlgorithm: partial.sshAlgorithm ?? DefaultArgs.sshAlgorithm, ); @@ -190,6 +194,7 @@ class SshnpParams { SshnpArg.sendSshPublicKeyArg.name: sendSshPublicKey, SshnpArg.localSshOptionsArg.name: localSshOptions, SshnpArg.remoteUserNameArg.name: remoteUsername, + SshnpArg.tunnelUserNameArg.name: tunnelUsername, SshnpArg.verboseArg.name: verbose, SshnpArg.rootDomainArg.name: rootDomain, SshnpArg.localSshdPortArg.name: localSshdPort, @@ -200,7 +205,7 @@ class SshnpParams { SshnpArg.sshAlgorithmArg.name: sshAlgorithm.toString(), }; args.removeWhere( - (key, value) => !parserType.shouldParse(SshnpArg.fromName(key).parseWhen), + (key, value) => !parserType.shouldParse(SshnpArg.fromName(key).parseWhen), ); return args; } @@ -229,6 +234,7 @@ class SshnpPartialParams { final bool? sendSshPublicKey; final List? localSshOptions; final String? remoteUsername; + final String? tunnelUsername; final bool? verbose; final String? rootDomain; final bool? legacyDaemon; @@ -255,6 +261,7 @@ class SshnpPartialParams { this.sendSshPublicKey, this.localSshOptions, this.remoteUsername, + this.tunnelUsername, this.verbose, this.rootDomain, this.localSshdPort, @@ -287,10 +294,11 @@ class SshnpPartialParams { atKeysFilePath: params2.atKeysFilePath ?? params1.atKeysFilePath, identityFile: params2.identityFile ?? params1.identityFile, identityPassphrase: - params2.identityPassphrase ?? params1.identityPassphrase, + params2.identityPassphrase ?? params1.identityPassphrase, sendSshPublicKey: params2.sendSshPublicKey ?? params1.sendSshPublicKey, localSshOptions: params2.localSshOptions ?? params1.localSshOptions, remoteUsername: params2.remoteUsername ?? params1.remoteUsername, + tunnelUsername: params2.tunnelUsername ?? params1.tunnelUsername, verbose: params2.verbose ?? params1.verbose, rootDomain: params2.rootDomain ?? params1.rootDomain, localSshdPort: params2.localSshdPort ?? params1.localSshdPort, @@ -299,7 +307,7 @@ class SshnpPartialParams { remoteSshdPort: params2.remoteSshdPort ?? params1.remoteSshdPort, idleTimeout: params2.idleTimeout ?? params1.idleTimeout, addForwardsToTunnel: - params2.addForwardsToTunnel ?? params1.addForwardsToTunnel, + params2.addForwardsToTunnel ?? params1.addForwardsToTunnel, sshClient: params2.sshClient ?? params1.sshClient, sshAlgorithm: params2.sshAlgorithm ?? params1.sshAlgorithm, ); @@ -339,6 +347,7 @@ class SshnpPartialParams { ? null : List.from(args[SshnpArg.localSshOptionsArg.name]), remoteUsername: args[SshnpArg.remoteUserNameArg.name], + tunnelUsername: args[SshnpArg.tunnelUserNameArg.name], verbose: args[SshnpArg.verboseArg.name], rootDomain: args[SshnpArg.rootDomainArg.name], localSshdPort: args[SshnpArg.localSshdPortArg.name], @@ -353,7 +362,7 @@ class SshnpPartialParams { sshAlgorithm: args[SshnpArg.sshAlgorithmArg.name] == null ? null : SupportedSshAlgorithm.fromString( - args[SshnpArg.sshAlgorithmArg.name]), + args[SshnpArg.sshAlgorithmArg.name]), ); } diff --git a/packages/noports_core/lib/src/sshnp/sshnp_core.dart b/packages/noports_core/lib/src/sshnp/sshnp_core.dart index 71ded03c6..c8271d441 100644 --- a/packages/noports_core/lib/src/sshnp/sshnp_core.dart +++ b/packages/noports_core/lib/src/sshnp/sshnp_core.dart @@ -46,6 +46,9 @@ abstract class SshnpCore /// The remote username to use for the ssh session String? remoteUsername; + /// The username to use for the initial ssh tunnel session + String? tunnelUsername; + // * Communication Channels /// The channel to communicate with the sshrvd (host) @@ -83,6 +86,9 @@ abstract class SshnpCore /// Set the remote username to use for the ssh session remoteUsername = await sshnpdChannel.resolveRemoteUsername(); + /// Set the username to use for the initial ssh tunnel + tunnelUsername = await sshnpdChannel.resolveTunnelUsername(remoteUsername); + /// Shares the public key if required await sshnpdChannel.sharePublicKeyIfRequired(identityKeyPair); 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 efb6c59f2..ec5fe5eff 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 @@ -39,17 +39,18 @@ mixin SshnpDartInitialTunnelHandler on SshnpCore throw error; } + var usernameForTunnel = tunnelUsername ?? getUserName(throwIfNull: true)!; try { AtSshKeyPair keyPair = await keyUtil.getKeyPair(identifier: identifier); client = SSHClient( socket, - username: remoteUsername ?? getUserName(throwIfNull: true)!, + username: usernameForTunnel, identities: [keyPair.keyPair], keepAliveInterval: Duration(seconds: 15), ); } catch (e, s) { throw SshnpError( - 'Failed to create SSHClient for ${params.remoteUsername}@${sshrvdChannel.host}:${sshrvdChannel.sshrvdPort} : $e', + 'Failed to create SSHClient for $usernameForTunnel@${sshrvdChannel.host}:${sshrvdChannel.sshrvdPort} : $e', error: e, stackTrace: s, ); @@ -59,7 +60,7 @@ mixin SshnpDartInitialTunnelHandler on SshnpCore await client.authenticated.catchError((e) => throw e); } catch (e, s) { throw SshnpError( - 'Failed to authenticate as ${params.remoteUsername}@${sshrvdChannel.host}:${sshrvdChannel.sshrvdPort} : $e', + 'Failed to authenticate as $usernameForTunnel@${sshrvdChannel.host}:${sshrvdChannel.sshrvdPort} : $e', error: e, stackTrace: s, ); 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 179a4e8e8..f2768f967 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 @@ -16,7 +16,7 @@ mixin SshnpOpensshInitialTunnelHandler on SshnpCore 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}' + String argsString = '$tunnelUsername@${sshrvdChannel.host}' ' -p ${sshrvdChannel.sshrvdPort}' ' -i $identifier' ' -L $localPort:localhost:${params.remoteSshdPort}' diff --git a/packages/noports_core/lib/src/sshnp/util/sshnpd_channel/sshnpd_channel.dart b/packages/noports_core/lib/src/sshnp/util/sshnpd_channel/sshnpd_channel.dart index 058db128f..2dba23ec2 100644 --- a/packages/noports_core/lib/src/sshnp/util/sshnpd_channel/sshnpd_channel.dart +++ b/packages/noports_core/lib/src/sshnp/util/sshnpd_channel/sshnpd_channel.dart @@ -161,6 +161,17 @@ abstract class SshnpdChannel with AsyncInitialization, AtClientBindings { } } + /// Resolve the username to use in the initial ssh tunnel + /// If [params.tunnelUsername] is set, it will be used. + /// Otherwise, the username will be set to [remoteUsername] + Future resolveTunnelUsername(String? remoteUsername) async { + if (params.tunnelUsername != null) { + return params.tunnelUsername!; + } else { + return remoteUsername; + } + } + /// List all available devices from the daemon. /// Returns a [SSHPNPDeviceList] object which contains a map of device names /// and corresponding info, and a list of active devices (devices which also diff --git a/packages/noports_core/test/sshnp/models/sshnp_params_test.dart b/packages/noports_core/test/sshnp/models/sshnp_params_test.dart index 14d2023e4..9a1838334 100644 --- a/packages/noports_core/test/sshnp/models/sshnp_params_test.dart +++ b/packages/noports_core/test/sshnp/models/sshnp_params_test.dart @@ -18,6 +18,7 @@ void main() { expect(params.sendSshPublicKey, isA()); expect(params.localSshOptions, isA>()); expect(params.remoteUsername, isA()); + expect(params.tunnelUsername, isA()); expect(params.verbose, isA()); expect(params.rootDomain, isA()); expect(params.localSshdPort, isA()); @@ -110,6 +111,14 @@ void main() { remoteUsername: 'myUsername'); expect(params.remoteUsername, equals('myUsername')); }); + test('SshnpParams.tunnelUsername test', () { + final params = SshnpParams( + clientAtSign: '', + sshnpdAtSign: '', + host: '', + tunnelUsername: 'myTunnelUsername'); + expect(params.tunnelUsername, equals('myTunnelUsername')); + }); test('SshnpParams.verbose test', () { final params = SshnpParams( clientAtSign: '', sshnpdAtSign: '', host: '', verbose: true); @@ -209,6 +218,7 @@ void main() { params.localSshOptions, equals(DefaultSshnpArgs.localSshOptions)); expect(params.verbose, equals(DefaultArgs.verbose)); expect(params.remoteUsername, isNull); + expect(params.tunnelUsername, isNull); expect(params.atKeysFilePath, isNull); expect(params.rootDomain, equals(DefaultArgs.rootDomain)); expect(params.localSshdPort, equals(DefaultArgs.localSshdPort)); @@ -236,6 +246,7 @@ void main() { sendSshPublicKey: true, localSshOptions: ['-L 127.0.01:8080:127.0.0.1:80'], remoteUsername: 'myUsername', + tunnelUsername: 'myTunnelUsername', verbose: true, rootDomain: 'root.atsign.wtf', localSshdPort: 4567, @@ -260,6 +271,7 @@ void main() { expect( params.localSshOptions, equals(['-L 127.0.01:8080:127.0.0.1:80'])); expect(params.remoteUsername, equals('myUsername')); + expect(params.tunnelUsername, equals('myTunnelUsername')); expect(params.verbose, equals(true)); expect(params.rootDomain, equals('root.atsign.wtf')); expect(params.localSshdPort, equals(4567)); @@ -290,6 +302,7 @@ void main() { params.localSshOptions, equals(DefaultSshnpArgs.localSshOptions)); expect(params.verbose, equals(DefaultArgs.verbose)); expect(params.remoteUsername, isNull); + expect(params.tunnelUsername, isNull); expect(params.atKeysFilePath, isNull); expect(params.rootDomain, equals(DefaultArgs.rootDomain)); expect(params.localSshdPort, equals(DefaultArgs.localSshdPort)); @@ -316,6 +329,7 @@ void main() { '"${SshnpArg.sendSshPublicKeyArg.name}": true,' '"${SshnpArg.localSshOptionsArg.name}": ["-L 127.0.01:8080:127.0.0.1:80"],' '"${SshnpArg.remoteUserNameArg.name}": "myUsername",' + '"${SshnpArg.tunnelUserNameArg.name}": "myTunnelUsername",' '"${SshnpArg.verboseArg.name}": true,' '"${SshnpArg.rootDomainArg.name}": "root.atsign.wtf",' '"${SshnpArg.localSshdPortArg.name}": 4567,' @@ -342,6 +356,7 @@ void main() { expect( params.localSshOptions, equals(['-L 127.0.01:8080:127.0.0.1:80'])); expect(params.remoteUsername, equals('myUsername')); + expect(params.tunnelUsername, equals('myTunnelUsername')); expect(params.verbose, equals(true)); expect(params.rootDomain, equals('root.atsign.wtf')); expect(params.localSshdPort, equals(4567)); @@ -378,6 +393,7 @@ void main() { '${SshnpArg.sendSshPublicKeyArg.bashName} = true', '${SshnpArg.localSshOptionsArg.bashName} = -L 127.0.01:8080:127.0.0.1:80', '${SshnpArg.remoteUserNameArg.bashName} = myUsername', + '${SshnpArg.tunnelUserNameArg.bashName} = myTunnelUsername', '${SshnpArg.verboseArg.bashName} = true', '${SshnpArg.rootDomainArg.bashName} = root.atsign.wtf', '${SshnpArg.localSshdPortArg.bashName} = 4567', @@ -401,6 +417,7 @@ void main() { expect( params.localSshOptions, equals(['-L 127.0.01:8080:127.0.0.1:80'])); expect(params.remoteUsername, equals('myUsername')); + expect(params.tunnelUsername, equals('myTunnelUsername')); expect(params.verbose, equals(true)); expect(params.rootDomain, equals('root.atsign.wtf')); expect(params.localSshdPort, equals(4567)); @@ -422,6 +439,7 @@ void main() { sendSshPublicKey: true, localSshOptions: ['-L 127.0.01:8080:127.0.0.1:80'], remoteUsername: 'myUsername', + tunnelUsername: 'myTunnelUsername', verbose: true, rootDomain: 'root.atsign.wtf', localSshdPort: 4567, @@ -449,6 +467,7 @@ void main() { expect(parsedParams.localSshOptions, equals(['-L 127.0.01:8080:127.0.0.1:80'])); expect(parsedParams.remoteUsername, equals('myUsername')); + expect(parsedParams.tunnelUsername, equals('myTunnelUsername')); expect(parsedParams.verbose, equals(true)); expect(parsedParams.rootDomain, equals('root.atsign.wtf')); expect(parsedParams.localSshdPort, equals(4567)); @@ -467,6 +486,7 @@ void main() { sendSshPublicKey: true, localSshOptions: ['-L 127.0.01:8080:127.0.0.1:80'], remoteUsername: 'myUsername', + tunnelUsername: 'myTunnelUsername', verbose: true, rootDomain: 'root.atsign.wtf', localSshdPort: 4567, @@ -492,6 +512,7 @@ void main() { expect(argMap[SshnpArg.localSshOptionsArg.name], equals(['-L 127.0.01:8080:127.0.0.1:80'])); expect(argMap[SshnpArg.remoteUserNameArg.name], equals('myUsername')); + expect(argMap[SshnpArg.tunnelUserNameArg.name], equals('myTunnelUsername')); expect(argMap[SshnpArg.verboseArg.name], equals(true)); expect(argMap[SshnpArg.rootDomainArg.name], equals('root.atsign.wtf')); expect(argMap[SshnpArg.localSshdPortArg.name], equals(4567)); @@ -518,6 +539,7 @@ void main() { sendSshPublicKey: true, localSshOptions: ['-L 127.0.01:8080:127.0.0.1:80'], remoteUsername: 'myUsername', + tunnelUsername: 'myTunnelUsername', verbose: true, rootDomain: 'root.atsign.wtf', localSshdPort: 4567, @@ -542,6 +564,7 @@ void main() { expect(parsedParams.localSshOptions, equals(['-L 127.0.01:8080:127.0.0.1:80'])); expect(parsedParams.remoteUsername, equals('myUsername')); + expect(parsedParams.tunnelUsername, equals('myTunnelUsername')); expect(parsedParams.verbose, equals(true)); expect(parsedParams.rootDomain, equals('root.atsign.wtf')); expect(parsedParams.localSshdPort, equals(4567)); @@ -571,6 +594,7 @@ void main() { expect(partialParams.sendSshPublicKey, isA()); expect(partialParams.localSshOptions, isA?>()); expect(partialParams.remoteUsername, isA()); + expect(partialParams.tunnelUsername, isA()); expect(partialParams.verbose, isA()); expect(partialParams.rootDomain, isA()); expect(partialParams.localSshdPort, isA()); @@ -632,6 +656,10 @@ void main() { final params = SshnpPartialParams(remoteUsername: 'myUsername'); expect(params.remoteUsername, equals('myUsername')); }); + test('SshnpPartialParams.tunnelUsername test', () { + final params = SshnpPartialParams(tunnelUsername: 'myTunnelUsername'); + expect(params.tunnelUsername, equals('myTunnelUsername')); + }); test('SshnpPartialParams.verbose test', () { final params = SshnpPartialParams(verbose: true); expect(params.verbose, equals(true)); @@ -700,6 +728,7 @@ void main() { expect(params.localSshOptions, isNull); expect(params.verbose, isNull); expect(params.remoteUsername, isNull); + expect(params.tunnelUsername, isNull); expect(params.rootDomain, isNull); expect(params.localSshdPort, isNull); expect(params.legacyDaemon, isNull); @@ -726,6 +755,7 @@ void main() { sendSshPublicKey: true, localSshOptions: ['-L 127.0.01:8080:127.0.0.1:80'], remoteUsername: 'myUsername', + tunnelUsername: 'myTunnelUsername', verbose: true, rootDomain: 'root.atsign.wtf', localSshdPort: 4567, @@ -749,6 +779,7 @@ void main() { expect( params.localSshOptions, equals(['-L 127.0.01:8080:127.0.0.1:80'])); expect(params.remoteUsername, equals('myUsername')); + expect(params.tunnelUsername, equals('myTunnelUsername')); expect(params.verbose, equals(true)); expect(params.rootDomain, equals('root.atsign.wtf')); expect(params.localSshdPort, equals(4567)); @@ -774,6 +805,7 @@ void main() { sendSshPublicKey: true, localSshOptions: ['-L 127.0.01:8080:127.0.0.1:80'], remoteUsername: 'myUsername', + tunnelUsername: 'myTunnelUsername', verbose: true, rootDomain: 'root.atsign.wtf', localSshdPort: 4567, @@ -798,6 +830,7 @@ void main() { expect( params.localSshOptions, equals(['-L 127.0.01:8080:127.0.0.1:80'])); expect(params.remoteUsername, equals('myUsername')); + expect(params.tunnelUsername, equals('myTunnelUsername')); expect(params.verbose, equals(true)); expect(params.rootDomain, equals('root.atsign.wtf')); expect(params.localSshdPort, equals(4567)); @@ -823,6 +856,7 @@ void main() { sendSshPublicKey: true, localSshOptions: ['-L 127.0.01:8080:127.0.0.1:80'], remoteUsername: 'myUsername', + tunnelUsername: 'myTunnelUsername', verbose: true, rootDomain: 'root.atsign.wtf', localSshdPort: 4567, @@ -850,6 +884,7 @@ void main() { expect(parsedParams.localSshOptions, equals(['-L 127.0.01:8080:127.0.0.1:80'])); expect(parsedParams.remoteUsername, equals('myUsername')); + expect(parsedParams.tunnelUsername, equals('myTunnelUsername')); expect(parsedParams.verbose, equals(true)); expect(parsedParams.rootDomain, equals('root.atsign.wtf')); expect(parsedParams.localSshdPort, equals(4567)); @@ -869,6 +904,7 @@ void main() { '"${SshnpArg.sendSshPublicKeyArg.name}": true,' '"${SshnpArg.localSshOptionsArg.name}": ["-L 127.0.01:8080:127.0.0.1:80"],' '"${SshnpArg.remoteUserNameArg.name}": "myUsername",' + '"${SshnpArg.tunnelUserNameArg.name}": "myTunnelUsername",' '"${SshnpArg.verboseArg.name}": true,' '"${SshnpArg.rootDomainArg.name}": "root.atsign.wtf",' '"${SshnpArg.localSshdPortArg.name}": 4567,' @@ -895,6 +931,7 @@ void main() { expect( params.localSshOptions, equals(['-L 127.0.01:8080:127.0.0.1:80'])); expect(params.remoteUsername, equals('myUsername')); + expect(params.tunnelUsername, equals('myTunnelUsername')); expect(params.verbose, equals(true)); expect(params.rootDomain, equals('root.atsign.wtf')); expect(params.localSshdPort, equals(4567)); @@ -921,6 +958,7 @@ void main() { SshnpArg.sendSshPublicKeyArg.name: true, SshnpArg.localSshOptionsArg.name: ['-L 127.0.01:8080:127.0.0.1:80'], SshnpArg.remoteUserNameArg.name: 'myUsername', + SshnpArg.tunnelUserNameArg.name: 'myTunnelUsername', SshnpArg.verboseArg.name: true, SshnpArg.rootDomainArg.name: 'root.atsign.wtf', SshnpArg.localSshdPortArg.name: 4567, @@ -945,6 +983,7 @@ void main() { expect( params.localSshOptions, equals(['-L 127.0.01:8080:127.0.0.1:80'])); expect(params.remoteUsername, equals('myUsername')); + expect(params.tunnelUsername, equals('myTunnelUsername')); expect(params.verbose, equals(true)); expect(params.rootDomain, equals('root.atsign.wtf')); expect(params.localSshdPort, equals(4567)); @@ -983,6 +1022,8 @@ void main() { '-L 127.0.01:8080:127.0.0.1:80', '--${SshnpArg.remoteUserNameArg.name}', 'myUsername', + '--${SshnpArg.tunnelUserNameArg.name}', + 'myTunnelUsername', '--${SshnpArg.verboseArg.name}', 'true', '--${SshnpArg.rootDomainArg.name}', @@ -1018,6 +1059,7 @@ void main() { expect( params.localSshOptions, equals(['-L 127.0.01:8080:127.0.0.1:80'])); expect(params.remoteUsername, equals('myUsername')); + expect(params.tunnelUsername, equals('myTunnelUsername')); expect(params.verbose, equals(true)); expect(params.rootDomain, equals('root.atsign.wtf')); expect(params.localSshdPort, equals(4567)); diff --git a/packages/noports_core/test/sshnp/sshnp_core_test.dart b/packages/noports_core/test/sshnp/sshnp_core_test.dart index ca290106e..467f1d8f5 100644 --- a/packages/noports_core/test/sshnp/sshnp_core_test.dart +++ b/packages/noports_core/test/sshnp/sshnp_core_test.dart @@ -54,6 +54,8 @@ void main() { .thenAnswer((_) async {}); when(() => mockSshnpdChannel.resolveRemoteUsername()) .thenAnswer((_) async => 'myRemoteUsername'); + when(() => mockSshnpdChannel.resolveTunnelUsername(any())) + .thenAnswer((_) async => 'myTunnelUsername'); when(() => mockSshnpdChannel.sharePublicKeyIfRequired( identityKeyPair ?? any())).thenAnswer((_) async {}); when(() => mockSshrvdChannel.callInitialization()) diff --git a/packages/noports_core/test/sshnp/util/sshnp_ssh_key_handler/sshnp_local_ssh_key_handler_test.dart b/packages/noports_core/test/sshnp/util/sshnp_ssh_key_handler/sshnp_local_ssh_key_handler_test.dart index e94eeb352..d76a6ea4e 100644 --- a/packages/noports_core/test/sshnp/util/sshnp_ssh_key_handler/sshnp_local_ssh_key_handler_test.dart +++ b/packages/noports_core/test/sshnp/util/sshnp_ssh_key_handler/sshnp_local_ssh_key_handler_test.dart @@ -40,6 +40,8 @@ void main() { .thenAnswer((_) async {}); when(() => mockSshnpdChannel.resolveRemoteUsername()) .thenAnswer((_) async => 'myRemoteUsername'); + when(() => mockSshnpdChannel.resolveTunnelUsername(any())) + .thenAnswer((_) async => 'myTunnelUsername'); when(() => mockSshnpdChannel.sharePublicKeyIfRequired(identityKeyPair)) .thenAnswer((_) async {}); when(() => mockSshrvdChannel.callInitialization()) diff --git a/packages/sshnp_gui/lib/l10n/app_en.arb b/packages/sshnp_gui/lib/l10n/app_en.arb index 85999dda4..cb951e9c6 100644 --- a/packages/sshnp_gui/lib/l10n/app_en.arb +++ b/packages/sshnp_gui/lib/l10n/app_en.arb @@ -72,6 +72,7 @@ "success": "Success", "switchAtsign" : "Switch atSign", "to" : "To", + "tunnelUserName" : "Remote Username to use for initial ssh tunnel", "username" : "Username", "usernameHint": "The user name on this host", "verbose" : "Verbose Logging",