Skip to content

Commit

Permalink
Merge branch 'socket-authenticator-option' into ci-allow-local-multi-…
Browse files Browse the repository at this point in the history
…build
  • Loading branch information
XavierChanth authored Jan 22, 2024
2 parents c853548 + 32d126e commit d5c4aad
Show file tree
Hide file tree
Showing 18 changed files with 155 additions and 95 deletions.
16 changes: 16 additions & 0 deletions packages/dart/noports_core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
# 6.0.0
- Added ability to authenticate to the socket rendezvous, and made this the
default behaviour.
- Added ability to end-to-end encrypt all traffic via the socket rendezvous (
SR), and made this the default behaviour. This provides a good general defense
against compromise by man-in-the-middle attacks if the two ends are
communicating via the SR. The encryption is implemented by exchanging a
symmetric key via an ephemeral encryption keypair generated by the client
for every session.
- Added ability to "ping" a daemon for info about it, including which
features the daemon supports.
- By default, sshnp now immediately drops into a prompt for clients that don't
support sshnp.canRunShell(). `-x` flag allows the ssh command to be output
instead of executing ssh immediately.
- Renamed everything sshrvd and sshrv to srvd and srv respectively

# 5.0.4

- refactor: move the `findLocalPortIfRequired` function to `EphemeralPortBinder`, a mixin on `SshnpCore`
Expand Down
8 changes: 4 additions & 4 deletions packages/dart/noports_core/lib/src/common/default_args.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ class DefaultArgs {
static const bool addForwardsToTunnel = false;
static final bool allowLocalFileSystem =
Platform.isLinux || Platform.isMacOS || Platform.isWindows;
static const bool authenticateClientToRvd = false;
static const bool authenticateDeviceToRvd = false;
static const bool encryptRvdTraffic = false;
static const bool discoverDaemonFeatures = false;
static const bool authenticateClientToRvd = true;
static const bool authenticateDeviceToRvd = true;
static const bool encryptRvdTraffic = true;
static const bool discoverDaemonFeatures = true;
}

class DefaultSshnpArgs {
Expand Down
8 changes: 6 additions & 2 deletions packages/dart/noports_core/lib/src/srv/srv_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class SrvImplExec implements Srv<Process> {
final String? sessionIVString;

@visibleForTesting
static const completionString = 'rv is running';
static const completionString = 'rv started successfully';

SrvImplExec(
this.host,
Expand Down Expand Up @@ -220,7 +220,11 @@ class SrvImplDart implements Srv<SocketConnector> {
}

// Do not remove this output; it is specifically looked for in
// SrvImplExec.run
// [SrvImplExec.run]. Why, you ask? Well, we have to wait until the srv
// has fully started - i.e. on the daemon side, established two outbound
// sockets, and on the client side, established one outbound socket and
// bound to a port. Looking for specific output when the rv is ready to
// do its job seems to be the only way to do this.
stderr.writeln(SrvImplExec.completionString);

return socketConnector;
Expand Down
7 changes: 6 additions & 1 deletion packages/dart/noports_core/lib/src/srvd/srvd_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,12 @@ class SrvdImpl implements Srvd {
FutureOr<AtClient> Function(SrvdParams)? atClientGenerator,
void Function(Object, StackTrace)? usageCallback}) async {
try {
var p = await SrvdParams.fromArgs(args);
SrvdParams p;
try {
p = await SrvdParams.fromArgs(args);
} on FormatException catch (e) {
throw ArgumentError(e.message);
}

if (!await File(p.atKeysFilePath).exists()) {
throw ('\n Unable to find .atKeys file : ${p.atKeysFilePath}');
Expand Down
15 changes: 11 additions & 4 deletions packages/dart/noports_core/lib/src/sshnpd/sshnpd.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,22 @@ abstract class Sshnpd {
/// - [SupportedSshAlgorithm.rsa]
abstract final SupportedSshAlgorithm sshAlgorithm;

static Future<Sshnpd> fromCommandLineArgs(List<String> args,
{AtClient? atClient,
FutureOr<AtClient> Function(SshnpdParams)? atClientGenerator,
void Function(Object, StackTrace)? usageCallback}) async {
/// The version of whatever program is using this library.
abstract final String version;

static Future<Sshnpd> fromCommandLineArgs(
List<String> args, {
AtClient? atClient,
FutureOr<AtClient> Function(SshnpdParams)? atClientGenerator,
void Function(Object, StackTrace)? usageCallback,
required String version,
}) async {
return SshnpdImpl.fromCommandLineArgs(
args,
atClient: atClient,
atClientGenerator: atClientGenerator,
usageCallback: usageCallback,
version: version,
);
}

Expand Down
51 changes: 33 additions & 18 deletions packages/dart/noports_core/lib/src/sshnpd/sshnpd_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,17 @@ class SshnpdImpl implements Sshnpd {
@visibleForTesting
bool initialized = false;

/// The version of whatever program is using this library.
@override
final String version;

/// State variables used by [_notificationHandler]
String _privateKey = '';

static const String commandToSend = 'sshd';

late final Map<String, dynamic> pingResponse;

SshnpdImpl({
// final fields
required this.atClient,
Expand All @@ -79,17 +85,37 @@ class SshnpdImpl implements Sshnpd {
this.localSshdPort = DefaultArgs.localSshdPort,
required this.ephemeralPermissions,
required this.sshAlgorithm,
required this.version,
}) {
logger.hierarchicalLoggingEnabled = true;
logger.logger.level = Level.SHOUT;

pingResponse = {
'devicename': device,
'version': version,
'corePackageVersion': packageVersion,
'supportedFeatures': {
DaemonFeatures.srAuth.name: true,
DaemonFeatures.srE2ee.name: true,
DaemonFeatures.acceptsPublicKeys.name: addSshPublicKeys,
},
};
}

static Future<Sshnpd> fromCommandLineArgs(List<String> args,
{AtClient? atClient,
FutureOr<AtClient> Function(SshnpdParams)? atClientGenerator,
void Function(Object, StackTrace)? usageCallback}) async {
static Future<Sshnpd> fromCommandLineArgs(
List<String> args, {
AtClient? atClient,
FutureOr<AtClient> Function(SshnpdParams)? atClientGenerator,
void Function(Object, StackTrace)? usageCallback,
required String version,
}) async {
try {
var p = await SshnpdParams.fromArgs(args);
SshnpdParams p;
try {
p = await SshnpdParams.fromArgs(args);
} on FormatException catch (e) {
throw ArgumentError(e.message);
}

// Check atKeyFile selected exists
if (!await File(p.atKeysFilePath).exists()) {
Expand Down Expand Up @@ -119,6 +145,7 @@ class SshnpdImpl implements Sshnpd {
localSshdPort: p.localSshdPort,
ephemeralPermissions: p.ephemeralPermissions,
sshAlgorithm: p.sshAlgorithm,
version: version,
);

if (p.verbose) {
Expand Down Expand Up @@ -303,15 +330,6 @@ class SshnpdImpl implements Sshnpd {
..namespaceAware = true);

/// send a heartbeat back
var pingResponse = {
'devicename': device,
'version': packageVersion,
'supportedFeatures': {
DaemonFeatures.srAuth.name: true,
DaemonFeatures.srE2ee.name: true,
DaemonFeatures.acceptsPublicKeys.name: addSshPublicKeys,
},
};
unawaited(
_notify(
atKey: atKey,
Expand Down Expand Up @@ -990,10 +1008,7 @@ class SshnpdImpl implements Sshnpd {
logger.info('Updating device info for $device');
await atClient.put(
atKey,
jsonEncode({
'devicename': device,
'version': packageVersion,
}),
jsonEncode(pingResponse),
putRequestOptions: PutRequestOptions()..useRemoteAtServer = true,
);
} catch (e) {
Expand Down
2 changes: 1 addition & 1 deletion packages/dart/noports_core/lib/src/version.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/dart/noports_core/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: noports_core
description: Core library code for sshnoports
homepage: https://docs.atsign.com/

version: 5.1.0
version: 6.0.0

environment:
sdk: ">=3.0.0 <4.0.0"
Expand Down
93 changes: 57 additions & 36 deletions packages/dart/sshnoports/bin/srv.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,52 +3,73 @@ import 'dart:io';
import 'package:args/args.dart';
import 'package:noports_core/srv.dart';
import 'package:socket_connector/socket_connector.dart';
import 'package:sshnoports/src/print_version.dart';

Future<void> main(List<String> args) async {
final ArgParser parser = ArgParser()
..addOption('host', abbr: 'h', mandatory: true, help: 'rvd host')
..addOption('port', abbr: 'p', mandatory: true, help: 'rvd port')
..addOption('local-port',
..addOption(
'host', abbr: 'h', mandatory: true, help: 'rvd host')..addOption(
'port', abbr: 'p', mandatory: true, help: 'rvd port')..addOption(
'local-port',
defaultsTo: '22',
help: 'Local port (usually the sshd port) to bridge to; defaults to 22')
..addFlag('bind-local-port',
defaultsTo: false,
negatable: false,
help: 'Set this flag when we are bridging from a local sender')
..addFlag('rv-auth',
help: 'Set this flag when we are bridging from a local sender')..addFlag(
'rv-auth',
defaultsTo: false,
help: 'Whether this rv process will authenticate to rvd')
..addFlag('rv-e2ee',
help: 'Whether this rv process will authenticate to rvd')..addFlag(
'rv-e2ee',
defaultsTo: false,
help: 'Whether this rv process will encrypt/decrypt'
' all rvd socket traffic');
final parsed = parser.parse(args);

final String host = parsed['host'];
final int streamingPort = int.parse(parsed['port']);
final int localPort = int.parse(parsed['local-port']);
final bool bindLocalPort = parsed['bind-local-port'];
final bool rvAuth = parsed['rv-auth'];
final bool rvE2ee = parsed['rv-e2ee'];

String? rvdAuthString = rvAuth ? Platform.environment['RV_AUTH'] : null;
String? sessionAESKeyString = rvE2ee ? Platform.environment['RV_AES'] : null;
String? sessionIVString = rvE2ee ? Platform.environment['RV_IV'] : null;

SocketConnector connector = await Srv.dart(
host,
streamingPort,
localPort: localPort,
bindLocalPort: bindLocalPort,
rvdAuthString: rvdAuthString,
sessionAESKeyString: sessionAESKeyString,
sessionIVString: sessionIVString,
).run();

/// Shut myself down once the socket connector closes
stderr.writeln('Waiting for connector to close');
await connector.done;

stderr.writeln('Closed - exiting');
exit(0);

try {
final ArgResults parsed;
try {
parsed = parser.parse(args);
} on FormatException catch (e) {
throw ArgumentError(e.message);
}

final String host = parsed['host'];
final int streamingPort = int.parse(parsed['port']);
final int localPort = int.parse(parsed['local-port']);
final bool bindLocalPort = parsed['bind-local-port'];
final bool rvAuth = parsed['rv-auth'];
final bool rvE2ee = parsed['rv-e2ee'];

String? rvdAuthString = rvAuth ? Platform.environment['RV_AUTH'] : null;
String? sessionAESKeyString = rvE2ee
? Platform.environment['RV_AES']
: null;
String? sessionIVString = rvE2ee ? Platform.environment['RV_IV'] : null;

if (rvAuth && (rvdAuthString ?? '').isEmpty) {
throw ArgumentError(
'--rv-auth required, but RV_AUTH is not in environment');
}
SocketConnector connector = await Srv.dart(
host,
streamingPort,
localPort: localPort,
bindLocalPort: bindLocalPort,
rvdAuthString: rvdAuthString,
sessionAESKeyString: sessionAESKeyString,
sessionIVString: sessionIVString,
).run();

/// Shut myself down once the socket connector closes
stderr.writeln('Waiting for connector to close');
await connector.done;

stderr.writeln('Closed - exiting');
exit(0);
} on ArgumentError catch (e) {
printVersion();
stderr.writeln(parser.usage);
stderr.writeln('\n$e');
exit(1);
}
}
2 changes: 1 addition & 1 deletion packages/dart/sshnoports/bin/srvd.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ void main(List<String> args) async {
),
usageCallback: (e, s) {
printVersion();
stdout.writeln(SrvdParams.parser.usage);
stderr.writeln(SrvdParams.parser.usage);
stderr.writeln('\n$e');
},
);
Expand Down
4 changes: 3 additions & 1 deletion packages/dart/sshnoports/bin/sshnpd.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:at_utils/at_logger.dart';
import 'package:noports_core/sshnpd.dart';
import 'package:sshnoports/src/create_at_client_cli.dart';
import 'package:sshnoports/src/print_version.dart';
import 'package:sshnoports/src/version.dart';

void main(List<String> args) async {
AtSignLogger.root_level = 'SHOUT';
Expand All @@ -22,9 +23,10 @@ void main(List<String> args) async {
),
usageCallback: (e, s) {
printVersion();
stdout.writeln(SshnpdParams.parser.usage);
stderr.writeln(SshnpdParams.parser.usage);
stderr.writeln('\n$e');
},
version: packageVersion,
);
} on ArgumentError catch (_) {
exit(1);
Expand Down
2 changes: 1 addition & 1 deletion packages/dart/sshnoports/lib/src/print_devices.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ void printDeviceList(Iterable<String> devices, Map<String, dynamic> info) {
return;
}
for (var device in devices) {
stderr.writeln(' $device - v${info[device]?['version']}');
stderr.writeln(' $device - v${info[device]?['version']} (core v${info[device]?['corePackageVersion']})');
}
}
2 changes: 1 addition & 1 deletion packages/dart/sshnoports/lib/src/print_version.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import 'package:sshnoports/src/version.dart';

/// Print version number
void printVersion() {
stdout.writeln('Version : $packageVersion');
stderr.writeln('Version : $packageVersion');
}
2 changes: 1 addition & 1 deletion packages/dart/sshnoports/lib/src/version.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/dart/sshnoports/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ packages:
path: "../noports_core"
relative: true
source: path
version: "5.1.0"
version: "6.0.0"
openssh_ed25519:
dependency: transitive
description:
Expand Down
4 changes: 2 additions & 2 deletions packages/dart/sshnoports/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
name: sshnoports
publish_to: none

version: 4.1.0
version: 5.0.0

environment:
sdk: ">=3.0.0 <4.0.0"

dependencies:
noports_core: 5.1.0
noports_core: 6.0.0
at_onboarding_cli: 1.4.1
args: 2.4.2
socket_connector: ^2.0.1
Expand Down
Loading

0 comments on commit d5c4aad

Please sign in to comment.