From b26b237dcc3bd7a1e47d5e6c7d89ca8f796ae46e Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Wed, 3 Jul 2024 21:33:15 +0200 Subject: [PATCH 1/3] Use /// instead of /// for properties --- src/Renci.SshNet/Common/AsyncResult.cs | 16 ++++---- src/Renci.SshNet/Common/ChannelInputStream.cs | 38 +++++++++---------- src/Renci.SshNet/Common/PipeStream.cs | 18 ++++----- .../Security/Cryptography/Cipher.cs | 4 +- .../Security/Cryptography/RsaKey.cs | 4 +- src/Renci.SshNet/Sftp/SftpFileStream.cs | 16 ++++---- src/Renci.SshNet/ShellStream.cs | 18 ++++----- 7 files changed, 57 insertions(+), 57 deletions(-) diff --git a/src/Renci.SshNet/Common/AsyncResult.cs b/src/Renci.SshNet/Common/AsyncResult.cs index 5f62b1b4a..262cd44ba 100644 --- a/src/Renci.SshNet/Common/AsyncResult.cs +++ b/src/Renci.SshNet/Common/AsyncResult.cs @@ -92,9 +92,9 @@ internal void EndInvoke() /// /// Gets a user-defined object that qualifies or contains information about an asynchronous operation. /// - /// + /// /// A user-defined object that qualifies or contains information about an asynchronous operation. - /// + /// public object AsyncState { get { return _asyncState; } @@ -103,9 +103,9 @@ public object AsyncState /// /// Gets a value indicating whether the asynchronous operation completed synchronously. /// - /// + /// /// if the asynchronous operation completed synchronously; otherwise, . - /// + /// public bool CompletedSynchronously { get { return _completedState == StateCompletedSynchronously; } @@ -114,9 +114,9 @@ public bool CompletedSynchronously /// /// Gets a that is used to wait for an asynchronous operation to complete. /// - /// + /// /// A that is used to wait for an asynchronous operation to complete. - /// + /// public WaitHandle AsyncWaitHandle { get @@ -147,9 +147,9 @@ public WaitHandle AsyncWaitHandle /// /// Gets a value indicating whether the asynchronous operation has completed. /// - /// + /// /// if the operation is complete; otherwise, . - /// + /// public bool IsCompleted { get { return _completedState != StatePending; } diff --git a/src/Renci.SshNet/Common/ChannelInputStream.cs b/src/Renci.SshNet/Common/ChannelInputStream.cs index f509ac38b..b7e4be241 100644 --- a/src/Renci.SshNet/Common/ChannelInputStream.cs +++ b/src/Renci.SshNet/Common/ChannelInputStream.cs @@ -153,9 +153,9 @@ protected override void Dispose(bool disposing) /// /// Gets a value indicating whether the current stream supports reading. /// - /// - /// true if the stream supports reading; otherwise, false. - /// + /// + /// if the stream supports reading; otherwise, . + /// public override bool CanRead { get { return false; } @@ -164,9 +164,9 @@ public override bool CanRead /// /// Gets a value indicating whether the current stream supports seeking. /// - /// - /// true if the stream supports seeking; otherwise, false. - /// + /// + /// if the stream supports seeking; otherwise, . + /// public override bool CanSeek { get { return false; } @@ -175,35 +175,35 @@ public override bool CanSeek /// /// Gets a value indicating whether the current stream supports writing. /// - /// - /// true if the stream supports writing; otherwise, false. - /// + /// + /// if the stream supports writing; otherwise, . + /// public override bool CanWrite { get { return true; } } /// - /// Gets the length in bytes of the stream. + /// Throws . /// - /// - /// A long value representing the length of the stream in bytes. - /// - /// A class derived from Stream does not support seeking. - /// Methods were called after the stream was closed. + /// Always. +#pragma warning disable SA1623 // The property's documentation should begin with 'Gets or sets' public override long Length +#pragma warning restore SA1623 // The property's documentation should begin with 'Gets or sets' { get { throw new NotSupportedException(); } } /// - /// Gets or sets the position within the current stream. + /// Gets the position within the current stream. /// - /// + /// /// The current position within the stream. - /// - /// The stream does not support seeking. + /// + /// The setter is called. +#pragma warning disable SA1623 // The property's documentation should begin with 'Gets or sets' public override long Position +#pragma warning restore SA1623 // The property's documentation should begin with 'Gets or sets' { get { return _totalPosition; } set { throw new NotSupportedException(); } diff --git a/src/Renci.SshNet/Common/PipeStream.cs b/src/Renci.SshNet/Common/PipeStream.cs index db211bf19..61a7f3bda 100644 --- a/src/Renci.SshNet/Common/PipeStream.cs +++ b/src/Renci.SshNet/Common/PipeStream.cs @@ -163,9 +163,9 @@ protected override void Dispose(bool disposing) /// /// Gets a value indicating whether the current stream supports reading. /// - /// + /// /// . - /// + /// /// /// It is safe to read from even after disposal. /// @@ -177,9 +177,9 @@ public override bool CanRead /// /// Gets a value indicating whether the current stream supports seeking. /// - /// + /// /// . - /// + /// public override bool CanSeek { get { return false; } @@ -188,10 +188,10 @@ public override bool CanSeek /// /// Gets a value indicating whether the current stream supports writing. /// - /// + /// /// if this stream has not been disposed and the underlying channel /// is still open, otherwise . - /// + /// /// /// A value of does not necessarily mean a write will succeed. It is possible /// that the stream is disposed by another thread between a call to and the call to write. @@ -204,7 +204,7 @@ public override bool CanWrite /// /// Gets the number of bytes currently available for reading. /// - /// A long value representing the length of the stream in bytes. + /// A long value representing the length of the stream in bytes. public override long Length { get @@ -221,9 +221,9 @@ public override long Length /// This property always returns 0, and throws /// when calling the setter. /// - /// + /// /// 0. - /// + /// /// The setter is called. #pragma warning disable SA1623 // The property's documentation should begin with 'Gets or sets' public override long Position diff --git a/src/Renci.SshNet/Security/Cryptography/Cipher.cs b/src/Renci.SshNet/Security/Cryptography/Cipher.cs index d96a214a9..743ce77f0 100644 --- a/src/Renci.SshNet/Security/Cryptography/Cipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Cipher.cs @@ -16,10 +16,10 @@ public abstract class Cipher /// /// Gets the size of the authentication tag for ciphers which implement Authenticated Encryption (AE). /// - /// + /// /// When this implements Authenticated Encryption, the size, in bytes, /// of the authentication tag included in the encrypted message. - /// + /// public virtual int TagSize { get; } /// diff --git a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs index cdb283ba7..71390d713 100644 --- a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs @@ -108,9 +108,9 @@ public override int KeyLength /// /// Gets the digital signature implementation for this key. /// - /// + /// /// An implementation of an RSA digital signature using the SHA-1 hash algorithm. - /// + /// protected internal override DigitalSignature DigitalSignature { get diff --git a/src/Renci.SshNet/Sftp/SftpFileStream.cs b/src/Renci.SshNet/Sftp/SftpFileStream.cs index 2494e2107..8bf0f864a 100644 --- a/src/Renci.SshNet/Sftp/SftpFileStream.cs +++ b/src/Renci.SshNet/Sftp/SftpFileStream.cs @@ -41,9 +41,9 @@ public class SftpFileStream : Stream /// /// Gets a value indicating whether the current stream supports reading. /// - /// + /// /// if the stream supports reading; otherwise, . - /// + /// public override bool CanRead { get { return _canRead; } @@ -52,9 +52,9 @@ public override bool CanRead /// /// Gets a value indicating whether the current stream supports seeking. /// - /// + /// /// if the stream supports seeking; otherwise, . - /// + /// public override bool CanSeek { get { return _canSeek; } @@ -63,9 +63,9 @@ public override bool CanSeek /// /// Gets a value indicating whether the current stream supports writing. /// - /// + /// /// if the stream supports writing; otherwise, . - /// + /// public override bool CanWrite { get { return _canWrite; } @@ -85,7 +85,7 @@ public override bool CanTimeout /// /// Gets the length in bytes of the stream. /// - /// A long value representing the length of the stream in bytes. + /// A long value representing the length of the stream in bytes. /// A class derived from Stream does not support seeking. /// Methods were called after the stream was closed. /// IO operation failed. @@ -125,7 +125,7 @@ public override long Length /// /// Gets or sets the position within the current stream. /// - /// The current position within the stream. + /// The current position within the stream. /// An I/O error occurs. /// The stream does not support seeking. /// Methods were called after the stream was closed. diff --git a/src/Renci.SshNet/ShellStream.cs b/src/Renci.SshNet/ShellStream.cs index 7b8c38460..8c086cc44 100644 --- a/src/Renci.SshNet/ShellStream.cs +++ b/src/Renci.SshNet/ShellStream.cs @@ -189,9 +189,9 @@ private ShellStream(ISession session, int bufferSize, bool noTerminal) /// /// Gets a value indicating whether the current stream supports reading. /// - /// + /// /// . - /// + /// /// /// It is safe to read from even after disposal. /// @@ -203,9 +203,9 @@ public override bool CanRead /// /// Gets a value indicating whether the current stream supports seeking. /// - /// + /// /// . - /// + /// public override bool CanSeek { get { return false; } @@ -214,10 +214,10 @@ public override bool CanSeek /// /// Gets a value indicating whether the current stream supports writing. /// - /// + /// /// if this stream has not been disposed and the underlying channel /// is still open, otherwise . - /// + /// /// /// A value of does not necessarily mean a write will succeed. It is possible /// that the channel is closed and/or the stream is disposed by another thread between a call to @@ -245,7 +245,7 @@ public override void Flush() /// /// Gets the number of bytes currently available for reading. /// - /// A long value representing the length of the stream in bytes. + /// A value representing the length of the stream in bytes. public override long Length { get @@ -262,9 +262,9 @@ public override long Length /// This property always returns 0, and throws /// when calling the setter. /// - /// + /// /// 0. - /// + /// /// The setter is called. #pragma warning disable SA1623 // The property's documentation should begin with 'Gets or sets' public override long Position From 90bce84d89032133f36c6a90a382582a4ffc9bf6 Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Wed, 3 Jul 2024 21:37:35 +0200 Subject: [PATCH 2/3] misc doc updates in SshCommand --- src/Renci.SshNet/SshCommand.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Renci.SshNet/SshCommand.cs b/src/Renci.SshNet/SshCommand.cs index d496031f2..f7f1d3dfd 100644 --- a/src/Renci.SshNet/SshCommand.cs +++ b/src/Renci.SshNet/SshCommand.cs @@ -14,7 +14,7 @@ namespace Renci.SshNet { /// - /// Represents SSH command that can be executed. + /// Represents an SSH command that can be executed. /// public class SshCommand : IDisposable { @@ -404,7 +404,7 @@ public IAsyncResult BeginExecute(string commandText, AsyncCallback? callback, ob /// /// The reference to the pending asynchronous request to finish. /// . - /// Either the IAsyncResult object did not come from the corresponding async method on this type, or EndExecute was called multiple times with the same IAsyncResult. + /// does not correspond to the currently executing command. /// is . public string EndExecute(IAsyncResult asyncResult) { @@ -488,7 +488,7 @@ public void CancelAsync(bool forceKill = false, int millisecondsTimeout = 500) } /// - /// Executes command specified by property. + /// Executes the command specified by . /// /// . /// Client is not connected. @@ -501,12 +501,10 @@ public string Execute() } /// - /// Executes the specified command text. + /// Executes the specified command. /// /// The command text. - /// - /// The result of the command execution. - /// + /// . /// Client is not connected. /// Operation has timed out. public string Execute(string commandText) From d552d855ef0b4906734fa16a9ed32aaf60f4dba7 Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Wed, 3 Jul 2024 22:04:33 +0200 Subject: [PATCH 3/3] Update README --- README.md | 114 ++++++++++++++++++++++------------------------ docfx/examples.md | 10 ++-- 2 files changed, 57 insertions(+), 67 deletions(-) diff --git a/README.md b/README.md index ab8959b3a..32c865b91 100644 --- a/README.md +++ b/README.md @@ -6,36 +6,65 @@ SSH.NET is a Secure Shell (SSH-2) library for .NET, optimized for parallelism. [![NuGet download count](https://img.shields.io/nuget/dt/SSH.NET.svg)](https://www.nuget.org/packages/SSH.NET) [![Build status](https://ci.appveyor.com/api/projects/status/ih77qu6tap3o92gu/branch/develop?svg=true)](https://ci.appveyor.com/api/projects/status/ih77qu6tap3o92gu/branch/develop) -## Introduction +## Key Features -This project was inspired by **Sharp.SSH** library which was ported from java and it seems like was not supported -for quite some time. This library is a complete rewrite, without any third party dependencies, using parallelism -to achieve the best performance possible. +* Execution of SSH command using both synchronous and asynchronous methods +* SFTP functionality for both synchronous and asynchronous operations +* SCP functionality +* Remote, dynamic and local port forwarding +* Interactive shell/terminal implementation +* Authentication via publickey, password and keyboard-interactive methods, including multi-factor +* Connection via SOCKS4, SOCKS5 or HTTP proxy -## Documentation +## How to Use -Documentation is hosted at https://sshnet.github.io/SSH.NET/. Currently (4/18/2020), the documentation is very sparse. -Fortunately, there are a large number of [tests](https://github.com/sshnet/SSH.NET/tree/develop/test/) that demonstrate usage with working code. -If the test for the functionality you would like to see documented is not complete, then you are cordially -invited to read the source, Luke, and highly encouraged to generate a pull request for the implementation of -the missing test once you figure things out. 🤓 +### Run a command -## Features +```cs +using (var client = new SshClient("sftp.foo.com", "guest", new PrivateKeyFile("path/to/my/key"))) +{ + client.Connect(); + using SshCommand cmd = client.RunCommand("echo 'Hello World!'"); + Console.WriteLine(cmd.Result); // "Hello World!\n" +} +``` -* Execution of SSH command using both synchronous and asynchronous methods -* Return command execution exit status and other information -* Provide SFTP functionality for both synchronous and asynchronous operations -* Provides SCP functionality -* Provide status report for upload and download sftp operations to allow accurate progress bar implementation -* Remote, dynamic and local port forwarding -* Shell/Terminal implementation -* Specify key file pass phrase -* Use multiple key files to authenticate -* Supports publickey, password and keyboard-interactive authentication methods -* Supports two-factor or higher authentication -* Supports SOCKS4, SOCKS5 and HTTP Proxy +### Upload and list files using SFTP + +```cs +using (var client = new SftpClient("sftp.foo.com", "guest", "pwd")) +{ + client.Connect(); + + using (FileStream fs = File.OpenRead(@"C:\tmp\test-file.txt")) + { + client.UploadFile(fs, "/home/guest/test-file.txt"); + } + + foreach (ISftpFile file in client.ListDirectory("/home/guest/")) + { + Console.WriteLine($"{file.FullName} {file.LastWriteTime}"); + } +} +``` + +## Main Types + +The main types provided by this library are: + +* Renci.SshNet.SshClient +* Renci.SshNet.SftpClient +* Renci.SshNet.ScpClient +* Renci.SshNet.PrivateKeyFile +* Renci.SshNet.SshCommand +* Renci.SshNet.ShellStream + +## Additional Documentation -## Encryption Method +* [Further examples](https://sshnet.github.io/SSH.NET/examples.html) +* [API browser](https://sshnet.github.io/SSH.NET/api/Renci.SshNet.html) + +## Encryption Methods **SSH.NET** supports the following encryption methods: * aes128-ctr @@ -57,7 +86,7 @@ the missing test once you figure things out. 🤓 * arcfour256 * cast128-cbc -## Key Exchange Method +## Key Exchange Methods **SSH.NET** supports the following key exchange methods: * curve25519-sha256 @@ -131,41 +160,6 @@ Private keys can be encrypted using one of the following cipher methods: * .NET Standard 2.0 and 2.1 * .NET 6 (and higher) -## Usage - -### Multi-factor authentication - -Establish a SFTP connection using both password and public-key authentication: - -```cs -var connectionInfo = new ConnectionInfo("sftp.foo.com", - "guest", - new PasswordAuthenticationMethod("guest", "pwd"), - new PrivateKeyAuthenticationMethod("rsa.key")); -using (var client = new SftpClient(connectionInfo)) -{ - client.Connect(); -} - -``` - -### Verify host identify - -Establish a SSH connection using user name and password, and reject the connection if the fingerprint of the server does not match the expected fingerprint: - -```cs -string expectedFingerPrint = "LKOy5LvmtEe17S4lyxVXqvs7uPMy+yF79MQpHeCs/Qo"; - -using (var client = new SshClient("sftp.foo.com", "guest", "pwd")) -{ - client.HostKeyReceived += (sender, e) => - { - e.CanTrust = expectedFingerPrint.Equals(e.FingerPrintSHA256); - }; - client.Connect(); -} -``` - ## Building the library The library has no special requirements to build, other than an up-to-date .NET SDK. See also [CONTRIBUTING.md](https://github.com/sshnet/SSH.NET/blob/develop/CONTRIBUTING.md). diff --git a/docfx/examples.md b/docfx/examples.md index ee626bb44..b4c7e2588 100644 --- a/docfx/examples.md +++ b/docfx/examples.md @@ -5,8 +5,6 @@ Getting Started ### Run a command -Establish an SSH connection and run a command: - ```cs using (var client = new SshClient("sftp.foo.com", "guest", new PrivateKeyFile("path/to/my/key"))) { @@ -16,9 +14,7 @@ using (var client = new SshClient("sftp.foo.com", "guest", new PrivateKeyFile("p } ``` -### Upload and list files - -SFTP Connection / Exchange +### Upload and list files using SFTP ```cs using (var client = new SftpClient("sftp.foo.com", "guest", "pwd")) @@ -39,7 +35,7 @@ using (var client = new SftpClient("sftp.foo.com", "guest", "pwd")) ### Multi-factor authentication -Establish an SFTP connection using both password and public-key authentication: +Establish a connection using both password and public-key authentication: ```cs var connectionInfo = new ConnectionInfo("sftp.foo.com", @@ -54,7 +50,7 @@ using (var client = new SftpClient(connectionInfo)) ### Verify host identify -Establish an SSH connection using user name and password, and reject the connection if the fingerprint of the server does not match the expected fingerprint: +Establish a connection using user name and password, and reject the connection if the fingerprint of the server does not match the expected fingerprint: ```cs string expectedFingerPrint = "LKOy5LvmtEe17S4lyxVXqvs7uPMy+yF79MQpHeCs/Qo";