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";
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
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)