From 1cc8d11d1c14c347cd302f8367571a63ad51055d Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Tue, 7 Nov 2023 19:28:27 -0500 Subject: [PATCH 01/13] refactor: organize tests to match new refactor tree structure --- .../{sshnp_params => models}/config_file_repository_test.dart | 0 .../{sshnp_params => models}/config_key_repository_test.dart | 0 .../test/sshnp/{sshnp_params => models}/sshnp_arg_test.dart | 0 .../test/sshnp/{sshnp_params => models}/sshnp_params_test.dart | 0 .../noports_core/test/sshnp/{ => models}/sshnp_result_test.dart | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename packages/noports_core/test/sshnp/{sshnp_params => models}/config_file_repository_test.dart (100%) rename packages/noports_core/test/sshnp/{sshnp_params => models}/config_key_repository_test.dart (100%) rename packages/noports_core/test/sshnp/{sshnp_params => models}/sshnp_arg_test.dart (100%) rename packages/noports_core/test/sshnp/{sshnp_params => models}/sshnp_params_test.dart (100%) rename packages/noports_core/test/sshnp/{ => models}/sshnp_result_test.dart (100%) 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 From 96332c50de6413ab452b18d20ce39545d21984d9 Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Wed, 8 Nov 2023 11:04:56 -0500 Subject: [PATCH 02/13] docs: remove old class diagrams --- docs/sshnp_class_diagrams.md | 582 ----------------------------------- 1 file changed, 582 deletions(-) delete mode 100644 docs/sshnp_class_diagrams.md 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 From 0cf3e403881bab31ce5d96a92f27f9ecc3cdd697 Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Wed, 8 Nov 2023 19:21:26 -0500 Subject: [PATCH 03/13] chore: make logger injectable for testing --- packages/noports_core/lib/src/sshnp/sshnp_core.dart | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/noports_core/lib/src/sshnp/sshnp_core.dart b/packages/noports_core/lib/src/sshnp/sshnp_core.dart index cd8206208..7bc515ede 100644 --- a/packages/noports_core/lib/src/sshnp/sshnp_core.dart +++ b/packages/noports_core/lib/src/sshnp/sshnp_core.dart @@ -24,7 +24,7 @@ abstract class SshnpCore // * AtClientBindings members /// The logger for this class @override - final AtSignLogger logger = AtSignLogger(' SshnpCore '); + final AtSignLogger logger; /// The [AtClient] to use for this instance @override @@ -63,15 +63,18 @@ abstract class SshnpCore SshnpCore({ required this.atClient, required this.params, + @visibleForTesting + AtSignLogger? logger, }) : sessionId = Uuid().v4(), namespace = '${params.device}.sshnp', - localPort = params.localPort { + localPort = params.localPort, + logger = logger ?? AtSignLogger('SshnpCore') { /// Set the logger level to shout - logger.hierarchicalLoggingEnabled = true; - logger.logger.level = Level.SHOUT; + this.logger.hierarchicalLoggingEnabled = true; + this.logger.logger.level = Level.SHOUT; if (params.verbose) { - logger.logger.level = Level.INFO; + this.logger.logger.level = Level.INFO; AtSignLogger.root_level = 'info'; } From a6de5e8e5db83f0ee1bac7f15991a4017b1c0d6f Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Wed, 8 Nov 2023 20:20:28 -0500 Subject: [PATCH 04/13] chore: simplify logger setup --- packages/noports_core/lib/src/sshnp/sshnp_core.dart | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/packages/noports_core/lib/src/sshnp/sshnp_core.dart b/packages/noports_core/lib/src/sshnp/sshnp_core.dart index 7bc515ede..40a211570 100644 --- a/packages/noports_core/lib/src/sshnp/sshnp_core.dart +++ b/packages/noports_core/lib/src/sshnp/sshnp_core.dart @@ -63,20 +63,13 @@ abstract class SshnpCore SshnpCore({ required this.atClient, required this.params, - @visibleForTesting - AtSignLogger? logger, + @visibleForTesting AtSignLogger? logger, }) : sessionId = Uuid().v4(), namespace = '${params.device}.sshnp', localPort = params.localPort, logger = logger ?? AtSignLogger('SshnpCore') { - /// Set the logger level to shout + this.logger.logger.level = params.verbose ? Level.INFO : Level.SHOUT; this.logger.hierarchicalLoggingEnabled = true; - this.logger.logger.level = Level.SHOUT; - - if (params.verbose) { - this.logger.logger.level = Level.INFO; - AtSignLogger.root_level = 'info'; - } /// Set the namespace to the device's namespace AtClientPreference preference = From 9bcc1c90e482c1224ec75735c50709d214fad43f Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Wed, 8 Nov 2023 20:21:21 -0500 Subject: [PATCH 05/13] chore: clean up logger --- packages/noports_core/lib/src/sshnp/sshnp_core.dart | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/noports_core/lib/src/sshnp/sshnp_core.dart b/packages/noports_core/lib/src/sshnp/sshnp_core.dart index 40a211570..21d68d238 100644 --- a/packages/noports_core/lib/src/sshnp/sshnp_core.dart +++ b/packages/noports_core/lib/src/sshnp/sshnp_core.dart @@ -24,7 +24,7 @@ abstract class SshnpCore // * AtClientBindings members /// The logger for this class @override - final AtSignLogger logger; + final AtSignLogger logger = AtSignLogger('Sshnp'); /// The [AtClient] to use for this instance @override @@ -63,13 +63,11 @@ abstract class SshnpCore SshnpCore({ required this.atClient, required this.params, - @visibleForTesting AtSignLogger? logger, }) : sessionId = Uuid().v4(), namespace = '${params.device}.sshnp', - localPort = params.localPort, - logger = logger ?? AtSignLogger('SshnpCore') { - this.logger.logger.level = params.verbose ? Level.INFO : Level.SHOUT; - this.logger.hierarchicalLoggingEnabled = true; + localPort = params.localPort { + logger.logger.level = params.verbose ? Level.INFO : Level.SHOUT; + logger.hierarchicalLoggingEnabled = true; /// Set the namespace to the device's namespace AtClientPreference preference = From 9e0336de0e0e08af823e1decc7e19d82c05116ed Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Wed, 8 Nov 2023 20:25:58 -0500 Subject: [PATCH 06/13] test: sshnp core constructor --- .../lib/src/sshnp/sshnp_core.dart | 2 +- .../test/sshnp/sshnp_core_test.dart | 83 +++++++++++++++---- 2 files changed, 67 insertions(+), 18 deletions(-) diff --git a/packages/noports_core/lib/src/sshnp/sshnp_core.dart b/packages/noports_core/lib/src/sshnp/sshnp_core.dart index 21d68d238..41d647032 100644 --- a/packages/noports_core/lib/src/sshnp/sshnp_core.dart +++ b/packages/noports_core/lib/src/sshnp/sshnp_core.dart @@ -66,8 +66,8 @@ abstract class SshnpCore }) : sessionId = Uuid().v4(), namespace = '${params.device}.sshnp', localPort = params.localPort { - logger.logger.level = params.verbose ? Level.INFO : Level.SHOUT; logger.hierarchicalLoggingEnabled = true; + logger.level = params.verbose ? 'info' : 'shout'; /// Set the namespace to the device's namespace AtClientPreference preference = diff --git a/packages/noports_core/test/sshnp/sshnp_core_test.dart b/packages/noports_core/test/sshnp/sshnp_core_test.dart index 53584b581..0df126403 100644 --- a/packages/noports_core/test/sshnp/sshnp_core_test.dart +++ b/packages/noports_core/test/sshnp/sshnp_core_test.dart @@ -1,5 +1,7 @@ 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'; @@ -7,32 +9,79 @@ class MockAtClient extends Mock implements AtClient {} class MockSshnpParams extends Mock implements SshnpParams {} +class MySshnpCore extends SshnpCore { + MySshnpCore({ + required super.atClient, + required super.params, + }); + + @override + AtSshKeyPair? get identityKeyPair => throw UnimplementedError(); + + @override + AtSshKeyUtil get keyUtil => throw UnimplementedError(); + + @override + Future run() => throw UnimplementedError(); + + @override + SshnpdChannel get sshnpdChannel => throw UnimplementedError(); + + @override + SshrvdChannel? get sshrvdChannel => throw UnimplementedError(); +} + void main() { group('Sshnp Core', () { - late AtClient atClient; - late SshnpParams params; + late AtClient mockAtClient; + late SshnpParams mockParams; setUp(() { - atClient = MockAtClient(); - params = MockSshnpParams(); + mockAtClient = MockAtClient(); + mockParams = MockSshnpParams(); registerFallbackValue(AtClientPreference()); }); - test('Constructor - expect that the namespace is set based on params', () { - verifyNever(() => atClient.getPreferences()); - verifyNever(() => params.device); - verifyNever(() => atClient.setPreferences(any())); + test('Constructor', () { + when(() => mockParams.device).thenReturn('mydevice'); + when(() => mockParams.localPort).thenReturn(0); + when(() => mockParams.verbose).thenReturn(false); + + when(() => mockAtClient.getPreferences()).thenReturn(null); + when(() => mockAtClient.setPreferences(any())).thenReturn(null); + + final sshnpCore = MySshnpCore(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.level, 'shout'); + expect(AtSignLogger.root_level, 'info'); + expect(sshnpCore.logger.hierarchicalLoggingEnabled, true); + }); + + test('Constructor - verbose logger', () { + when(() => mockParams.device).thenReturn('mydevice'); + when(() => mockParams.localPort).thenReturn(0); + when(() => mockParams.verbose).thenReturn(true); + + 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); + final sshnpCore = MySshnpCore(atClient: mockAtClient, params: mockParams); -// TODO write a new MYSshnpCore class - // final sshnpCore = MySshnpCore(atClient: atClient, params: params); + /// 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); - // verify(() => atClient.getPreferences()).called(1); - // verify(() => params.device).called(1); - // verify(() => atClient.setPreferences(any())).called(1); + /// Expect that the logger is configured correctly + expect(sshnpCore.logger.level, 'info'); + expect(AtSignLogger.root_level, 'info'); + expect(sshnpCore.logger.hierarchicalLoggingEnabled, true); }); }); } From 924736f80f885948a6d614e6338bd4a68541830f Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Wed, 8 Nov 2023 20:26:25 -0500 Subject: [PATCH 07/13] chore: remove unused import --- packages/noports_core/lib/src/sshnp/sshnp_core.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/noports_core/lib/src/sshnp/sshnp_core.dart b/packages/noports_core/lib/src/sshnp/sshnp_core.dart index 41d647032..cf9529f18 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'; From ad72708b14473454de5e9480828f3b058fb730bf Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Wed, 8 Nov 2023 21:10:15 -0500 Subject: [PATCH 08/13] fix: tests --- packages/noports_core/lib/src/sshnp/sshnp_core.dart | 1 - packages/noports_core/test/sshnp/sshnp_core_test.dart | 6 ++---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/noports_core/lib/src/sshnp/sshnp_core.dart b/packages/noports_core/lib/src/sshnp/sshnp_core.dart index cf9529f18..49b8b5dc2 100644 --- a/packages/noports_core/lib/src/sshnp/sshnp_core.dart +++ b/packages/noports_core/lib/src/sshnp/sshnp_core.dart @@ -65,7 +65,6 @@ abstract class SshnpCore }) : sessionId = Uuid().v4(), namespace = '${params.device}.sshnp', localPort = params.localPort { - logger.hierarchicalLoggingEnabled = true; logger.level = params.verbose ? 'info' : 'shout'; /// Set the namespace to the device's namespace diff --git a/packages/noports_core/test/sshnp/sshnp_core_test.dart b/packages/noports_core/test/sshnp/sshnp_core_test.dart index 0df126403..c30674dc7 100644 --- a/packages/noports_core/test/sshnp/sshnp_core_test.dart +++ b/packages/noports_core/test/sshnp/sshnp_core_test.dart @@ -58,9 +58,8 @@ void main() { verify(() => mockAtClient.setPreferences(any())).called(1); /// Expect that the logger is configured correctly - expect(sshnpCore.logger.level, 'shout'); + expect(sshnpCore.logger.logger.level, Level.SHOUT); expect(AtSignLogger.root_level, 'info'); - expect(sshnpCore.logger.hierarchicalLoggingEnabled, true); }); test('Constructor - verbose logger', () { @@ -79,9 +78,8 @@ void main() { verify(() => mockAtClient.setPreferences(any())).called(1); /// Expect that the logger is configured correctly - expect(sshnpCore.logger.level, 'info'); + expect(sshnpCore.logger.logger.level, Level.INFO); expect(AtSignLogger.root_level, 'info'); - expect(sshnpCore.logger.hierarchicalLoggingEnabled, true); }); }); } From b046707993da7012aa55e96be0bc3b5bc41ff25c Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Thu, 9 Nov 2023 13:41:43 -0500 Subject: [PATCH 09/13] chore: remove unused line --- packages/noports_core/lib/src/common/default_args.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/noports_core/lib/src/common/default_args.dart b/packages/noports_core/lib/src/common/default_args.dart index 4665a1ade..cdde95e34 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; From a54fb29998f0201835b85eb6c9e0992cf092f056 Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Thu, 9 Nov 2023 18:44:24 -0500 Subject: [PATCH 10/13] chore: mark async init members as visible for testing --- .../lib/src/common/mixins/async_initialization.dart | 3 +++ 1 file changed, 3 insertions(+) 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(); From 761f230c1ff2a50558ea61b1b842d2dc61252baf Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Thu, 9 Nov 2023 18:45:42 -0500 Subject: [PATCH 11/13] chore: sshrvd channel is required on sshnp core --- .../noports_core/lib/src/sshnp/sshnp_core.dart | 9 +++++---- .../sshnp/util/sshnp_initial_tunnel_handler.dart | 16 ++++++++-------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/packages/noports_core/lib/src/sshnp/sshnp_core.dart b/packages/noports_core/lib/src/sshnp/sshnp_core.dart index 49b8b5dc2..3ece92d13 100644 --- a/packages/noports_core/lib/src/sshnp/sshnp_core.dart +++ b/packages/noports_core/lib/src/sshnp/sshnp_core.dart @@ -53,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 @@ -87,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 @@ -101,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.dart b/packages/noports_core/lib/src/sshnp/util/sshnp_initial_tunnel_handler.dart index a1cd7e4ec..39c5d422b 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.dart @@ -20,8 +20,8 @@ mixin SshnpExecInitialTunnelHandler 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' @@ -81,19 +81,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, ); @@ -110,7 +110,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, ); @@ -120,7 +120,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, ); From ae0ec93737418ec6eb7b845612045c348a0f3f58 Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Thu, 9 Nov 2023 18:45:53 -0500 Subject: [PATCH 12/13] test: sshnp_core mocks --- .../test/sshnp/sshnp_core_constants.dart | 14 ++ .../test/sshnp/sshnp_core_mocks.dart | 108 ++++++++++ .../test/sshnp/sshnp_core_test.dart | 204 ++++++++++++------ 3 files changed, 265 insertions(+), 61 deletions(-) create mode 100644 packages/noports_core/test/sshnp/sshnp_core_constants.dart create mode 100644 packages/noports_core/test/sshnp/sshnp_core_mocks.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 c30674dc7..40cc4ef3f 100644 --- a/packages/noports_core/test/sshnp/sshnp_core_test.dart +++ b/packages/noports_core/test/sshnp/sshnp_core_test.dart @@ -5,81 +5,163 @@ 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 {} - -class MySshnpCore extends SshnpCore { - MySshnpCore({ - required super.atClient, - required super.params, - }); - - @override - AtSshKeyPair? get identityKeyPair => throw UnimplementedError(); - - @override - AtSshKeyUtil get keyUtil => throw UnimplementedError(); - - @override - Future run() => throw UnimplementedError(); - - @override - SshnpdChannel get sshnpdChannel => throw UnimplementedError(); - - @override - SshrvdChannel? get sshrvdChannel => throw UnimplementedError(); -} +import 'sshnp_core_mocks.dart'; void main() { - group('Sshnp Core', () { + 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(() { + /// Creation mockAtClient = MockAtClient(); mockParams = MockSshnpParams(); + mockSshnpdChannel = MockSshnpdChannel(); + mockSshrvdChannel = MockSshrvdChannel(); registerFallbackValue(AtClientPreference()); - }); - test('Constructor', () { - when(() => mockParams.device).thenReturn('mydevice'); - when(() => mockParams.localPort).thenReturn(0); - when(() => mockParams.verbose).thenReturn(false); - - when(() => mockAtClient.getPreferences()).thenReturn(null); - when(() => mockAtClient.setPreferences(any())).thenReturn(null); - - final sshnpCore = MySshnpCore(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'); + /// Initialization + stubbedCallInitialization = FunctionStub(); + stubbedInitialize = FunctionStub(); + stubbedCompleteInitialization = FunctionStub(); + stubbedFindLocalPortIfRequired = FunctionStub(); }); - test('Constructor - verbose logger', () { + /// 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(true); - + when(() => mockParams.verbose).thenReturn(verbose); when(() => mockAtClient.getPreferences()).thenReturn(null); when(() => mockAtClient.setPreferences(any())).thenReturn(null); - - final sshnpCore = MySshnpCore(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'); - }); - }); + } + + /// 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); + + when(() => mockSshnpdChannel.callInitialization()) + .thenAnswer((_) async {}); + when(() => mockSshnpdChannel.resolveRemoteUsername()) + .thenAnswer((_) async => 'myRemoteUsername'); + when(() => mockSshnpdChannel.sharePublicKeyIfRequired( + identityKeyPair ?? any())).thenAnswer((_) async {}); + when(() => mockSshrvdChannel.callInitialization()) + .thenAnswer((_) async {}); + } + + 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 } From 1cbf54bf4c7d825c1ba1de3e62f667cd0ef37f5d Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Tue, 14 Nov 2023 10:22:38 -0500 Subject: [PATCH 13/13] chore: remove unnecessary non-null assertions --- .../sshnp_openssh_initial_tunnel_handler.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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'