diff --git a/docs/sshnp_class_diagrams.md b/docs/sshnp_class_diagrams.md deleted file mode 100644 index 8ab774f63..000000000 --- a/docs/sshnp_class_diagrams.md +++ /dev/null @@ -1,582 +0,0 @@ -# SSHNP Class Diagrams - -Table of contents: -- [SSHNP Class Diagrams](#sshnp-class-diagrams) - - [SSHNP Family (basic)](#sshnp-family-basic) - - [SSHNP Family (with mixins)](#sshnp-family-with-mixins) - - [SSHNPResult Family](#sshnpresult-family) - - [Near Full Diagram (Generated and Stripped)](#near-full-diagram-generated-and-stripped) - - [Full Diagram (Generated)](#full-diagram-generated) - - -## SSHNP Family (basic) - -```mermaid -classDiagram - class SSHNP { - <> - } - - class SSHNPCore { - <> - } - - class SSHNPForward { - <> - } - - class SSHNPForwardDart { - <> - } - - class SSHNPForwardDartPureImpl - class SSHNPForwardDartLocalImpl - class SSHNPForwardExecImpl - - class SSHNPReverse { - <> - } - - class SSHNPReverseImpl - class SSHNPLegacyImpl - - - SSHNP <|.. SSHNPCore - SSHNPCore <|-- SSHNPForward - SSHNPForward <|-- SSHNPForwardDart - SSHNPForwardDart <|-- SSHNPForwardDartPureImpl - SSHNPForwardDart <|-- SSHNPForwardDartLocalImpl - SSHNPForward <|-- SSHNPForwardExecImpl - SSHNPCore <|-- SSHNPReverse - SSHNPReverse <|-- SSHNPReverseImpl - SSHNPReverse <|-- SSHNPLegacyImpl -``` - -## SSHNP Family (with mixins) - -```mermaid -classDiagram - namespace SSHNPNamespace { - class SSHNP { - <> - } - - class SSHNPCore { - <> - } - - class SSHNPForward { - <> - } - - class SSHNPForwardDart { - <> - } - - class SSHNPForwardDartPureImpl - class SSHNPForwardDartLocalImpl - class SSHNPForwardExecImpl - - class SSHNPReverse { - <> - } - - class SSHNPReverseImpl - class SSHNPLegacyImpl - } - - SSHNP <|.. SSHNPCore - SSHNPCore <|-- SSHNPForward - SSHNPForward <|-- SSHNPForwardDart - SSHNPForwardDart <|-- SSHNPForwardDartPureImpl - SSHNPForwardDart <|-- SSHNPForwardDartLocalImpl - SSHNPForward <|-- SSHNPForwardExecImpl - SSHNPCore <|-- SSHNPReverse - SSHNPReverse <|-- SSHNPReverseImpl - SSHNPReverse <|-- SSHNPLegacyImpl - - namespace PayLoadHandlers { - class DefaultSSHNPDPayloadHandler { - <> - } - - class LegacySSHNPDPayloadHandler { - <> - } - } - - namespace SSHKeyHandlers { - class SSHNPLocalSSHKeyHandler { - <> - } - - class SSHNPDartSSHKeyHandler { - <> - } - } - - DefaultSSHNPDPayloadHandler <|-- SSHNPForwardDart - DefaultSSHNPDPayloadHandler <|-- SSHNPForwardExecImpl - DefaultSSHNPDPayloadHandler <|-- SSHNPReverseImpl - LegacySSHNPDPayloadHandler <|-- SSHNPLegacyImpl - SSHNPLocalSSHKeyHandler <|-- SSHNPForwardDartLocalImpl - SSHNPLocalSSHKeyHandler <|-- SSHNPForwardExecImpl - SSHNPLocalSSHKeyHandler <|-- SSHNPReverse - SSHNPDartSSHKeyHandler <|-- SSHNPForwardDartPureImpl -``` - -## SSHNPResult Family - -```mermaid -classDiagram - SSHNPResult <|.. SSHNPSuccess - SSHNPResult <|.. SSHNPFailure - - SSHNPFailure <|.. SSHNPError - Exception <|.. SSHNPError - - SSHNPSuccess <|.. SSHNPNoOpSuccess - SSHNPSuccess <|.. SSHNPCommand - - SSHNPCommand *-- SSHNPConnectionBean - class SSHNPResult { - <> - } - class SSHNPConnectionBean { - <> - } - class SSHNPNoOpSuccess { - Needed for pure dart since it doesn't output a command - } -``` - - -## Near Full Diagram (Generated and Stripped) - -```mermaid -classDiagram - class SSHNPReverseImpl - SSHNPReverse <|-- SSHNPReverseImpl - DefaultSSHNPDPayloadHandler <|-- SSHNPReverseImpl - - class SSHNPReverse - <> SSHNPReverse - SSHNPReverse o-- SSHRV - SSHNPReverse o-- AtSSHKeyPair - SSHNPCore <|-- SSHNPReverse - SSHNPLocalSSHKeyHandler <|-- SSHNPReverse - - class SSHNPLegacyImpl - SSHNPReverse <|-- SSHNPLegacyImpl - LegacySSHNPDPayloadHandler <|-- SSHNPLegacyImpl - - class DefaultSSHNPDPayloadHandler - <> DefaultSSHNPDPayloadHandler - - class LegacySSHNPDPayloadHandler - <> LegacySSHNPDPayloadHandler - - class SSHNPLocalSSHKeyHandler - <> SSHNPLocalSSHKeyHandler - SSHNPLocalSSHKeyHandler o-- LocalSSHKeyUtil - SSHNPLocalSSHKeyHandler o-- AtSSHKeyPair - - class SSHNPDartSSHKeyHandler - <> SSHNPDartSSHKeyHandler - SSHNPDartSSHKeyHandler o-- DartSSHKeyUtil - - class SSHNPCore - <> SSHNPCore - SSHNPCore o-- AtClient - SSHNPCore o-- SSHNPParams - SSHNPCore o-- AtSSHKeyUtil - SSHNP <|.. SSHNPCore - - class SSHNPForward - <> SSHNPForward - SSHNPCore <|-- SSHNPForward - - class SSHNPForwardDartLocalImpl - SSHNPForwardDart <|-- SSHNPForwardDartLocalImpl - SSHNPLocalSSHKeyHandler <|-- SSHNPForwardDartLocalImpl - - class SSHNPForwardDartPureImpl - SSHNPForwardDartPureImpl o-- AtSSHKeyPair - SSHNPForwardDartPureImpl o-- AtSSHKeyPair - SSHNPForwardDart <|-- SSHNPForwardDartPureImpl - SSHNPDartSSHKeyHandler <|-- SSHNPForwardDartPureImpl - - class SSHNPForwardExecImpl - SSHNPForwardExecImpl o-- AtSSHKeyPair - SSHNPForward <|-- SSHNPForwardExecImpl - SSHNPLocalSSHKeyHandler <|-- SSHNPForwardExecImpl - DefaultSSHNPDPayloadHandler <|-- SSHNPForwardExecImpl - - class SSHNPForwardDart - <> SSHNPForwardDart - SSHNPForward <|-- SSHNPForwardDart - DefaultSSHNPDPayloadHandler <|-- SSHNPForwardDart - - class SSHNPResult - <> SSHNPResult - - class SSHNPSuccess - SSHNPResult <|.. SSHNPSuccess - - class SSHNPFailure - SSHNPResult <|.. SSHNPFailure - - class SSHNPError - SSHNPFailure <|.. SSHNPError - Exception <|.. SSHNPError - - class SSHNPCommand - SSHNPSuccess <|-- SSHNPCommand - SSHNPConnectionBean <|-- SSHNPCommand - - class SSHNPNoOpSuccess - SSHNPSuccess <|-- SSHNPNoOpSuccess - SSHNPConnectionBean <|-- SSHNPNoOpSuccess - - class SSHNPConnectionBean - <> SSHNPConnectionBean - - class SSHNP - SSHNP o-- AtClient - SSHNP o-- SSHNPParams -``` - -## Full Diagram (Generated) -```mermaid -classDiagram - class SSHNPReverseImpl - SSHNPReverseImpl : +init() dynamic - SSHNPReverseImpl : +run() dynamic - SSHNPReverse <|-- SSHNPReverseImpl - DefaultSSHNPDPayloadHandler <|-- SSHNPReverseImpl - - class SSHNPReverse - <> SSHNPReverse - SSHNPReverse : +sshrvGenerator SSHRV - SSHNPReverse o-- SSHRV - SSHNPReverse : +ephemeralKeyPair AtSSHKeyPair - SSHNPReverse o-- AtSSHKeyPair - SSHNPReverse : +localUsername String - SSHNPReverse : +usingSshrv bool - SSHNPReverse : +init() dynamic - SSHNPReverse : +cleanUp() dynamic - SSHNPCore <|-- SSHNPReverse - SSHNPLocalSSHKeyHandler <|-- SSHNPReverse - - class SSHNPLegacyImpl - SSHNPLegacyImpl : +init() dynamic - SSHNPLegacyImpl : +run() dynamic - SSHNPReverse <|-- SSHNPLegacyImpl - LegacySSHNPDPayloadHandler <|-- SSHNPLegacyImpl - - class DefaultSSHNPDPayloadHandler - <> DefaultSSHNPDPayloadHandler - DefaultSSHNPDPayloadHandler : #ephemeralPrivateKey String - DefaultSSHNPDPayloadHandler : +useLocalFileStorage bool - DefaultSSHNPDPayloadHandler : +handleSshnpdPayload() FutureOr - - class LegacySSHNPDPayloadHandler - <> LegacySSHNPDPayloadHandler - LegacySSHNPDPayloadHandler : +handleSshnpdPayload() bool - - class SSHNPLocalSSHKeyHandler - <> SSHNPLocalSSHKeyHandler - SSHNPLocalSSHKeyHandler : -_sshKeyUtil LocalSSHKeyUtil - SSHNPLocalSSHKeyHandler o-- LocalSSHKeyUtil - SSHNPLocalSSHKeyHandler : -_identityKeyPair AtSSHKeyPair? - SSHNPLocalSSHKeyHandler o-- AtSSHKeyPair - SSHNPLocalSSHKeyHandler : +keyUtil LocalSSHKeyUtil - SSHNPLocalSSHKeyHandler o-- LocalSSHKeyUtil - SSHNPLocalSSHKeyHandler : +identityKeyPair AtSSHKeyPair? - SSHNPLocalSSHKeyHandler o-- AtSSHKeyPair - SSHNPLocalSSHKeyHandler : +init() dynamic - - class SSHNPDartSSHKeyHandler - <> SSHNPDartSSHKeyHandler - SSHNPDartSSHKeyHandler : -_sshKeyUtil DartSSHKeyUtil - SSHNPDartSSHKeyHandler o-- DartSSHKeyUtil - SSHNPDartSSHKeyHandler : +keyUtil DartSSHKeyUtil - SSHNPDartSSHKeyHandler o-- DartSSHKeyUtil - - class SSHNPCore - <> SSHNPCore - SSHNPCore : +logger AtSignLogger - SSHNPCore o-- AtSignLogger - SSHNPCore : +atClient AtClient - SSHNPCore o-- AtClient - SSHNPCore : +params SSHNPParams - SSHNPCore o-- SSHNPParams - SSHNPCore : +sessionId String - SSHNPCore : +remoteUsername String - SSHNPCore : +host String - SSHNPCore : +port int - SSHNPCore : +localPort int - SSHNPCore : +sshrvdPort int? - SSHNPCore : #doneCompleter Completer~void~ - SSHNPCore o-- Completer~void~ - SSHNPCore : -_initializeStarted bool - SSHNPCore : #initializedCompleter Completer~void~ - SSHNPCore o-- Completer~void~ - SSHNPCore : #sshnpdAck bool - SSHNPCore : #sshnpdAckErrors bool - SSHNPCore : +sshrvdAck bool - SSHNPCore : +identityKeyPair FutureOr~AtSSHKeyPair?~ - SSHNPCore : +done dynamic - SSHNPCore : +initializeStarted bool - SSHNPCore : +initialized dynamic - SSHNPCore : +clientAtSign String - SSHNPCore : +sshnpdAtSign String - SSHNPCore : +namespace String - SSHNPCore : +keyUtil AtSSHKeyUtil - SSHNPCore o-- AtSSHKeyUtil - SSHNPCore : +getNamespace()$ String - SSHNPCore : +init() dynamic - SSHNPCore : #completeInitialization() void - SSHNPCore : +handleSshnpdResponses() dynamic - SSHNPCore : #handleSshnpdPayload()* FutureOr - SSHNPCore : #startAndWaitForInit() dynamic - SSHNPCore : #notify() dynamic - SSHNPCore : #fetchRemoteUserName() dynamic - SSHNPCore : #getHostAndPortFromSshrvd() dynamic - SSHNPCore : #sharePublicKeyWithSshnpdIfRequired() dynamic - SSHNPCore : #waitForDaemonResponse() dynamic - SSHNPCore : #cleanUp() FutureOr - SSHNPCore : -_getAtKeysRemote() dynamic - SSHNPCore : +Future() dynamic - SSHNPCore : +() dynamic - SSHNPCore : +>() dynamic - SSHNPCore : +listDevices() dynamic - SSHNP <|.. SSHNPCore - - class SSHNPArg - SSHNPArg : +format ArgFormat - SSHNPArg o-- ArgFormat - SSHNPArg : +name String - SSHNPArg : +abbr String? - SSHNPArg : +help String? - SSHNPArg : +mandatory bool - SSHNPArg : +defaultsTo dynamic - SSHNPArg : +type ArgType - SSHNPArg o-- ArgType - SSHNPArg : +allowed Iterable~String~? - SSHNPArg : +parseWhen ParseWhen - SSHNPArg o-- ParseWhen - SSHNPArg : +aliases List~String~? - SSHNPArg : +negatable bool - SSHNPArg : +hide bool - SSHNPArg : +args$ List~SSHNPArg~ - SSHNPArg : +profileNameArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +helpArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +keyFileArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +fromArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +toArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +deviceArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +hostArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +portArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +localPortArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +identityFileArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +identityPassphraseArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +sendSshPublicKeyArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +localSshOptionsArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +verboseArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +remoteUserNameArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +rootDomainArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +localSshdPortArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +legacyDaemonArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +remoteSshdPortArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +idleTimeoutArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +sshClientArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +ssHAlgorithmArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +addForwardsToTunnelArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +configFileArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +listDevicesArg$ SSHNPArg - SSHNPArg o-- SSHNPArg - SSHNPArg : +bashName String - SSHNPArg : +aliasList List~String~ - SSHNPArg : +toString() String - SSHNPArg : +createArgParser()$ ArgParser - - class SSHNPParams - SSHNPParams : +clientAtSign String - SSHNPParams : +sshnpdAtSign String - SSHNPParams : +host String - SSHNPParams : +device String - SSHNPParams : +port int - SSHNPParams : +localPort int - SSHNPParams : +identityFile String? - SSHNPParams : +identityPassphrase String? - SSHNPParams : +sendSshPublicKey bool - SSHNPParams : +localSshOptions List~String~ - SSHNPParams : +remoteUsername String? - SSHNPParams : +verbose bool - SSHNPParams : +rootDomain String - SSHNPParams : +localSshdPort int - SSHNPParams : +legacyDaemon bool - SSHNPParams : +remoteSshdPort int - SSHNPParams : +idleTimeout int - SSHNPParams : +addForwardsToTunnel bool - SSHNPParams : +atKeysFilePath String? - SSHNPParams : +sshClient SupportedSshClient - SSHNPParams o-- SupportedSshClient - SSHNPParams : +sshAlgorithm SupportedSSHAlgorithm - SSHNPParams o-- SupportedSSHAlgorithm - SSHNPParams : +profileName String? - SSHNPParams : +listDevices bool - SSHNPParams : +toConfigLines() List - SSHNPParams : +toArgMap() Map - SSHNPParams : +toJson() String - - class SSHNPPartialParams - SSHNPPartialParams : +profileName String? - SSHNPPartialParams : +clientAtSign String? - SSHNPPartialParams : +sshnpdAtSign String? - SSHNPPartialParams : +host String? - SSHNPPartialParams : +device String? - SSHNPPartialParams : +port int? - SSHNPPartialParams : +localPort int? - SSHNPPartialParams : +localSshdPort int? - SSHNPPartialParams : +atKeysFilePath String? - SSHNPPartialParams : +identityFile String? - SSHNPPartialParams : +identityPassphrase String? - SSHNPPartialParams : +sendSshPublicKey bool? - SSHNPPartialParams : +localSshOptions List~String~? - SSHNPPartialParams : +remoteUsername String? - SSHNPPartialParams : +verbose bool? - SSHNPPartialParams : +rootDomain String? - SSHNPPartialParams : +legacyDaemon bool? - SSHNPPartialParams : +remoteSshdPort int? - SSHNPPartialParams : +idleTimeout int? - SSHNPPartialParams : +addForwardsToTunnel bool? - SSHNPPartialParams : +sshClient SupportedSshClient? - SSHNPPartialParams o-- SupportedSshClient - SSHNPPartialParams : +sshAlgorithm SupportedSSHAlgorithm? - SSHNPPartialParams o-- SupportedSSHAlgorithm - SSHNPPartialParams : +listDevices bool? - - class SSHNPForward - <> SSHNPForward - SSHNPForward : -_sshrvdPort int - SSHNPForward : +sshrvdPort int - SSHNPForward : +requestSocketTunnelFromDaemon() dynamic - SSHNPCore <|-- SSHNPForward - - class SSHNPForwardDartLocalImpl - SSHNPForwardDartLocalImpl : +init() dynamic - SSHNPForwardDartLocalImpl : +run() dynamic - SSHNPForwardDart <|-- SSHNPForwardDartLocalImpl - SSHNPLocalSSHKeyHandler <|-- SSHNPForwardDartLocalImpl - - class SSHNPForwardDartPureImpl - SSHNPForwardDartPureImpl : -_identityKeyPair AtSSHKeyPair - SSHNPForwardDartPureImpl o-- AtSSHKeyPair - SSHNPForwardDartPureImpl : +identityKeyPair AtSSHKeyPair - SSHNPForwardDartPureImpl o-- AtSSHKeyPair - SSHNPForwardDartPureImpl : +init() dynamic - SSHNPForwardDartPureImpl : +run() dynamic - SSHNPForwardDart <|-- SSHNPForwardDartPureImpl - SSHNPDartSSHKeyHandler <|-- SSHNPForwardDartPureImpl - - class SSHNPForwardExecImpl - SSHNPForwardExecImpl : +ephemeralKeyPair AtSSHKeyPair - SSHNPForwardExecImpl o-- AtSSHKeyPair - SSHNPForwardExecImpl : +init() dynamic - SSHNPForwardExecImpl : +run() dynamic - SSHNPForward <|-- SSHNPForwardExecImpl - SSHNPLocalSSHKeyHandler <|-- SSHNPForwardExecImpl - DefaultSSHNPDPayloadHandler <|-- SSHNPForwardExecImpl - - class SSHNPForwardDart - <> SSHNPForwardDart - SSHNPForwardDart : +terminateMessage String - SSHNPForwardDart : #startInitialTunnel() dynamic - SSHNPForward <|-- SSHNPForwardDart - DefaultSSHNPDPayloadHandler <|-- SSHNPForwardDart - - class SSHNPResult - <> SSHNPResult - - class SSHNPSuccess - SSHNPResult <|.. SSHNPSuccess - - class SSHNPFailure - SSHNPResult <|.. SSHNPFailure - - class SSHNPError - SSHNPError : +message Object - SSHNPError : +error Object? - SSHNPError : +stackTrace StackTrace? - SSHNPError : +toString() String - SSHNPError : +toVerboseString() String - SSHNPFailure <|.. SSHNPError - Exception <|.. SSHNPError - - class SSHNPCommand - SSHNPCommand : +command String - SSHNPCommand : +localPort int - SSHNPCommand : +remoteUsername String? - SSHNPCommand : +host String - SSHNPCommand : +privateKeyFileName String? - SSHNPCommand : +sshOptions List~String~ - SSHNPCommand : +args List~String~ - SSHNPCommand : +shouldIncludePrivateKey()$ bool - SSHNPCommand : +toString() String - SSHNPSuccess <|-- SSHNPCommand - SSHNPConnectionBean <|-- SSHNPCommand - - class SSHNPNoOpSuccess - SSHNPNoOpSuccess : +message String? - SSHNPNoOpSuccess : +toString() String - SSHNPSuccess <|-- SSHNPNoOpSuccess - SSHNPConnectionBean <|-- SSHNPNoOpSuccess - - class SSHNPConnectionBean - <> SSHNPConnectionBean - SSHNPConnectionBean : -_connectionBean Bean? - SSHNPConnectionBean : +connectionBean Bean? - SSHNPConnectionBean : +killConnectionBean() dynamic - - class SSHNP - SSHNP : +atClient AtClient - SSHNP o-- AtClient - SSHNP : +params SSHNPParams - SSHNP o-- SSHNPParams - SSHNP : +done dynamic - SSHNP : +initialized dynamic - SSHNP : +fromParamsWithFileBindings()$ dynamic - SSHNP : +init()* dynamic - SSHNP : +run()* dynamic - SSHNP : +FutureOr() dynamic - SSHNP : +() dynamic - SSHNP : +>() dynamic - SSHNP : +listDevices()* dynamic - -``` \ No newline at end of file diff --git a/packages/noports_core/lib/src/common/default_args.dart b/packages/noports_core/lib/src/common/default_args.dart index 1af701dd8..2cb6274f0 100644 --- a/packages/noports_core/lib/src/common/default_args.dart +++ b/packages/noports_core/lib/src/common/default_args.dart @@ -8,11 +8,11 @@ class DefaultArgs { static const SupportedSshAlgorithm sshAlgorithm = SupportedSshAlgorithm.ed25519; static const bool verbose = false; - static const SupportedSshAlgorithm algorithm = SupportedSshAlgorithm.ed25519; static const String rootDomain = 'root.atsign.org'; static const SshrvGenerator sshrvGenerator = Sshrv.exec; static const int localSshdPort = 22; static const int remoteSshdPort = 22; + /// value in seconds after which idle ssh tunnels will be closed static const int idleTimeout = 15; static const bool help = false; diff --git a/packages/noports_core/lib/src/common/mixins/async_initialization.dart b/packages/noports_core/lib/src/common/mixins/async_initialization.dart index e1108dad9..f4c38fd52 100644 --- a/packages/noports_core/lib/src/common/mixins/async_initialization.dart +++ b/packages/noports_core/lib/src/common/mixins/async_initialization.dart @@ -24,6 +24,7 @@ mixin class AsyncInitialization { /// To be called by the class that implements this mixin /// to ensure that [initialize] is only called once + @visibleForTesting @protected Future callInitialization() async { if (!_initializeStarted) { @@ -43,6 +44,7 @@ mixin class AsyncInitialization { /// /// hint: call [isSafeToInitialize] at the beginning of this method /// to ensure that initialization is not done more than once + @visibleForTesting @visibleForOverriding @protected Future initialize() async {} @@ -50,6 +52,7 @@ mixin class AsyncInitialization { /// To be called by the class that implements this mixin /// to signal completion of the initialization process /// hint: call this in the last line of [initialize] + @visibleForTesting @protected void completeInitialization() { if (isSafeToInitialize) _initializedCompleter.complete(); diff --git a/packages/noports_core/lib/src/sshnp/sshnp_core.dart b/packages/noports_core/lib/src/sshnp/sshnp_core.dart index cd8206208..3ece92d13 100644 --- a/packages/noports_core/lib/src/sshnp/sshnp_core.dart +++ b/packages/noports_core/lib/src/sshnp/sshnp_core.dart @@ -5,7 +5,6 @@ import 'dart:io'; import 'package:at_client/at_client.dart' hide StringBuffer; import 'package:at_utils/at_logger.dart'; -import 'package:logging/logging.dart'; import 'package:meta/meta.dart'; import 'package:noports_core/src/common/mixins/async_completion.dart'; import 'package:noports_core/src/common/mixins/async_initialization.dart'; @@ -24,7 +23,7 @@ abstract class SshnpCore // * AtClientBindings members /// The logger for this class @override - final AtSignLogger logger = AtSignLogger(' SshnpCore '); + final AtSignLogger logger = AtSignLogger('Sshnp'); /// The [AtClient] to use for this instance @override @@ -54,7 +53,7 @@ abstract class SshnpCore /// The channel to communicate with the sshrvd (host) @protected - SshrvdChannel? get sshrvdChannel; + SshrvdChannel get sshrvdChannel; /// The channel to communicate with the sshnpd (daemon) @protected @@ -66,14 +65,7 @@ abstract class SshnpCore }) : sessionId = Uuid().v4(), namespace = '${params.device}.sshnp', localPort = params.localPort { - /// Set the logger level to shout - logger.hierarchicalLoggingEnabled = true; - logger.logger.level = Level.SHOUT; - - if (params.verbose) { - logger.logger.level = Level.INFO; - AtSignLogger.root_level = 'info'; - } + logger.level = params.verbose ? 'info' : 'shout'; /// Set the namespace to the device's namespace AtClientPreference preference = @@ -95,13 +87,13 @@ abstract class SshnpCore remoteUsername = await sshnpdChannel.resolveRemoteUsername(); /// Find a spare local port if required - await _findLocalPortIfRequired(); + await findLocalPortIfRequired(); /// Shares the public key if required await sshnpdChannel.sharePublicKeyIfRequired(identityKeyPair); /// Retrieve the sshrvd host and port pair - await sshrvdChannel?.callInitialization(); + await sshrvdChannel.callInitialization(); } @override @@ -109,7 +101,8 @@ abstract class SshnpCore completeDisposal(); } - Future _findLocalPortIfRequired() async { + @visibleForTesting + Future findLocalPortIfRequired() async { // TODO investigate if this is a problem on mobile // find a spare local port if (localPort == 0) { 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 b8f40c9ba..f163bffbc 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 @@ -18,19 +18,19 @@ mixin SshnpDartInitialTunnelHandler on SshnpCore // If we are starting an initial tunnel, it should be to sshrvd, // so it is safe to assume that sshrvdChannel is not null here logger.info( - 'Starting direct ssh session to ${sshrvdChannel!.host} on port ${sshrvdChannel!.sshrvdPort} with forwardLocal of $localPort'); + 'Starting direct ssh session to ${sshrvdChannel.host} on port ${sshrvdChannel.sshrvdPort} with forwardLocal of $localPort'); try { late final SSHClient client; late final SSHSocket socket; try { socket = await SSHSocket.connect( - sshrvdChannel!.host, - sshrvdChannel!.sshrvdPort!, + sshrvdChannel.host, + sshrvdChannel.sshrvdPort!, ).catchError((e) => throw e); } catch (e, s) { var error = SshnpError( - 'Failed to open socket to ${sshrvdChannel!.host}:${sshrvdChannel!.sshrvdPort} : $e', + 'Failed to open socket to ${sshrvdChannel.host}:${sshrvdChannel.sshrvdPort} : $e', error: e, stackTrace: s, ); @@ -47,7 +47,7 @@ mixin SshnpDartInitialTunnelHandler on SshnpCore ); } catch (e, s) { throw SshnpError( - 'Failed to create SSHClient for ${params.remoteUsername}@${sshrvdChannel!.host}:${sshrvdChannel!.sshrvdPort} : $e', + 'Failed to create SSHClient for ${params.remoteUsername}@${sshrvdChannel.host}:${sshrvdChannel.sshrvdPort} : $e', error: e, stackTrace: s, ); @@ -57,7 +57,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 ${params.remoteUsername}@${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 c36e6c141..f165efa52 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 @@ -12,8 +12,8 @@ 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}' - ' -p ${sshrvdChannel!.sshrvdPort}' + String argsString = '$remoteUsername@${sshrvdChannel.host}' + ' -p ${sshrvdChannel.sshrvdPort}' ' -i $identifier' ' -L $localPort:localhost:${params.remoteSshdPort}' ' -o LogLevel=VERBOSE' diff --git a/packages/noports_core/test/sshnp/sshnp_params/config_file_repository_test.dart b/packages/noports_core/test/sshnp/models/config_file_repository_test.dart similarity index 100% rename from packages/noports_core/test/sshnp/sshnp_params/config_file_repository_test.dart rename to packages/noports_core/test/sshnp/models/config_file_repository_test.dart diff --git a/packages/noports_core/test/sshnp/sshnp_params/config_key_repository_test.dart b/packages/noports_core/test/sshnp/models/config_key_repository_test.dart similarity index 100% rename from packages/noports_core/test/sshnp/sshnp_params/config_key_repository_test.dart rename to packages/noports_core/test/sshnp/models/config_key_repository_test.dart diff --git a/packages/noports_core/test/sshnp/sshnp_params/sshnp_arg_test.dart b/packages/noports_core/test/sshnp/models/sshnp_arg_test.dart similarity index 100% rename from packages/noports_core/test/sshnp/sshnp_params/sshnp_arg_test.dart rename to packages/noports_core/test/sshnp/models/sshnp_arg_test.dart diff --git a/packages/noports_core/test/sshnp/sshnp_params/sshnp_params_test.dart b/packages/noports_core/test/sshnp/models/sshnp_params_test.dart similarity index 100% rename from packages/noports_core/test/sshnp/sshnp_params/sshnp_params_test.dart rename to packages/noports_core/test/sshnp/models/sshnp_params_test.dart diff --git a/packages/noports_core/test/sshnp/sshnp_result_test.dart b/packages/noports_core/test/sshnp/models/sshnp_result_test.dart similarity index 100% rename from packages/noports_core/test/sshnp/sshnp_result_test.dart rename to packages/noports_core/test/sshnp/models/sshnp_result_test.dart diff --git a/packages/noports_core/test/sshnp/sshnp_core_constants.dart b/packages/noports_core/test/sshnp/sshnp_core_constants.dart new file mode 100644 index 000000000..183ea42df --- /dev/null +++ b/packages/noports_core/test/sshnp/sshnp_core_constants.dart @@ -0,0 +1,14 @@ +class TestingKeyPair { + static const public = 'ssh-ed25519 ' + 'AAAAC3NzaC1lZDI1NTE5AAAAIGoKAULs01V4Lqwdyz+IZLXkSfI+6HBJmFoAzCpRvoda ' + 'for-testing-do-not-use'; + + static const private = '''-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACBqCgFC7NNVeC6sHcs/iGS15EnyPuhwSZhaAMwqUb6HWgAAAKBJvoc+Sb6H +PgAAAAtzc2gtZWQyNTUxOQAAACBqCgFC7NNVeC6sHcs/iGS15EnyPuhwSZhaAMwqUb6HWg +AAAEBnVg+o0CCLV0NqeXy6A1+w236zA8D6lqFe2mmyZbRqpWoKAULs01V4Lqwdyz+IZLXk +SfI+6HBJmFoAzCpRvodaAAAAFmZvci10ZXN0aW5nLWRvLW5vdC11c2UBAgMEBQYH +-----END OPENSSH PRIVATE KEY----- +'''; +} diff --git a/packages/noports_core/test/sshnp/sshnp_core_mocks.dart b/packages/noports_core/test/sshnp/sshnp_core_mocks.dart new file mode 100644 index 000000000..75377aaae --- /dev/null +++ b/packages/noports_core/test/sshnp/sshnp_core_mocks.dart @@ -0,0 +1,108 @@ +import 'package:at_client/at_client.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:noports_core/sshnp_foundation.dart'; + +import 'sshnp_core_constants.dart'; + +/// Function Stubbing +abstract class FunctionCaller { + void call(); +} + +class FunctionStub extends Mock implements FunctionCaller {} + +/// Mocked Classes +class MockAtClient extends Mock implements AtClient {} + +class MockSshnpParams extends Mock implements SshnpParams {} + +class MockSshnpdChannel extends Mock implements SshnpdChannel {} + +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, + SshnpdChannel? sshnpdChannel, + SshrvdChannel? sshrvdChannel, + }) : _sshnpdChannel = sshnpdChannel, + _sshrvdChannel = sshrvdChannel; + + @override + Future initialize() async { + await super.initialize(); + completeInitialization(); + } + + @override + AtSshKeyPair? get identityKeyPair => _identityKeyPair; + final _identityKeyPair = + AtSshKeyPair.fromPem(TestingKeyPair.private, identifier: 'testing'); + + @override + AtSshKeyUtil get keyUtil => throw UnimplementedError(); + + @override + Future run() => throw UnimplementedError(); + + @override + SshnpdChannel get sshnpdChannel => + _sshnpdChannel ?? (throw UnimplementedError()); + final SshnpdChannel? _sshnpdChannel; + + @override + SshrvdChannel get sshrvdChannel => + _sshrvdChannel ?? (throw UnimplementedError()); + final SshrvdChannel? _sshrvdChannel; + + @override + Future findLocalPortIfRequired() { + _stubbedFindLocalPortIfRequired?.call(); + return super.findLocalPortIfRequired(); + } +} + +/// Stubbed mixin wrapper +mixin StubbedAsyncInitializationMixin on AsyncInitialization { + late FunctionStub _mockCallInitialization; + late FunctionStub _mockInitialize; + late FunctionStub _mockCompleteInitialization; + + void stubAsyncInitialization({ + required FunctionStub mockCallInitialization, + required FunctionStub mockInitialize, + required FunctionStub mockCompleteInitialization, + }) { + _mockCallInitialization = mockCallInitialization; + _mockInitialize = mockInitialize; + _mockCompleteInitialization = mockCompleteInitialization; + } + + @override + Future callInitialization() async { + _mockCallInitialization.call(); + return super.callInitialization(); + } + + @override + Future initialize() async { + _mockInitialize.call(); + await super.initialize(); + } + + @override + void completeInitialization() { + _mockCompleteInitialization.call(); + super.completeInitialization(); + } +} diff --git a/packages/noports_core/test/sshnp/sshnp_core_test.dart b/packages/noports_core/test/sshnp/sshnp_core_test.dart index 53584b581..40cc4ef3f 100644 --- a/packages/noports_core/test/sshnp/sshnp_core_test.dart +++ b/packages/noports_core/test/sshnp/sshnp_core_test.dart @@ -1,38 +1,167 @@ import 'package:at_client/at_client.dart'; -import 'package:noports_core/sshnp_params.dart'; +import 'package:at_utils/at_logger.dart'; +import 'package:logging/logging.dart'; +import 'package:noports_core/sshnp_foundation.dart'; import 'package:test/test.dart'; import 'package:mocktail/mocktail.dart'; -class MockAtClient extends Mock implements AtClient {} - -class MockSshnpParams extends Mock implements SshnpParams {} +import 'sshnp_core_mocks.dart'; void main() { - group('Sshnp Core', () { - late AtClient atClient; - late SshnpParams params; + group('SshnpCore', () { + /// Creation mocks + late AtClient mockAtClient; + late SshnpParams mockParams; + late SshnpdChannel mockSshnpdChannel; + late SshrvdChannel mockSshrvdChannel; + + /// Initialization stubs + late FunctionStub stubbedCallInitialization; + late FunctionStub stubbedInitialize; + late FunctionStub stubbedCompleteInitialization; + late FunctionStub stubbedFindLocalPortIfRequired; setUp(() { - atClient = MockAtClient(); - params = MockSshnpParams(); + /// Creation + mockAtClient = MockAtClient(); + mockParams = MockSshnpParams(); + mockSshnpdChannel = MockSshnpdChannel(); + mockSshrvdChannel = MockSshrvdChannel(); registerFallbackValue(AtClientPreference()); + + /// Initialization + stubbedCallInitialization = FunctionStub(); + stubbedInitialize = FunctionStub(); + stubbedCompleteInitialization = FunctionStub(); + stubbedFindLocalPortIfRequired = FunctionStub(); }); - test('Constructor - expect that the namespace is set based on params', () { - verifyNever(() => atClient.getPreferences()); - verifyNever(() => params.device); - verifyNever(() => atClient.setPreferences(any())); + /// When declaration setup for the constructor of [StubbedSshnpCore] + whenConstructor({bool verbose = false}) { + when(() => mockParams.device).thenReturn('mydevice'); + when(() => mockParams.localPort).thenReturn(0); + when(() => mockParams.verbose).thenReturn(verbose); + when(() => mockAtClient.getPreferences()).thenReturn(null); + when(() => mockAtClient.setPreferences(any())).thenReturn(null); + } - when(() => atClient.getPreferences()).thenReturn(null); - when(() => params.device).thenReturn('mydevice'); - when(() => atClient.setPreferences(any())).thenReturn(null); + /// When declaration setup for the initialization of [StubbedSshnpCore] + whenInitialization({AtSshKeyPair? identityKeyPair}) { + when(() => stubbedCallInitialization.call()).thenAnswer((_) async {}); + when(() => stubbedInitialize.call()).thenAnswer((_) async {}); + when(() => stubbedCompleteInitialization.call()).thenReturn(null); + when(() => stubbedFindLocalPortIfRequired.call()).thenReturn(null); -// TODO write a new MYSshnpCore class - // final sshnpCore = MySshnpCore(atClient: atClient, params: params); + when(() => mockSshnpdChannel.callInitialization()) + .thenAnswer((_) async {}); + when(() => mockSshnpdChannel.resolveRemoteUsername()) + .thenAnswer((_) async => 'myRemoteUsername'); + when(() => mockSshnpdChannel.sharePublicKeyIfRequired( + identityKeyPair ?? any())).thenAnswer((_) async {}); + when(() => mockSshrvdChannel.callInitialization()) + .thenAnswer((_) async {}); + } - // verify(() => atClient.getPreferences()).called(1); - // verify(() => params.device).called(1); - // verify(() => atClient.setPreferences(any())).called(1); - }); - }); + group('Constructor', () { + test('verbose=false', () { + whenConstructor(verbose: false); + + final sshnpCore = + StubbedSshnpCore(atClient: mockAtClient, params: mockParams); + + /// Expect that the namespace is set in the preferences + verify(() => mockAtClient.getPreferences()).called(1); + verify(() => mockParams.device).called(1); + verify(() => mockAtClient.setPreferences(any())).called(1); + + /// Expect that the logger is configured correctly + expect(sshnpCore.logger.logger.level, Level.SHOUT); + expect(AtSignLogger.root_level, 'info'); + }); // test verbose=false + + test('verbose=true', () { + whenConstructor(verbose: true); + + final sshnpCore = + StubbedSshnpCore(atClient: mockAtClient, params: mockParams); + + /// Expect that the namespace is set in the preferences + verify(() => mockAtClient.getPreferences()).called(1); + verify(() => mockParams.device).called(1); + verify(() => mockAtClient.setPreferences(any())).called(1); + + /// Expect that the logger is configured correctly + expect(sshnpCore.logger.logger.level, Level.INFO); + expect(AtSignLogger.root_level, 'info'); + }); // test verbose=true + }); // group Constructor + + group('Initialization', () { + setUp(() {}); + test('AsyncInitialization', () async { + whenConstructor(); + + final sshnpCore = StubbedSshnpCore( + atClient: mockAtClient, + params: mockParams, + sshnpdChannel: mockSshnpdChannel, + sshrvdChannel: mockSshrvdChannel, + ); + + /// Setup stubs for the mocks that are part of [MockAsyncInitializationMixin] + sshnpCore.stubAsyncInitialization( + mockCallInitialization: stubbedCallInitialization, + mockCompleteInitialization: stubbedCompleteInitialization, + 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); + + /// Using verify in order to guarantee that init cycle is correct + /// Some of the middle steps may be valid in another, but this tests + /// against the current implementation's order + verifyInOrder([ + () => stubbedCallInitialization.call(), + () => stubbedInitialize.call(), + () => mockSshnpdChannel.callInitialization(), + () => mockSshnpdChannel.resolveRemoteUsername(), + () => stubbedFindLocalPortIfRequired.call(), + () => mockSshnpdChannel + .sharePublicKeyIfRequired(sshnpCore.identityKeyPair), + () => mockSshrvdChannel.callInitialization(), + () => stubbedCompleteInitialization.call(), + ]); + + /// Ensure that no initialization steps are called twice + verifyNever(() => stubbedCallInitialization.call()); + verifyNever(() => stubbedInitialize.call()); + verifyNever(() => mockSshnpdChannel.callInitialization()); + verifyNever(() => mockSshnpdChannel.resolveRemoteUsername()); + verifyNever(() => stubbedFindLocalPortIfRequired.call()); + verifyNever(() => mockSshnpdChannel + .sharePublicKeyIfRequired(sshnpCore.identityKeyPair)); + verifyNever(() => mockSshrvdChannel.callInitialization()); + verifyNever(() => stubbedCompleteInitialization.call()); + + /// Ensure [initialize()] is not ran a second time if we call + /// [callInitialization()] a second time + await expectLater(sshnpCore.callInitialization(), completes); + verify(() => stubbedCallInitialization.call()).called(1); + verifyNever(() => stubbedInitialize.call()); + verifyNever(() => stubbedCompleteInitialization.call()); + verifyNever(() => stubbedFindLocalPortIfRequired.call()); + verifyNever(() => mockSshrvdChannel.callInitialization()); + }); + }); // group Initialization + }); // group SshnpCore }